Swift: Custom ViewController initializers

IosObjective CSwiftUiviewcontrollerInitialization

Ios Problem Overview


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)?

Ios Solutions


Solution 1 - Ios

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()
}

Solution 2 - Ios

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

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

Solution 3 - Ios

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
    }
}

Solution 4 - Ios

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.

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestionBadmintonCatView Question on Stackoverflow
Solution 1 - IosBadmintonCatView Answer on Stackoverflow
Solution 2 - IosTr0yJView Answer on Stackoverflow
Solution 3 - IosemrcftciView Answer on Stackoverflow
Solution 4 - IoswlingkeView Answer on Stackoverflow