bcv bcv - 1 month ago 8
Swift Question

IBOutlet elements come out nil when I try to set them in viewDidLoad

I am creating a carousel in which there will be 3-4 view controllers. I created a viewcontroller in storyboard and I set the IBOutlets inside viewDidLoad(). My plan is to instantiate these ViewControllers and dynamically change their iboutlets.Since their viewDidLoad functions will be called when they are loaded, this is where I set the iboutlet elements.here is the custom view controller code:

import UIKit

class CarouselViewController: UIViewController {

@IBOutlet weak var imageView: UIImageView!
@IBOutlet weak var label: UILabel!


var imageName: String?
var bottomText: String?

convenience init(imageName: String, bottomText: String){
self.init()
self.imageName = imageName
self.bottomText = bottomText
}

override func viewDidLoad() {
if(self.imageView==nil){
println("nil")
}
self.imageView.image = UIImage(named: self.imageName!)
self.label.text = self.bottomText
}
}


And this is how I instantiate it:

var vc1 = CarouselViewController(imageName: "tour1", bottomText: "This is view1")


However, in viewDidload(), self.imageView comes out nil.Exact error message is:

fatal error: unexpectedly found nil while unwrapping an Optional value


I linked the view controller in storyboard to the class
I checked the outlets. When I hover over each of them, the corresponding UI element gets highlighted on storyboard.
My guess is that there might be something I dont know about the flow of how view controllers are created. Can anyone help? Thanks

Edit: I added super.viewDidLoad() on top of viewDidLoad(), still the same problem

Edit2: This is how I create and use the viewcontrollers:

var vc1 = CarouselViewController(imageName: "tour1", bottomText: "This is view1")
var vc2 = CarouselViewController(imageName: "tour2", bottomText: "This is view2")


let pages = PagesController([vc1, vc2])
self.presentViewController(pages, animated: true) { () -> Void in
pages.goTo(0)
}


Edit3: Solution found, answer given by @Roux is correct. One should instantiate UIViewControllers using storyboards to achieve this functionality. There is also another solution: Create UIViewController with nib(tick the box when creating UIViewController class) and in convenience init method call

self.init(nibname:"NibName", bundle: nil)

Answer

I've had the same problem under iOS7 on very slow devices.

Just wait for your views to be rendered in viewDidLayoutSubviews then do your changes. Don't forget to do so just once though for viewDidLayoutSubviews is being called a lot.

var first = false

override func viewDidLayoutSubviews() { 
    super.viewDidLayoutSubviews()
    if self.first {
        //Update your views
        self.first = false
    }
}

You could also use view.layoutSubviews() but I recommend you not to ;)

EDIT

I did not see the problem at first sight but you are creating your view controllers from scratch! You must instantiate them using a storyboard or your IBOutlets won't be set ;)

var vc1 = storyboard?.instantiateViewControllerWithIdentifier("YourControllerStoryboardId") as! CarouselViewController

Hope this'll help!