@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