При объявлении свойства как nonatomic
вы получите следующее:
// .h
@property (nonatomic, retain) id ivar;
// .m
- (id)ivar {
return ivar;
}
- (void)setIvar:(id)newValue {
if (ivar != newValue) { // this check is mandatory
[ivar release];
ivar = [newValue retain];
}
}
Обратите внимание на отметку ivar != newValue
.Если он отсутствует, ivar может быть освобожден после release
, а следующее retain
вызовет ошибку доступа к памяти.
Когда вы объявляете свойство с помощью copy
, код будет выглядеть почтито же самое, с retain
, замененным на copy
.
Для assign
, это еще проще:
- (void)setIvar:(id)newValue {
ivar = newValue;
}
Теперь, когда вы объявляете свою собственность как atomic
(по умолчанию), все немного сложнее.Фрагмент, похожий на приведенный ниже, был опубликован одним из инженеров Apple на форумах разработчиков:
- (id)ivar {
@synchronized (self) {
return [[self->ivar retain] autorelease];
}
}
- (void)setIvar:(id)newValue {
@synchronized (self) {
if (newValue != self->ivar) {
[self->ivar release];
self->ivar = newValue;
[self->ivar retain];
}
}
}
Обратите внимание на блок @synchronized
в обоих методах и дополнительный retain-autorelease
в геттере.Обе эти вещи гарантируют, что вы получите либо предыдущее значение (сохраненное и автоматически освобожденное), либо новое в случае, если значение изменяется каким-либо потоком, пока вы пытаетесь его прочитать.