44

In Objective-C, is it necessary to override all inherited constructors of a subclass to add custom initialization logic?

For example, would the following be correct for a UIView subclass with custom initialization logic?

@implementation CustomUIView

- (id)init {
    self = [super init];
    if (self) {
        [self initHelper];
    }
    return self;
}

- (id)initWithFrame:(CGRect)theFrame {
    self = [super initWithFrame:theFrame];
    if (self) {
        [self initHelper];
    }
    return self;
}

- (id)initWithCoder:(NSCoder *)decoder {
    self = [super initWithCoder:decoder];
    if (self) {
        [self initHelper];
    }
    return self;
}

- (void) initHelper {
    // Custom initialization
}

@end
hpique
  • 119,096
  • 131
  • 338
  • 476

3 Answers3

46

Every Cocoa Touch (and Cocoa) class has a designated initializer; for UIView, as stated in this documentation, that method is initWithFrame:. In this particular case, you'll only need to override initWithFrame; all other calls will cascade down and hit this method, eventually.

This goes beyond the scope of the question, but if you do end up creating a custom initializer with extra parameters, you should make sure to the designated initializer for the superclass when assigning self, like this:

- (id)initWithFrame:(CGRect)theFrame puzzle:(Puzzle *)thePuzzle title:(NSString *)theTitle {
    self = [super initWithFrame:theFrame];
    if (self) {
        [self setPuzzle:thePuzzle];
        [self setTitle:theTitle];
        [self initHelper];
    }
    return self;
}
Sam Ritchie
  • 10,988
  • 4
  • 42
  • 53
  • 1
    So even if I instance CustomUIView with plain init, it will call initWithFrame? – hpique Dec 05 '10 at 16:39
  • That's correct. he way to test this would be to override both init: and initWithFrame:, set breakpoints (or NSLog statements) on the first line of each, and instance CustomUIView using init. You should see init get hit first, followed by initWithFrame:. – Sam Ritchie Dec 05 '10 at 17:08
  • 33
    What's important to remember is that if an object gets instantiated from a NIB, `initWithCoder:` is called, and **NOT** `initWithFrame:`. – Pascal May 29 '11 at 16:58
  • 3
    @Pascal that's a good point and probably should be edited into the answer, from the doc referenced in the answer about `initWithFrame`: _"If you use Interface Builder to design your interface, this method is not called when your view objects are subsequently loaded from the nib file."_ – pauloya Feb 08 '12 at 15:11
  • Additional quote from [Apple docs](http://developer.apple.com/library/ios/#documentation/Cocoa/Conceptual/LoadingResources/CocoaNibs/CocoaNibs.html#//apple_ref/doc/uid/10000051i-CH4-SW8) about loading views from resource files: _"Custom views in OS X receive an initWithFrame: message."_, while _"Custom views in iOS do not use the initWithFrame: method for initialization."_ – Maciej Jastrzebski Apr 28 '13 at 09:23
  • 4
    So with @Pascal comments, Sam's accepted answer is false. Since you can't rely on a convention for constructors, it's probably less time consuming to assume you must override all of them, to ensure your init is run each time. – gdbj Apr 29 '14 at 08:43
  • 2
    @GregoryJohnson Not necessarily _all_ of them; `initWithCoder:` is special, it's part of the `NSCoding` category. You're fine with overriding the designated initializer, `initWithFrame:` in this case, **PLUS** `initWithCoder:`. – Pascal Apr 29 '14 at 15:41
6

In case of using Interface Builder, the one is called is :

- (id)initWithCoder:(NSCoder *)coder
{
    self = [super initWithCoder:coder];
    if (self) {
       //do sth
    }
    return self;
}
letanthang
  • 390
  • 5
  • 7
4

In general you should follow the designated initializer convention. The designated initializer is the init, that covers the initialization of all instance variables. The designated initializer is also the method that is called by other init methods of a class.

Apple's documentation about designated initializers.

initWithFrame: is the designated initializer of the NSView class. Apple's Cocoa documentation always explicitly mentions the designated initializer of a class.

initWithCoder: is discussed here on SO.

Community
  • 1
  • 1
Thomas Zoechling
  • 34,177
  • 3
  • 81
  • 112