У меня есть некоторые вопросы о синтезируемых свойствах в Objective C. Полный список следует, но основной вопрос - это: Как компилятор гарантирует, что ivars для синтезируемых свойств правильно выпущены, даже при том, что мой код может или не может включать методы выпуска в dealloc?
Примечание: Я решил не отправить их как отдельные вопросы, потому что они так тесно связаны и потому что существует горстка существующих вопросов, которые затрагивают отдельные проблемы, действительно не добираясь до сути дела.
Несколько подобные вопросы:
Установка: Рассмотрите класс с единственным свойством:
@interface Person : NSObject
{
NSString * name;
}
@property (nonatomic, retain) name;
@end
Вопрос № 1: очень простой случай:
@implementation Person
@synthesize name;
@end
С этой установкой я принимаю это name
будет автоматически выпущен каждый раз, когда a Person
объект выпущен. В моем уме компилятор просто вставляет [name release]
в dealloc
метод, как будто я ввел его сам. Это корректно?
Вопрос № 2: Если я принимаю решение записать свое собственное dealloc
метод для этого класса, и я опускаю вызов к [name release]
, это протечет?
@implementation Person
@synthesize name;
- (void)dealloc { [super dealloc]; }
@end
Вопрос № 3: Если я принимаю решение записать свое собственное dealloc
метод для этого класса, и я включаю вызов в [name release]
, будет тот результат в двойном выпуске с тех пор @synthesize
уже заботился о нем для меня?
@implementation Person
@synthesize name;
- (void)dealloc { [name release]; [super dealloc]; }
@end
Вопрос № 4: Если я принимаю решение записать свое собственное средство доступа свойства для этого класса, но я не пишу свое собственное dealloc
метод, будет name
быть пропущенными?
@implementation Person
@dynamic name;
- (void)setName:(NSString *)newName
{
[newName retain];
[name release];
name = newName;
}
@end
Вопрос № 5: у Меня есть чувство (на основе опыта), что ни один из вышеупомянутых сценариев не приведет к утечкам или двойным выпускам, так как язык был разработан для предотвращения их. Это, конечно, поднимает вопрос "как?". Компилятор просто достаточно умен для отслеживания каждый возможный случай? Что, если я должен был сделать следующее (отмечают, что это - смехотворный пример, просто означало иллюстрировать мой тезис):
void Cleanup(id object) { [object release]; }
@implementation Person
@synthesize name;
- (void)dealloc { Cleanup(name); }
@end
Был бы тот дурак компилятор в добавление другого [name release]
к dealloc
метод?
Q1:
Нет. @synthesize
не изменяет -dealloc
за вас. Вы должны -выпустить
имя
самостоятельно.
Q2:
Да, утечка будет. По той же причине, что и Q1.
Q3:
Нет, это не будет двойного релиза. По той же причине, что и Q1.
Q4:
Да, утечка будет. По той же причине, что и Q1.
Q5:
Нет, это не будет двойного выпуска. По той же причине, что и Q1.
Вы можете проверить это самостоятельно, переопределив -retain
и -release
и -dealloc
, чтобы сообщить о том, что происходит.
#import <Foundation/Foundation.h>
@interface X : NSObject {}
@end
@implementation X
-(oneway void)release {
NSLog(@"Releasing %p, next count = %d", self, [self retainCount]-1);
[super release];
}
-(id)retain {
NSLog(@"Retaining %p, next count = %d", self, [self retainCount]+1);
return [super retain];
}
-(void)dealloc {
NSLog(@"Dealloc %p", self);
[super dealloc];
}
@end
@interface Y : NSObject {
X* x;
}
@property (nonatomic, retain) X* x;
@end
@implementation Y
@synthesize x;
- (void)dealloc { [x release]; [super dealloc]; }
@end
int main () {
NSAutoreleasePool* pool = [[NSAutoreleasePool alloc] init];
Y* y = [[Y alloc] init];
X* x = [[X alloc] init];
y.x = x;
[y release];
[x release];
[pool drain];
return 0;
}
В Q1, Q2 и Q4 последний -retainCount
из x
равен 1, поэтому есть утечка, а в Q3 и Q5 последний -retainCount
равен 0 и вызывается -dealloc
, поэтому утечки нет.
Из документации Objective-C по свойствам :
dealloc
Объявленные свойства в основном принимают место объявления метода доступа ; когда вы синтезируете свойство , компилятор создает только любые отсутствующие методы доступа. Нет прямого взаимодействия с методом dealloc - свойства не автоматически освобождаются для вас. Однако объявленные свойства предоставляют полезный способ перекрестной проверки реализации вашего метода dealloc : вы можете найти все объявления свойств в файле заголовка и убедиться, что Свойства объекта , не отмеченные как присвоение, освобождаются, а те, которые отмечены как присвоение, не освобождаются.
Это, по сути, ответ на все ваши вопросы.