Инициализация класса с помощью инициализатора суперкласса

Попробуйте использовать Gitlense . Это плагин VSCode. Работает для меня при работе с командой.

7
задан zoul 12 April 2010 в 15:14
поделиться

1 ответ

Обычно в Objective C Вы создаете обозначенный инициализатор для каждого класса, и затем разделяет на подклассы, используют тот же инициализатор. Таким образом вместо того, чтобы использовать initAnimal и initDog, Вы просто используете init. Подкласс собаки затем определил бы свой собственный init метод и назвал бы обозначенный инициализатор в его родительском классе:

@implementation Dog
-(id)init
{
    if( (self = [super init]) ) {  // call init in Animal and assign to self
        // do something specific to a dog
    }
    return self;
}
@end

Вы не должны действительно указывать initDog и initAnimal, потому что класс объявляется на правой стороне присвоения...

Обновление: я добавляю следующее к ответу для отражения дополнительной информации в вопросе

Существует много способов гарантировать, чтобы подклассы не называли инициализаторы кроме своего обозначенного инициализатора и способа, которым Вы в конечном счете выбираете, будет в основном основан на Вашем целом дизайне. Одна из хороших вещей о Objective C - то, что это настолько гибко. Я дам Вам два примера здесь для запущения Вас.

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

@implementation Dog
-(id)init
{
    // Dog does not respond to this initializer
    NSAssert( false, @"Dog classes must use one of the designated initializers; see the documentation for more information." );

    [self autorelease];
    return nil;
}

-(id)initWithFur:(FurOptionsType)furOptions
{
    if( (self = [super init]) ) {
        // do stuff and set up the fur based on the options
    }
    return self;
}
@end

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

@interface Animal : NSObject
-(id)initAnimal;
@end

@interface Animal ()
-(id)_prvInitAnimal;
@end

@interface Dog : Animal
-(id)initDog;
@end

@implementation Animal
-(id)init
{
    NSAssert( false, @"Objects must call designated initializers; see documentation for details." );

    [self autorelease];
    return nil;
}

-(id)initAnimal
{
    NSAssert( [self isMemberOfClass:[Animal class]], @"Only Animal may call initAnimal" );

    // core animal initialization done in private initializer
    return [self _prvInitAnimal];
}

-(id)_prvInitAnimal
{
    if( (self = [super init]) ) {
        // do standard animal initialization
    }
    return self;
}
@end

@implementation Dog
-(id)initDog
{
    if( (self = [super _prvInitAnimal]) ) {
        // do some dog related stuff
    }
    return self;
}
@end

Здесь Вы видите интерфейс и реализацию класса Животного и Собаки. Животное является обозначенным объектом верхнего уровня и поэтому переопределяет реализацию NSOBJECT init. Любой, кто называет init на Животном или любом из подклассов Животного, получит ошибку утверждения, отсылающую их к документации. Животное также определяет частный инициализатор на частной категории. Частная категория осталась бы с Вашим кодом, и подклассы Животного назовут этот частный инициализатор, когда они будут звонить в супер. Это - цель, должен назвать init на суперклассе Животного (NSObject в этом случае) и сделать любую универсальную инициализацию, которая могла бы быть необходимой.

Наконец, первая строка в initAnimal методе Животного является утверждением, что получатель является на самом деле Животным и не некоторым подклассом. Если получатель не будет Животным, то программа перестанет работать с ошибкой утверждения, и программист будет отнесен в документацию.

Это всего два примера того, как Вы могли бы разработать что-то со своими конкретными требованиями. Однако я настоятельно рекомендовал бы, чтобы Вы рассмотрели свои конструктивные ограничения и видели, требуете ли Вы действительно этого типа дизайна, поскольку это нестандартно в Какао и в большинстве платформ дизайна OO. Например, можно рассмотреть делающие различные объекты корневого уровня животных и просто иметь протокол Животных вместо этого, требуя, чтобы все различные "животные" ответили на определенные универсальные животным сообщения. Тем путем каждое животное (и истинные подклассы Животного) может обработать их обозначенные инициализаторы сами и не должно будет полагаться на суперклассы, ведущие себя таким определенным, нестандартным способом.

19
ответ дан 6 December 2019 в 10:04
поделиться