All IBOutlets are nil

Yestay Muratov picture Yestay Muratov · Apr 25, 2015 · Viewed 7.1k times · Source

Hello I am initializing viewController using this code:

 var aboutUsViewController = self.storyboard?.instantiateViewControllerWithIdentifier("AboutUsViewController") as AboutUsViewController

After this I move to aboutViewController. However all my IBOutlets on aboutViewController are nil! Why is that so? I am using MMDrawer library in order to have side bar menu.

 var aboutUsViewController = self.storyboard?.instantiateViewControllerWithIdentifier("AboutUsViewController") as AboutUsViewController


        var aboutUsNavController = UINavigationController(rootViewController: aboutUsViewController)

        var appDelegate: AppDelegate = UIApplication.sharedApplication().delegate as AppDelegate

        appDelegate.centerContainer!.centerViewController = aboutUsNavController
        appDelegate.centerContainer!.toggleDrawerSide(MMDrawerSide.Left, animated: true, completion: nil)

On the side bar I am choosing about us menu item and after I am creating AboutViewController and moving it to the left... The problem is that when I initialize my controller , outlets are nil

I AM also having such kind of problem when using pageViewController:

class ViewController: UIViewController, UIPageViewControllerDataSource, UIPageViewControllerDelegate {


let pageTitles = ["Title 1", "Title 2", "Title 3", "Title 4"]
var images = ["long3","long4","long1","long2"]
var count = 0


var pageViewController : UIPageViewController!

override func viewDidLoad() {
    super.viewDidLoad()
    reset()
    // Do any additional setup after loading the view, typically from a nib.
}

override func didReceiveMemoryWarning() {
    super.didReceiveMemoryWarning()
    // Dispose of any resources that can be recreated.
}

func reset() {
    /* Getting the page View controller */
    pageViewController = self.storyboard?.instantiateViewControllerWithIdentifier("PageViewController") as UIPageViewController
    self.pageViewController.dataSource = self

    let pageContentViewController = self.viewControllerAtIndex(0)
    self.pageViewController.setViewControllers([pageContentViewController!], direction: UIPageViewControllerNavigationDirection.Forward, animated: true, completion: nil)

    /* We are substracting 30 because we have a start again button whose height is 30*/
    self.pageViewController.view.frame = CGRectMake(0, 0, self.view.frame.width, self.view.frame.height - 30)
    self.addChildViewController(pageViewController)
    self.view.addSubview(pageViewController.view)
    self.pageViewController.didMoveToParentViewController(self)
}



func pageViewController(pageViewController: UIPageViewController, viewControllerAfterViewController viewController: UIViewController) -> UIViewController? {

    var index = (viewController as PageContentViewController).pageIndex!
    index++
    if (index >= self.images.count){
        return nil
    }

    return self.viewControllerAtIndex(index)
}


func pageViewController(pageViewController: UIPageViewController, viewControllerBeforeViewController viewController: UIViewController) -> UIViewController? {
    var index = (viewController as PageContentViewController).pageIndex!

    if index<=0 {
        return nil
    }
    index--
    return self.viewControllerAtIndex(index)
}

func viewControllerAtIndex(index : Int) -> UIViewController? {
    if((self.pageTitles.count == 0) || (index >= self.pageTitles.count)) {
        return nil
    }
    let pageContentViewController = self.storyboard?.instantiateViewControllerWithIdentifier("PageContentViewController") as PageContentViewController

    pageContentViewController.imageName = self.images[index]
    pageContentViewController.titleText = self.pageTitles[index]
    pageContentViewController.pageIndex = index
    return pageContentViewController
}

func presentationCountForPageViewController(pageViewController: UIPageViewController) -> Int {
    return pageTitles.count
}

func presentationIndexForPageViewController(pageViewController: UIPageViewController) -> Int {
    return 0
    }

}



class PageContentViewController: UIPageViewController {


@IBOutlet var imageViewMain: UIImageView!

@IBOutlet var labelMain: UILabel!

var pageIndex: Int!
var titleText: String!
var imageName: String!


override func viewDidLoad() {
    super.viewDidLoad()

    self.imageViewMain.image = UIImage(named:imageName)
    self.labelMain.text = self.titleText
    self.labelMain.alpha = 0.1
    UIView.animateWithDuration(1.0, animations:{ ()-> Void in
        self.labelMain.alpha = 1.0
    })
    // Do any additional setup after loading the view.
}

override func didReceiveMemoryWarning() {
    super.didReceiveMemoryWarning()
    // Dispose of any resources that can be recreated.
}


/*
// MARK: - Navigation



  // In a storyboard-based application, you will often want to do a little preparation before navigation
    override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) {
        // Get the new view controller using segue.destinationViewController.
        // Pass the selected object to the new view controller.
    }
    */

}

I am having problem that label and image outlet is nil!!! The same problem I had using MMDrawer library. The same situation. I am not using segues ! I think because of that outlets are nil

Answer

Rob picture Rob · Apr 25, 2015

I assume you're looking at the outlets immediately after instantiating the scene (you'll also see this behavior if using segues and trying to use the outlets in prepareForSegue). But the outlets are not hooked up until after you present/push to that scene, the view is loaded, and viewDidLoad is called.

Bottom line, do not try to use the outlets prior to viewDidLoad being called (i.e. do not use outlets immediately after instantiating the scene). Instead, pass the needed data to the destination scene (e.g. a String property), and the viewDidLoad of the destination should then populate the outlet.

For example, you might have a property in AboutUsViewController:

var message: String!

When you instantiate AboutUsViewController, you'd set that property:

let aboutUsViewController = self.storyboard?.instantiateViewControllerWithIdentifier("AboutUsViewController") as AboutUsViewController // use `as!` in Swift 1.2

aboutUsViewController.message = "some message"

presentViewController(aboutUsViewController, animated: true, completion: nil)

And then the viewDidLoad of AboutUsViewController would use that property to populate the outlet accordingly:

override func viewDidLoad() {
    super.viewDidLoad()

    label1.text = message
}

But you would never have the originating view controller try to set/adjust the outlets of the destination scene. That's the responsibility of AboutUsViewController.


Just to confirm, are your outlets hooked up properly? The below shows two ways to confirm that they are hooked up properly.

When you select the view controller in Interface Builder and then look in the connections inspector, do you see your outlets hooked up there? In the following snapshot, label1 is hooked up, but label2 is not:

enter image description here

Or when you look at your code, and look at the outlets, do you see solid dots in the left margin (meaning the outlet is hooked up) or empty dots (meaning the outlet is not hooked up)?

enter image description here