Andre
Andre

Reputation: 7668

iOS Swift: nil IBOutlets with custom ViewController

Evening I have a problem with outlets.

viewController1 make several instances of ViewController2, presenting them into a page container controlled with a pageControl.

The problem is that the view controller outlets in the ViewController2 are always nil.

Probably because the ViewController2 is instantiate via code.

How can I fix this?

here I create the different ViewController2

let page = OnboardPageViewController(onboard: onboard)
            pages.append(page)

Here is the init code for ViewController2

    //--------------------
    //MARK: - Outlets
    //--------------------

    @IBOutlet var backgroundVideoView: BackgroundVideo!
    @IBOutlet var backgroundUIImage: UIImageView!
    @IBOutlet var titleLabel: UILabel!
    @IBOutlet var descriptionLabel: UILabel!

    //--------------------
    //MARK: - Properties
    //--------------------

    let onboard: Onboard

    //--------------------
    //MARK: - View's Methods
    //--------------------

    override func viewDidLoad() {
        super.viewDidLoad()
        print("loaded: \(onboard.title)")

        //FIXME: - need to find a way to link the outlets even if the controller is called via code
    }

    override func viewWillAppear(_ animated: Bool) {
        super.viewWillAppear(true)
        print("presenting: \(onboard.title)")
    }

    init(onboard: Onboard) {
        self.onboard = onboard
        super.init(nibName: nil, bundle: nil)
    }

    required init?(coder aDecoder: NSCoder) {
        fatalError("init(coder:) has not been implemented")
    }

Upvotes: 0

Views: 813

Answers (2)

Jose Grosso
Jose Grosso

Reputation: 91

You have to instantiate through UIStoryboard object, something like this:

if let viewController = UIStoryboard.init(name: "YourStoryBoardName", bundle: nil).instantiateViewController(withIdentifier: "YourViewController") {
   // do something with it
}

You can cast it to your custom class in at the same time of the unwrap (with as? CustomClassViewCotroller)

Edit: static func to instantiate your view controller like init:

class YourViewController: UIViewController {

    static func instantiate(withViewModel vm: ViewModel) -> YourViewController? {
        if let viewController = UIStoryboard.init(name: "YourStoryboard", bundle: nil).instantiateViewController(withIdentifier: "YourViewController") as? YourViewController {
            viewController.viewModel = vm

            return viewController
        }

        return nil
    }

    var viewModel: ViewModel?

    // ...

}

There will be more optional unwrapping in your code when using viewModel var but I think this is the correct way to create view controllers programmatically (in segues you have to set variables too, but that is another history).

Good luck mate.

Upvotes: 1

Lou Franco
Lou Franco

Reputation: 89232

Your outlets will be nil until the Storyboard file is loaded. So, right after init, they will be nil. You have to wait until viewDidLoad is called before accessing them.

If you need to init and set up things in the VC, you have to add other (non outlet) properties to hold that information. You can't just init and then access an outlet.

EDIT: In your code (added later), you aren't using a XIB or Storyboard. But, since you have outlets, I am assuming that you actually have one.

Don't use a custom init. Instead add properties and set them after you initialize using a Storyboard instantiate.

Upvotes: 1

Related Questions