@property/@synthesize вопрос
Я просматриваю всю мою документацию по управлению памятью, и я немного смущен.
Когда вы используете @property, он создает геттеры/сеттеры для объекта:
.h: @property (сохранить, неатомно) NSString * myString
.m: @synthesize myString
Я понимаю это, но там, где я запутался, это использование самого себя. Я вижу различный синтаксис в разных блогах и книгах. Я видел:
myString = [NSString alloc] initWithString:@"Hi there"];
или
self.myString = [NSString alloc] initWithString:@"Hi there"];
Затем в dealloc я вижу:
self.myString = nil;
или
[myString release];
или
self.myString = nil;
[myString release];
На этом сайте кто-то сказал, что использование self добавляет еще один прирост к счету сохранения? Это правда, я этого нигде не видел.
Используются ли автоматические геттеры/сеттеры, которые предоставляются авторефератом?
Каков правильный способ сделать все это?
Спасибо!
Ответы
Ответ 1
Если вы не используете синтаксис точки, вы не используете какой-либо сеттер или getter.
Следующее, это зависит от того, как было объявлено свойство.
Предположим, что-то вроде этого:
@property (nonatomic, retain) Article *article;
...
@synthesize article;
Назначение для статьи с помощью
self.article = [[Article alloc] init];
будет перегружать экземпляр, возвращаемый alloc/init, и вызвать утечку. Это связано с тем, что установщик статьи сохранит его и выпустит для вас любой предыдущий экземпляр.
Итак, вы можете переписать его как:
self.article = [[[Article alloc] init] autorelease];
Выполнение этого
article = [[Article alloc] init];
также нормально, но может включать утечку, поскольку статья может содержать ссылку на экземпляр уже. Поэтому необходимо заранее освободить значение:
[article release];
article = [[Article alloc] init];
Свободная память может быть выполнена с помощью
[article release];
или
self.article = nil;
Первый имеет доступ к полю напрямую, не участвует в сеттерах/геттерах. Второй устанавливает нуль в поле с помощью сеттера. Который освободит текущий экземпляр, если он есть, прежде чем установить его на нуль.
Эта конструкция
self.myString = nil;
[myString release];
просто слишком много, он фактически отправляет освобождение на нуль, что безвредно, но также бесполезно.
Вам просто нужно мысленно отобразить шляпу с использованием точечного синтаксиса с помощью методов доступа:
self.article = newArticle
// is
[self setArticle:newArticle];
и
myArticle = self.article;
// is
myArticle = [self article];
Некоторые предложения по чтению, все официальные документы Apple:
Язык программирования Objective-C
Руководство по программированию памяти
Ответ 2
Когда вы создаете setter retain
, вы создаете что-то вроде этого:
- (void)setString:(NSString *)someString {
if (someString != string) {
[string release];
[someString retain];
string = someString;
}
}
Если вы не используете setter, новое значение не получает, чтобы сохранить - вы не "владеете" этой строкой, и потому что все ссылки, если исходная строка выпущена, вы можете столкнуться с нулевым ссылка, которая приведет к EXC_BAD_ACCESS
. Использование setter гарантирует, что ваш класс теперь имеет копию этого значения, поэтому да, он увеличивает счет сохранения нового значения. (Обратите внимание, что использование геттера - это соглашение ООП, что аутсайдеры не должны иметь возможность напрямую касаться ivar. Также в вашем получателе вы можете изменить значение, возможно, вернуть NSArray, когда ваш ivar - это NSMutableArray, например).
Вы не должны autorelease
в сеттере. Apple использовала его в своем примере кода, но нужно иметь в виду, что сеттеры называются много-миллионными раз, потенциально. Все эти объекты входят в один и тот же пул авторезистов, поэтому, если вы не создадите свой собственный и/или регулярно его не очищаете, у вас будет множество элементов в вашем пуле, все ненужные, но все еще занятые оперативной памятью. Гораздо лучше просто release
.
Что касается dealloc, проследите через этот сеттер. Если вы отправляете release
напрямую, это очевидно - вы выпускаете этот объект. Но если вы пишете self.string = nil;
, то вы делаете следующее:
- Значение nil не совпадает, поэтому вы вводите
if
block
- Вы публикуете старое значение - то, что вы хотите сделать
- Вы
retain
nil: сообщения ниль ничего не делаете, и вы не сработаете
- Вы устанавливаете ниль, которая не принимает никакой памяти, в строку, которая теперь фактически пуста.
Как правило, я использую release
в моем методе dealloc
, потому что release
кажется более окончательным, а dealloc
- это окончательный вызов метода, который получит ваш объект. Я использую self.string = nil;
в методах viewDidUnload и методах памяти.
Надеюсь, это поможет!
Ответ 3
В дополнение к Nick ответ - синтезированные геттеры/сеттеры не предоставляют autorelease (кстати, какая большая идея для этого? Ну, вы можете использовать getter как factory, но это не обычный способ в Objective C).
Затем в dealloc я вижу:
self.myString = nil;
или
[выпуск myString];
или
self.myString = nil; [туЗЬптд релиз];
В dealloc не имеет значения, какую форму выпуска вы используете. Но хороший способ состоит в том, чтобы сбрасывать ваши поля при их выпуске:) Я предпочитаю использовать self.myString = nil;
в dealloc