95

How do you add custom initializers to UIViewController subclasses in Swift?

I've created a sub class of UIViewController that looks something like this:

class MyViewController : UIViewController
{
    init(leftVC:UIViewController, rightVC:UIViewController, gap:Int)
    {
        self.leftVC = leftVC;
        self.rightVC = rightVC;
        self.gap = gap;

        super.init();

        setupScrollView();
        setupViewControllers();
    }
}

When I run it I get a fatal error:

fatal error: use of unimplemented initializer 'init(nibName:bundle:)' for class 'MyApp.MyViewController'

I've read elewhere that when adding a custom initializer one has to also override init(coder aDecoder:NSCoder) so let's override that init and see what happens:

override init(coder aDecoder: NSCoder)
{
    super.init(coder: aDecoder);
}

If I add this, Xcode complains that self.leftVC is not initialized at super.init call. So I guess that can't be the solution either. So I wonder how can I add custom initializers properly to a ViewController subclass in Swift (since in Objective-C this seems not to be a problem)?

8
  • How are you trying to instantiate your MyViewController? Commented Aug 27, 2014 at 12:58
  • Why not instantiate everything in viewDidLoad() ,there you can initialise them just the way you want Commented Aug 27, 2014 at 12:59
  • @MikePollard with dualViewCtrl = DualViewCtrl(leftVC: l, rightVC: r, gap: 50) ... I already found out I need to use the initWithNib initializer. Commented Aug 27, 2014 at 13:01
  • 3
    @tudoricc Because often you want instance properties that are safely initialized in the initializer with given parameters. You can't do that in viewDidLoad since then it would not be guaranteed that the properties are available when needed. Commented Aug 27, 2014 at 13:03
  • I am sorry is just that in my mind I see the viewDidLoad() as an initialiser. thanx for the explanation Commented Aug 27, 2014 at 13:05

4 Answers 4

134

Solved it! One has to call the designated initializer which in this case is the init with nibName, obviously ...

init(leftVC:UIViewController, rightVC:UIViewController, gap:Int)
{
    self.leftVC = leftVC
    self.rightVC = rightVC
    self.gap = gap

    super.init(nibName: nil, bundle: nil)

    setupScrollView()
    setupViewControllers()
}
Sign up to request clarification or add additional context in comments.

13 Comments

Get rid of those ugly semi colons :)
I like semicolons. They make code less ambiguous, especially with those ridiculously verbose Cocoa/Cocoa-Touch API names and signatures. Bad decision from the Swift designers to remove them IMHO.
IMHO, if you type a character and it doesn't effect the compiled binary, you shouldn't type it :)
@SamSoffes so you don't use (extra) whitespace at all? And you obfuscate all symbols to be single characters?
This discussion reminds me of tabs vs spaces in Silicon Valley
|
20

Swift 5

If you want to write custom initializer to UIViewController which is initialized with storyBoard.instantiateViewController(withIdentifier: "ViewControllerIdentifier")

You can write custom initializer for only Optional properties.

class MyFooClass: UIViewController {
    var foo: Foo?

    init(with foo: Foo) {
        self.foo = foo
        super.init(nibName: nil, bundle: nil)
    }

    public required init?(coder aDecoder: NSCoder) {
        super.init(coder: aDecoder)
        self.foo = nil
    }
}

1 Comment

"You can write custom initializer for only Optional properties." is the key. That I missed initially.
18

For a more generic UIViewController you can use this as of Swift 2.0

init() {
    super.init(nibName: nil, bundle: nil)
}

Comments

11

Not sure if you managed to fully solve this... but depending on how you want your class's interface to look and whether or not you actually need the coder functionality, you can also use the below:

convenience required init(coder aDecoder: NSCoder)
{
    //set some defaults for leftVC, rightVC, and gap
    self.init(leftVC, rightVC, gap)
}

Since init:leftVC:rightVC:gap is a designated initializer, you can fulfill the requirement of implementing init:coder by making it a convenience initializer that calls your designated initializer.

This could be better than

override init(coder aDecoder: NSCoder)
{
    super.init(coder: aDecoder);
}

because if you need to initialize some properties, then you would need to rewrite them.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.