Должен ли я ссылаться на 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;
}
Я не уверен, в какой момент в инициализации объекта свойства становятся доступными с помощью точечной нотации.
Ответы
Ответ 1
Использовать прямой доступ в частично сконструированных состояниях независимо от 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), можно найти здесь: Инициализация свойства, точечная нотация
Ответ 2
Нет, не стоит!
Вы можете найти описание, почему здесь
Также яблоки рекомендуют не делать этого. Читайте здесь
Ответ 3
Я не уверен, в какой момент в инициализации объекта свойства становятся доступными с помощью точечной нотации.
Поскольку точечное обозначение по-прежнему является методом Objective-C (и методом C фактически по методу ObjC), точечная нотация или вызов метода совершенно безопасна. GIVEN метод готов к работе с базовым типом (типами) в памяти, в каком бы состоянии они ни находились.
Нормальное правило об избежании использования неинициализированного (возможно) сегмента памяти гаража по-прежнему будет применяться. Что является самой сильной мотивацией для использования ивара в init.
Но если ваш метод (getter | setter) способен правильно использовать сегмент памяти - независимо от того, записывается ли он прежде, чем он будет прочитан, - тогда, во всяком случае, используйте ваш getter в методе init.
Lazy getter использует предположение, что указатель, который он инициализирует, запускается как "nil", чтобы принять решение о выполнении инициализации. Если вы не можете считать исходное содержимое вашей памяти, тогда инициализация ivar может быть самым безопасным курсом.
Почему существует правило никогда не использовать сеттеры или геттеры в init, если метод способен корректно работать в этом сценарии?