Назначенный инициализатор и удобный инициализатор в objective-c и как их правильно создать и связать вместе

Я пытаюсь понять, какой должен быть назначен инициализатор и какой инициализатор удобства. Я читал документы apple по этой теме, но я все еще не уверен. Должен ли назначенный инициализатор иметь все значения, необходимые для класса? Например
Это был первый назначенный инициализатор, который я создал

-(id)initWithCardCount:(NSUInteger)cardCount usingDeck:(Deck *)deck
{
    self = [super init];
    if (self) {
        for(int i = 0; i<=cardCount;i++){
            Card *card = [deck drawRandomCard];
            if (!card) {
                self = nil;
                break;
            }else{
                self.cards[i] = card;
            }
        }
    }

    return self;
}

теперь adde cardMatchMode свойство для этого класса и хотел бы установить его в инициализаторе. Сделать класс обратно совместимым и чтобы понять инициализаторы, я сохраняю тот, который у меня есть сейчас, и создаю другой инициализатор.

-(id)initwithCardCount:(NSUInteger)cardCount usingDeck:(Deck *)deck cardMatchMode:(NSUInteger)matchMode
{

    _cardMatchMode = matchMode;
    return [self initWithCardCount:cardCount usingDeck:deck];;
}

на основе документов apple инициализатор удобства должен возвращать значение для назначенного инициализатора, но вопрос в том, Могу ли я установить дополнительное свойство для этого класса в инициализаторе удобства? Могу я сказать self.cardMatchMode = matchMode; или self все еще не полностью инициализирован?
Это работает, но я просто хотел понять, если это правильный код, и я могу получить доступ к cardMatchMode свойство в удобстве init или я должен был бы сделать -(id)initwithCardCount:(NSUInteger)cardCount usingDeck:(Deck *)deck cardMatchMode:(NSUInteger)matchMode

в качестве назначенного инициализатора и другого удобства init и переработать код? Спасибо!

/ / / / / / Update

я получал ошибку в

-(id)initwithCardCount:(NSUInteger)cardCount usingDeck:(Deck *)deck cardMatchMode:(NSUInteger)matchMode

когда я пытался сделать self = [self initWithCardCount:(NSUInteger)cardCount usingDeck:(Deck*)deck; ошибка сказала, что вы не можете назначить себя вне семьи init. Я понял, в чем проблема. Метод init имел нижний регистр w, и он должен был быть капитальным, поэтому теперь это работает. Это код, который у меня теперь есть для моего удобства инициализатора.

-(id)initWithCardCount:(NSUInteger)cardCount usingDeck:(Deck *)deck cardMatchMode:(NSUInteger)matchMode
{
    self = [self initWithCardCount:cardCount usingDeck:deck];
    if (self){
        _cardMatchMode = matchMode;
    }
    return self;
}

теперь это имеет больше смысла. Я назвал назначенный init, который вызывает super, а затем я установил cardMatchMode переменной.

насколько я понимаю, есть много объектов, которые имеют удобный инициализатор с дополнительными параметрами, и он будет просто вызывать назначенный init. Если вы посмотрите на NSString и у него разные инициализаторы с разными параметрами. Это, наверное, призвание инит что назначенный инициализатор. Правильно ли это?

2 ответов


согласно документации Apple, назначенный инициализатор

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

Так что в вашем случае это будет - (id)initwithCardCount:(NSUInteger)cardCount usingDeck:(Deck *)deck cardMatchMode:(NSUInteger)matchMode. Все остальные инициализаторы будут иметь меньше аргументов, заполняя отсутствующие параметры назначенного инициализатора значениями по умолчанию или другими выводимыми значениями.

таким образом, каждый инициализатор удобства вызывает назначенный инициализатор вместо инициализатора суперкласса.

удобная пара инициализаторов будет выглядеть так в вашем случае:

/**
 Convenience initializers
*/
- (id)init
{
    self = [self initwithCardCount:kDefaultCardCount usingDeck:[Deck defaultDeck] cardMatchMode:kCardMatchModeDefault];
    return self;
}

- (id)initWithCardCount:(NSUInteger)cardCount usingDeck:(Deck *)deck
{
    self = [self initwithCardCount:cardCount usingDeck:deck cardMatchMode:kCardMatchModeDefault]; 
    if (self) {

    }

    return self;
}

/**
 Designated initializer
*/
- (id)initwithCardCount:(NSUInteger)cardCount usingDeck:(Deck *)deck cardMatchMode:(NSUInteger)matchMode
{
    self = [super init];
    if (self) {
        for (int i = 0; i <= cardCount; i++) {
            Card *card = [deck drawRandomCard];
            if (!card) {
                self = nil;
                break;
            }
            else {
                self.cards[i] = card;
            }
        }
        // Set card match mode here:
        _cardMatchMode = matchMode;
    }

    return self;
}

назначенный инициализатор-это тот, который вызывает назначенный инициализатор суперкласса своего класса, поэтому это единственный инициализатор, который вызывает метод на объекте super. Ни один другой инициализатор в классе не должен этого делать; эти вторичные инициализаторы должны вызывать назначенный инициализатор с помощью self. Обычно назначенный инициализатор имеет все параметры, необходимые для создания полезного объекта класса.

короче говоря, назначенный инициализатор только тот, который вызывает инициализатор на super, и все другие инициализаторы в классе вызывают назначенный инициализатор (используя self).