Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Double Initialization Of UIViewController's Subclass Member in Swift

I wanted to make a custom container view controller and added some members to the subclass of UIViewController. When I try to init it from the app delegate by using following code:

self.window = UIWindow(frame: UIScreen.mainScreen().bounds)
self.window?.rootViewController = CustomContainerViewController()
self.window?.makeKeyAndVisible()

all the members in CustomContainerViewController were initialized twice.

Here is CustomContainerViewController's code:

class CustomContainerViewController: UIViewController {
    let tabBar = CustomTabBar()

    override init() {
        super.init()
    }

    required init(coder aDecoder: NSCoder) {
        super.init(coder: aDecoder)
    }

    override init(nibName nibNameOrNil: String?, bundle nibBundleOrNil: NSBundle?) {
        super.init(nibName: nibNameOrNil?, bundle: nibBundleOrNil?)
    }
}

Here is CustomTabBar's code:

class CustomTabBar: UIView {
     override init(){
         println("init")
         super.init()
    }
     override init(frame: CGRect) {
         println("initWithFrame:")
         super.init(frame: frame)
    }
     required init(coder aDecoder: NSCoder) {
         println("initWithCoder:")
         super.init(coder: aDecoder)
    }
}

Whenever you init the CustomContainerViewController from the app delegate by using the code previously mentioned, is always prints "init", "initWithFrame" twice.

like image 407
WeZZard Avatar asked Oct 11 '14 03:10

WeZZard


1 Answers

Incorrect designated initializer used.

UIViewController has only one designated initializer init(nibName nibNameOrNil: String?, bundle nibBundleOrNil: NSBundle?).

As its comment says

The designated initializer. If you subclass UIViewController, you must call the super implementation of this method, even if you aren't using a NIB. (As a convenience, the default init method will do this for you, and specify nil for both of this methods arguments.) In the specified NIB, the File's Owner proxy should have its class set to your view controller subclass, with the view outlet connected to the main view. If you invoke this method with a nil nib name, then this class' -loadView method will attempt to load a NIB whose name is the same as your view controller's class. If no such NIB in fact exists then you must either call -setView: before -view is invoked, or override the -loadView method to set up your views programatically.

So whenever you override the init() method of UIViewController, once you call super, UIViewController's implementation would call init(nibName nibNameOrNil: String?, bundle nibBundleOrNil: NSBundle?) on behalf of you. So all the members in your UIViewController's subclass were initialized twice.

To solve this problem, use following code in the app delegate

self.window = UIWindow(frame: UIScreen.mainScreen().bounds)
self.window?.rootViewController = CustomContainerViewController(nibName: nil, bundle: nil)
self.window?.makeKeyAndVisible()

And never call the init() method of UIViewController or override this method in subclasses.

like image 151
WeZZard Avatar answered Oct 13 '22 16:10

WeZZard