Чем объявленные частные ивы отличаются от синтезированных иваров? - PullRequest
1 голос
/ 21 марта 2010

Я знаю, что современная среда выполнения Objective C может синтезировать ивары.Я думал, что синтезированные ивары ведут себя точно так же, как объявленные ивары, помеченные @private, но они не делают.

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

@interface A : NSObject {
#if !__OBJC2__
  @private
    NSString *_c;
#endif
}

@property (nonatomic, copy) NSString *d;

@end


@implementation A

@synthesize d=_c;

- (void)dealloc {
    [_c release];
    [super dealloc];
}

@end

и подкласс:

@interface B : A {
#if !__OBJC2__
@private
    NSString *_c;
#endif
}

@property (nonatomic, copy) NSString *e;

@end


@implementation B

@synthesize e=_c;

- (void)dealloc {
    [_c release];
    [super dealloc];
}

@end

Подкласс не может иметь объявленный ivar с тем же именем, что и один из объявленных иваров своего суперкласса, дажеесли икар суперкласса является частным.Это кажется мне нарушением смысла @private, поскольку на подкласс влияет выбор суперкласса чего-то частного.

Однако меня больше беспокоит вопрос о том, как мне следует думать осинтезированный ивар.Я думал, что они действовали как объявленные частные ивары, но без хрупкой проблемы базового класса.Может быть, это правильно, и я просто не понимаю проблему хрупкого базового класса.Почему приведенный выше код компилируется только в современной среде выполнения?Существует ли проблема хрупкого базового класса, когда все переменные экземпляра суперкласса являются закрытыми?

Ответы [ 2 ]

6 голосов
/ 22 марта 2010

Синтезированные ивы являются частными. И вы видели, что компилятор работает правильно.

Игнорировать код внутри условных выражений !__OBJ2__. Я буду только смотреть на случай синтезированного ивара.

Вот что имеет ваш код:

  • A::_c представляет собой синтезированный ивар доступно только в пределах реализация A.
  • B::_c является синтезированный ивар и только доступны в рамках реализации B.

Они не являются одной и той же переменной. Они не сталкиваются и не хранят одно и то же значение.

Ситуация, когда проблема все еще может возникать ...

Если вы попытаетесь поместить реализацию A и B в один и тот же файл, компилятор сможет видеть объявление A::_c во время компиляции B и будет запретить вам доступ к _c в строке @synthesize e=_c; в B.

Зачем это делать? Разве я не сказал, что A::_c и B::_c были отдельными, не связанными переменными?

Наличие обеих реализаций в одном файле создает ситуацию, когда _c не является необъявленным идентификатором, когда компилятор достигает @synthesize e=_c;, поэтому компилятор не будет пытаться создать новый синтезирующий ivar для B, вместо этого он пытается получить доступ к A::_c и не удается (так как A::_c является личным).

2 голосов
/ 21 марта 2010

Короче говоря, вы не можете [иметь частные ивы].

Альтернатива - объявить класс в вашем файле реализации, который содержит все состояния, а затем обработать его как структуру.

.m:

@interface PrivateGoo:NSObject
{... ivars ...}
... props
@end

@implementation PrivateGoo
... @synth or not

Затем в .h объявите ивару как id privateGoop;. Если скорость поиска ужасна, используйте ((PrivateGoo*)privateGoop)->iVar; в своем файле .m. Будьте осторожны с управлением памятью, если вы делаете.

Обратите внимание, что у этого есть несколько преимуществ, даже если это кажется на первый взгляд странным. А именно, это делает рефакторинг из PrivateGoo тривиальным; если ваша инкапсуляция данных внезапно обнаружит необходимость иметь бизнес-логику или сделать ее более универсальной, это будет тривиально. С GC компилятор установит информацию о макете для PrivateGoo и будет полностью управлять всей памятью. Использование структуры требует небольшого количества скачков, чтобы заставить работать правильно - правильные схемы распределения и т. Д.

<Ч />

Извините - на самом деле не ответили на вопрос.

Синтезированные ивары работают точно так же, как и обычные ивары, за исключением того, что вам не нужно объявлять их в заголовке. В них нет ничего особенного, кроме этого. Обратите внимание, что синтезированные ивары не требуются, чтобы избежать проблемы хрупкого базового класса.

Директивы @private, @protected и @public существуют для удобства компилятора; дать ему возможность предупреждать (или сообщать об ошибке), когда вы получаете доступ к тому, что объявлено недоступным. Все еще существует относительно плоское пространство имен OBjective-C для контента, и именно это мешает вам иметь iVar с тем же именем в подклассе.

Хрупкая задача базового класса ортогональна свойствам и синтезированным иварам. Хрупкие базовые классы были адресованы в современном ABI Objective-C 2.0 для iPhone OS и 64-битной Mac OS X. 32-битная Mac OS X сохраняет устаревшее поведение по причинам двоичной совместимости.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...