Должен ли я ссылаться на self.property в методе init с ARC?

Быстрый вопрос

если у меня есть свойство и ivar, объявленные с тем же именем:

в.h файле:

(Reminder*)reminder;
@property(nonatomic,strong)(Reminder*)reminder;

в файле.m я должен использовать ivar или свойство в методе init, если я использую ARC?

- (id)initWithReminder:(Reminder*)reminder_ {
    self = [super init];
    if (self) {
        reminder = reminder_;
    }
    return self;
}

Или я должен использовать свойство, чтобы получить выгоду от автоматического подсчета ссылок, как это:

- (id)initWithReminder:(Reminder*)reminder_ {
    self = [super init];
    if (self) {
        self.reminder = reminder_;
    }
    return self;
}

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

3 ответа

Решение

Используйте прямой доступ в частично построенных состояниях, независимо от ARC:

- (id)initWithReminder:(Reminder*)reminder_ {
    self = [super init];
    if (self) {
        reminder = reminder_;
        // OR
        reminder = [reminder_ retain];
    }
    return self;
}

Это потому что self.whatever вызовет другие побочные эффекты, такие как уведомления о значении ключа (KVO), или, возможно, ваш класс реализует (явно) или переопределение подкласса setWhatever: - и это может предоставить ваш частично инициализированный экземпляр другим API (включая его собственный), которые справедливо предполагают, что они имеют дело с полностью сконструированным объектом.

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

Таким образом, единый способ, который гарантирует правильность, состоит в том, чтобы использовать прямой доступ в частично построенных состояниях и избегать использования средств доступа.

Примечание: я использую "частично построенный", потому что инициализация - только половина изображения; -dealloc имеет подобные предостережения.

Более подробно о том, почему вы должны использовать прямой доступ в частично построенных состояниях (ARC || MRC), можно найти здесь: Инициализация свойства, точечная запись

Нет, не надо!

Вы можете найти описание, почему здесь
Также яблоко рекомендую не делать этого. Читать здесь

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

Поскольку точечная нотация все еще является методом Objective-C (а метод C фактически находится под методом ObjC), точечная нотация или вызов метода совершенно безопасны. GIVEN, метод подготовлен для работы с базовыми типами в памяти в в каком бы состоянии они ни находились. Обычное правило об избежании использования неинициализированного (возможно) сегмента гаражной памяти все равно будет применяться. Что является самой сильной мотивацией для использования ивара в init.

Но если ваш метод (getter|setter) способен правильно использовать сегмент памяти - независимо от того, был ли он сначала записан перед чтением, - тогда непременно используйте ваш метод get в методе init. Ленивый метод получения использует преимущество предположения, что указатель, который он будет инициализировать, начинается с нуля, чтобы принять решение о выполнении инициализации. Если вы не можете принять начальное содержимое вашей памяти, то инициализация ивара может быть самым безопасным.

Почему есть правило никогда не использовать сеттеры или геттеры в инициализации, если метод способен работать правильно в этом сценарии?

Другие вопросы по тегам