@ property / @ синтезировать вопрос - PullRequest
10 голосов
/ 05 мая 2011

Я просматриваю всю свою документацию, касающуюся управления памятью, и меня что-то немного смущает.

Когда вы используете @property, он создает методы получения / установки для объекта:

.h: @property (retain, nonatomic) NSString * myString

.m: @synthesize myString

Я понимаю это, но когда я запутался, это использование self.Я вижу разный синтаксис в разных блогах и книгах.Я видел:

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 добавляет еще один шаг к счету удержания?Это правда, я нигде этого не видел.

Имеются ли автоматические геттеры / сеттеры, которые предусмотрены в авто-выпуске?

Как правильно все это делать?

Спасибо!

Ответы [ 3 ]

18 голосов
/ 05 мая 2011

Если вы не используете точечный синтаксис, вы не используете никакой метод установки или получения.

Следующее, это зависит от того, как было объявлено свойство.

Давайте предположим, что-то вроде этого:

@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

Руководство по программированию управления памятью

1 голос
/ 06 мая 2011

В дополнение к ответу Ника - синтезированные геттеры / сеттеры не предоставляют авто-релиз (кстати, какова основная идея сделать это? Ну, вы можете использовать геттер как фабрику, но это не распространено в Objective C).

Тогда в dealloc я вижу:

self.myString = nil;

или

[myString release];

или

self.myString = ноль; [туЗЬптд релиз];

В dealloc не имеет значения, какую форму релиза вы используете. Но хороший способ - обнулить поля при их освобождении :) Я предпочитаю использовать self.myString = nil; в dealloc

1 голос
/ 06 мая 2011

Когда вы создаете retain сеттер, вы создаете что-то вроде этого:

- (void)setString:(NSString *)someString {
    if (someString != string) {
        [string release];
        [someString retain];
        string = someString;
    }
}

Если вы не используете установщик, новое значение не получает сохраняемого значения - вы не «владеете» этой строкой, и, поскольку это все ссылки, если исходная строка освобождена, вы можете столкнуться с нулем ссылка, которая приведет к EXC_BAD_ACCESS. Использование установщика гарантирует, что ваш класс теперь имеет копию этого значения - так что да, он увеличивает счетчик сохранения нового значения. (Обратите внимание, что использование метода получения является соглашением ООП - посторонние не должны иметь возможность напрямую касаться ивара. Также в своем геттере вы можете изменить значение, например, возвращая NSArray, когда ваш ивар является NSMutableArray, например).

Вы не должны autorelease в установщике - Apple использовала его в своем примере кода, но следует иметь в виду, что сеттеры вызываются много раз - потенциально миллионы раз. Все эти объекты входят в один и тот же пул автоматического выпуска, поэтому, если вы не создадите свой собственный и / или не будете регулярно его очищать, в вашем пуле будет куча элементов, все ненужные, но все еще занимающие оперативную память. Намного лучше просто release.

Что касается Deloc, проследите через этот сеттер. Если вы отправите release напрямую, это очевидно - вы освободите этот объект. Но если вы напишите self.string = nil;, то, что вы делаете, это:

  1. Значение nil не совпадает, поэтому вы вводите блок if
  2. Вы отпускаете старое значение - то, что вы хотите сделать
  3. Вы retain ноль: сообщения на ноль ничего не делают, и вы не вылетаете
  4. Вы устанавливаете nil, который не занимает никакой памяти, в строку, которая теперь фактически пуста

Как правило, я использую release в своем методе dealloc, потому что release кажется более окончательным, а dealloc - последний вызов метода, который получит ваш объект. Я использую self.string = nil; в viewDidUnload и методах предупреждения памяти.

Надеюсь, это поможет!

...