I am coding in Objective-C / Cocoa-Touch for iPhone, and I was wondering, is it ever OK to not chain initializers? For instance, in my parent class I have three initializers that all need to be inherited from by child class. Is it OK in this instance to not chain? For instance, in this one class I have it set up like this:
- (id)initWithGraphic:(Graphic*)graphic size:(CGSize)size
{
self = [super initWithFrame:CGRectZero];
if (self)
{
...
}
return self;
}
- (id)initWithGraphic:(Graphic*)graphic maximumDimension:(CGFloat)maximumDimension
{
self = [super initWithFrame:CGRectZero];
if (self)
{
...
}
return self;
}
- (id)initWithGraphic:(Graphic*)graphic
{
self = [super initWithFrame:CGRectZero];
if (self)
{
...
}
return self;
}
So essentially I don’t have one designated initializer because it’s tough for me to chain them together, I basically have three.
Short answer: if you want your code to be understandable and maintainable, then you must always call
super‘s designated initializer.Long answer…
The
-[NSObject init]method is documented to do nothing:Therefore in theory you’re not required to call it. In practice it’s better to call it because it makes your code more uniform (and therefore easier to understand), and less likely to break if you decide to change a class to inherit from something other than
NSObject.If you have some inheritance chain
MyGrandparent > MyParent > MyObject, and you are the implementer of bothMyParentandMyObject, andMyParentdoesn’t override all ofMyGrandparent‘s initializers, then you could directly call one ofMyGrandparent‘s non-overridden initializers from yourMyObjectinitializers. But again, this is a bad idea. It will be confusing when you or someone else has to revisit the code later, and likely to break if you change the implementation ofMyParentlater.Also, if you’re creating multiple initializers, you need to learn about designated initializers here and here. It’s important to pick one of your initializers as the designated initializer, and make sure all subclass initializers call the superclass’s designated initializer directly. Otherwise, you’re likely to end up creating infinite recursion. I explained this problem thoroughly in this answer and this answer.
UPDATE
In your example, you could set up a designated initializer like this:
You don’t have to expose the designated initializer in the public header file. You can add a a separate header file exposing the designated initializer for subclasses to import. For example, Apple does this with the
UIGestureRecognizerSubclass.hheader, which declares theForSubclassEyesOnlycategory onUIGestureRecognizer.Or you could expose the
configureWith...methods to your subclasses, and maybe you wouldn’t even need to have them override the initializers.