Part 1

TL;DR? Code for part 2

In part 2 of this guide, I want to be able to switch the displayed view controller when the menu option is selected. Right now, the menu is pretty useless. You can select it but only MainViewController is shown. Let’s change this.

Two more view controllers

Let’s add 2 more view controllers in storyboard. I am going to call them YellowViewController and RedViewController and change each view’s background color appropriately.

Again, don’t forget to change the Custom Class and Storyboard ID of each view controller to its respective ViewController class.

img

Update menu options

In part 1, we named our menu options Option A, B and C. To make things a bit more clear, let’s change it to Main, Red, and Green.

img

Listening to menu change

To recap, ContainerViewController holds reference to both MenuViewController and the UINavigationController that holds MainViewController. In MenuViewController, we could get a reference to UINavigationControllerand ask it to switch the displayed view controller. That would look something like this.

((self.parentViewController as! ContainerViewController).rightViewController as! UINavigationController).pushViewController(redViewController, animated: true)

There is no problem with this but it creates a tight coupling between MenuViewController and ContainerViewController. If we tried to contain MenuViewController inside another view controller, this code could break. Another way to achieve this is by sending a notification when a menu option is selected. This way, other objects can listen to those notifications and act on them.

import UIKit
class MenuViewController: UITableViewController, UITableViewDelegate {
    @IBOutlet var menuTableView: UITableView! {
        didSet{
            menuTableView.delegate = self
            menuTableView.bounces = false
        }
    }
    
    struct Notifications {
        static let MainSelected = "MainSelected"
        static let RedSelected = "RedSelected"
        static let GreenSelected = "GreenSelected"
    }
    
    override func tableView(tableView: UITableView, didSelectRowAtIndexPath indexPath: NSIndexPath) {
        let item = indexPath.item
        let center = NSNotificationCenter.defaultCenter()
        
        switch item {
        case 0:
            center.postNotification(NSNotification(name: Notifications.MainSelected, object: self))
        case 1:
            center.postNotification(NSNotification(name: Notifications.RedSelected, object: self))
        case 2:
            center.postNotification(NSNotification(name: Notifications.GreenSelected, object: self))
        default:
            println("Unrecognized menu index")
            return
        }
    }
}

tableView: didSelectRowAtIndexPath will get called when user taps on the menu option. When that happens, we send a notification with a name specific to that row. The next piece of the puzzle is to observe this notification and act on it. We want the UINavigationController to receives this notification and displays the correct view controller. In order to do this, we first need to create a custom UINavigationController. I am going to name this MainNavigationController.

In the storyboard, click on the Navigation Controller that is pointing to MainViewController. Under its Identity Inspector, change the class name to MainNavigationController.

img

import UIKit

class MainNavigationController: UINavigationController {

    private var mainSelectedObserver: NSObjectProtocol?
    private var redSelectedObserver: NSObjectProtocol?
    private var greenSelectedObserver: NSObjectProtocol?
    
    override func viewWillAppear(animated: Bool) {
        super.viewWillAppear(animated)
        addObservers()
    }
    
    override func viewWillDisappear(animated: Bool) {
        super.viewWillDisappear(animated)
        removeObservers()
    }
    
    private func addObservers() {
        let center = NSNotificationCenter.defaultCenter()
        let storyboard = UIStoryboard(name: "Main", bundle: nil)
        
        mainSelectedObserver = center.addObserverForName(MenuViewController.Notifications.MainSelected, object: nil, queue: nil) { (notification: NSNotification!) in
            let mvc = storyboard.instantiateViewControllerWithIdentifier("MainViewController") as! UIViewController
            self.setViewControllers([mvc], animated: true)
        }
        
        redSelectedObserver = center.addObserverForName(MenuViewController.Notifications.RedSelected, object: nil, queue: nil) { (notification: NSNotification!) in
            let rvc = storyboard.instantiateViewControllerWithIdentifier("RedViewController") as! UIViewController
            self.setViewControllers([rvc], animated: true)
        }
        
        greenSelectedObserver = center.addObserverForName(MenuViewController.Notifications.GreenSelected, object: nil, queue: nil) { (notification: NSNotification!) in
            let gvc = storyboard.instantiateViewControllerWithIdentifier("GreenViewController") as! UIViewController
            self.setViewControllers([gvc], animated: true)
        }
    }
    
    private func removeObservers(){
        let center = NSNotificationCenter.defaultCenter()
        
        if mainSelectedObserver !=  nil {
            center.removeObserver(mainSelectedObserver!)
        }
        if redSelectedObserver != nil {
            center.removeObserver(redSelectedObserver!)
        }
        if greenSelectedObserver != nil {
            center.removeObserver(greenSelectedObserver!)
        }
    }

}

That’s it!

You now should be able to select the menu and see the displayed view controller change. The code for part 2 can be found here

Simple Slide Out Navigation Menu in iOS with Swift (Part 1)

Simple guide on how to create slide out navigation without using external library Continue reading

Subdomain with NGINX on Linode

Published on January 14, 2015

Uh-oh. Where Is On Ready In Ember?

Published on January 05, 2015