Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to write init methods of a UIViewController in Swift

I am unable to add init method to the following UIViewController class. I need to write some code in the init method. Do i have to write init(coder) method? Even when I add the coder and decoder methods I still get errors. I also tried using the init method without any parameters but that also does not seem to work.

class ViewController: UIViewController {

    var tap: UITapGestureRecognizer?

    override init(nibName nibNameOrNil: String?, bundle nibBundleOrNil: NSBundle?)   {
        super.init(nibName: nil, bundle: nil)
        tap = UITapGestureRecognizer(target: self, action: Selector("handleTap:"))
    }

...
...
}

If I call the super.init() method without parameters the error is "Must call a designated initializer of super class" and if I pass the parameter nib and bundle then error is "Required initializer init(coder)".

Even when I add init(coder) and init(decoder) it does not work.

like image 649
Ankit Goel Avatar asked Jun 06 '15 05:06

Ankit Goel


People also ask

What is Init method in Swift?

An initializer is a special type of function that is used to create an object of a class or struct. In Swift, we use the init() method to create an initializer. For example, class Wall { ... // create an initializer init() { // perform initialization ... } }

How many types of init are there in Swift?

Swift defines two kinds of initializers for class types to help ensure all stored properties receive an initial value. These are known as designated initializers and convenience initializers.

What is UIViewController in Swift?

The UIViewController class defines the shared behavior that's common to all view controllers. You rarely create instances of the UIViewController class directly. Instead, you subclass UIViewController and add the methods and properties needed to manage the view controller's view hierarchy.

What is convenience init Swift?

convenience init : Convenience initializers are secondary, supporting initializers for a class. You can define a convenience initializer to call a designated initializer from the same class as the convenience initializer with some of the designated initializer's parameters set to default values.


3 Answers

I used:

convenience init() {
    self.init(nibName:nil, bundle:nil)
}

Some people suggested:

convenience init(){
    self.init()
}

But this gives you an infinite loop.

like image 86
Glauco Neves Avatar answered Oct 19 '22 13:10

Glauco Neves


All of these answers are half-answers. Some people are experiencing infinite loops in related posts because they are only adding the convenience init() (it recursively calls itself if you don't providing a distinct init() method for it to invoke), while other people are neglecting to extend the superclass. This format combines all the solutions to satisfy the problem completely.

// This allows you to initialise your custom UIViewController without a nib or bundle.
convenience init() {
    self.init(nibName:nil, bundle:nil)
}

// This extends the superclass.
override init(nibName nibNameOrNil: String?, bundle nibBundleOrNil: Bundle?) {
    super.init(nibName: nibNameOrNil, bundle: nibBundleOrNil)
    tap = UITapGestureRecognizer(target: self, action: Selector("handleTap:"))
}

// This is also necessary when extending the superclass.
required init?(coder aDecoder: NSCoder) {
    fatalError("init(coder:) has not been implemented") // or see Roman Sausarnes's answer
}

Edit: Also, if you want to initialise any class properties using parameters passed into your convenience init() method without all the overridden init() methods complaining, then you may set all those properties as implicitly unwrapped optionals, which is a pattern used by Apple themselves.

like image 42
Jamie Birch Avatar answered Oct 19 '22 11:10

Jamie Birch


You need to override the init(nibName:bundle:) initializer, and provide the init(coder:) required initializer, and initialize tap in both of them:

class ViewController: UIViewController {

    var tap: UITapGestureRecognizer?

    override init(nibName nibNameOrNil: String?, bundle nibBundleOrNil: Bundle?)   {
        print("init nibName style")
        super.init(nibName: nibNameOrNil, bundle: nibBundleOrNil)
        tap = UITapGestureRecognizer(target: self, action: Selector("handleTap:"))
    }

    // note slightly new syntax for 2017
    required init?(coder aDecoder: NSCoder) {
        print("init coder style")
        super.init(coder: aDecoder)
        tap = UITapGestureRecognizer(target: self, action: Selector("handleTap:"))
    }
...
...
}

Also, be sure when calling the superclass initializer that you don't just pass nil for the nibName and bundle. You should pass up whatever was passed in.


Note that the "convenience init" method mentioned in some answers is only relevant if you are actually "by hand" yourself initializing a view controller. (There are very few situations where you would do that.) If you want to "do something during normal initialization" - so for example create a gesture recognizer or just initialize some variables - the only possible solution is exactly the one given in this answer.

like image 29
Aaron Rasmussen Avatar answered Oct 19 '22 12:10

Aaron Rasmussen