4

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)
bcv
  • 83
  • 1
  • 7

3 Answers3

5

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!

Roux
  • 201
  • 1
  • 9
  • Still wont do. I suppose there is no way of manipulating UI elements before actually putting the view controller on screen. – bcv Jul 22 '15 at 12:28
  • Are you still trying to access your views in your viewDidLoad ? viewDidLayoutSubviews is being called after viewDidLoad, once all views have been rendered. – Roux Jul 22 '15 at 12:34
  • No, and it still returns nil. – bcv Jul 22 '15 at 12:40
  • I've missed the real point here sorry. I've updated my answer, hope this is it! – Roux Jul 22 '15 at 12:46
  • Thanks Roux! You have a great day – bcv Jul 22 '15 at 13:00
  • This helped me. Especially the last part about instantiating the view controller via the storyboard. I think this is a pretty confusing aspect of the framework. – Aaron Soellinger Aug 05 '23 at 03:05
0

An easier way to do this (in my opinion) is to use awakeFromNib() in place of viewDidLoad(). This is more directly connected to the IBOutlets, so they should be loaded by the time awakeFromNib() is called.

C1FR1
  • 133
  • 1
  • 9
-1

Can you try calling Super-classes viewDidLoad before accessing any view objects ?

like

override func viewDidLoad() {
    super.viewDidLoad()
    if(self.imageView==nil){
        println("nil")
    }
    self.imageView.image = UIImage(named: self.imageName!)
    self.label.text = self.bottomText
}    
ogres
  • 3,660
  • 1
  • 17
  • 16
  • are you sure IBOutlets are set from the Storyboard ? can you check it ? open storyboard , then select imageview and label and see on the right side if Reference outlet is set , maybe you removed it and forgot to add again ? it looks like nothing is assigned to them – ogres Jul 22 '15 at 11:04
  • Yes, those are set as well. Each one of them gets highlighted when I hover over them. Besides, app would crash in that case, it wouldnt even run – bcv Jul 22 '15 at 11:07
  • it would run and crash only after you try to access that nil objects ,and which is happening at the moment , how are you creating this view ? can you provide a code ? – ogres Jul 22 '15 at 11:09