Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Which initializer(s) to override for UITableViewController subclass

I have a UITableViewController subclass that's instantiated, depending on where it's used, in a NIB or via code. In both cases I want to do customization in the initializer method. Does that mean I need to implement both initWithNibName:bundle: and initWithCoder:, and would each method call its respective super initializer?

While I don't need this right now, what if I also want to be able to instantiate the view controller with initWithStyle:? Would I then need 3 different init methods that replicate the same behavior?

It seems like this violates the whole designated initializer convention, as there would essentially be 3 separate initializers that don't end up calling a common init method. Or is there a way to create a common designated initializer while supporting the 3 different instantiate routes?

like image 870
Daniel Dickison Avatar asked Apr 13 '09 04:04

Daniel Dickison


People also ask

What must a convenience initializer call?

The convenience initializer must call one of the two designated initializers, because it can only call another initializer from the same class. This satisfies rules 2 and 3 from above. Both designated initializers must call the single designated initializer from the superclass, to satisfy rule 1 from above.

How to initialize an object 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 ... } }


3 Answers

My confusion was based on the mistaken belief that each class should have a single designated initializer. This is not true, and in the case of UITableViewController there are 3 designated initializers (as far as I can tell):

  1. initWithStyle: declared locally
  2. initWithNibName:bundle: inherited from UIViewController
  3. initWithCoder: from adopting NSCoding protocol

You need to override 1 or more of these in your subclass depending on how your subclass gets instantiated. In my case I had to implement #2 and #3 since the class can be loaded from a NIB, or instantiated via code with reference to a NIB. (I imagine it's rare that you'll use both initWithStyle: and initWithNibName:bundle: for a single class.)

I found Apple's Coding Guidelines for Cocoa helpful.

like image 167
Daniel Dickison Avatar answered Oct 06 '22 00:10

Daniel Dickison


Internally,

  • UITableViewController's -initWithStyle: calls the super's -init then set the _tableViewStyle ivar.
  • UIViewController's -init simply calls -initWithNibName:bundle: with default arguments.
  • UITableViewController does not override -initWithNibName:bundle:.

Therefore, if you override -initWithNibName:bundle: then -initWithStyle: will adopt the change too. Of course, to play safe (as you shouldn't rely on implementation details), override both of them.

(And no need to override -initWithCoder: unless you will un/archive the instances.)

like image 35
kennytm Avatar answered Oct 06 '22 00:10

kennytm


To clarify, initWithStyle:, being UITableViewController's only published initializer in the docs, is its one explicit designated initializer.

initWithNibName:bundle: is inherited from UIViewController and is the designated initializer for that class. As such, in accordance with Cocoa guidelines, UITableViewController must override this method (by implementing it). However, this does not make it a designated initializer of UITableViewController.

initWithCoder: is, as you point out, an implicit designated initializer from NSCoding.

like image 35
bfalling Avatar answered Oct 05 '22 23:10

bfalling