Переопределение init в подклассе

В Objective-C необходимо ли переопределить все наследуемые конструкторы подкласса для добавления пользовательской логики инициализации?

Например, допустимо ли следующее для подкласса UIView с пользовательской логикой инициализации?

@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

Ответ 1

Каждый класс Cocoa Touch (и Cocoa) имеет назначенный инициализатор; для UIView, как указано в этой документации, этот метод initWithFrame:. В этом конкретном случае вам нужно только переопределить initWithFrame; все остальные вызовы будут каскадом вниз и ударить этот метод, в конце концов.

Это выходит за рамки вопроса, но если вы создадите пользовательский инициализатор с дополнительными параметрами, вы должны убедиться в назначении инициализатора для суперкласса при назначении self, например:

- (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;
}

Ответ 2

В общем, вы должны следовать условному соглашению инициализатора. Назначенный инициализатор представляет собой init, который охватывает инициализацию всех переменных экземпляра. Назначенный инициализатор также является методом, который вызывается другими методами init класса.

Apple documentation о назначенных инициализаторах.

initWithFrame: - назначенный инициализатор класса NSView. Документация Apple Cocoa всегда явно упоминает назначенный инициализатор класса.

initWithCoder: обсуждается здесь на SO.

Ответ 3

В случае использования Interface Builder, он вызывается:

- (id)initWithCoder:(NSCoder *)coder
{
    self = [super initWithCoder:coder];
    if (self) {
       //do sth
    }
    return self;
}