Objective-C Setter Управление памятью - PullRequest
2 голосов
/ 09 июня 2009

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

NSString *theBackendResponse = [[NSString alloc] initWithData:receivedData encoding:NSASCIIStringEncoding];
NSDictionary *accountDictionary = [theBackendResponse propertyList];
[viewController setAccountDictionary:accountDictionary];

Теперь, что мне делать с accountDictionary в методе setAccountDictionary моего контроллера представления? Прямо сейчас я просто устанавливаю переменную экземпляра "accountDictionary" на то, что возвращается. Должен ли я установить его на сохраненный, а затем выпустить тот, который вернулся? Как должен выглядеть мой блок кода установщика, учитывая, что метод propertyList NSString автоматически освобожден?

Кстати, если я выпущу theBackendResponse, я потеряю accountDictionary? Я полагаю, нет ...

Ответы [ 4 ]

14 голосов
/ 09 июня 2009

Вызов [objectInstance autorelease] добавляет объект к текущему NSAutoreleasePool. Когда этот пул получает сообщение drain, он отправляет release всем объектам в пуле. Если какой-либо из этих объектов retainCount достигает 0, они освобождаются в этой точке. Цель автоматического выпуска состоит в том, чтобы позволить вам пометить объект, который будет выпущен "когда-нибудь в будущем". Это особенно полезно для таких вещей, как методы, которые возвращают недавно выделенный объект, но хотят освободить его, чтобы вызывающая сторона не должна была вступать во владение возвращенным объектом. Метод может выглядеть так:

- (id)myMethod {
    id myObj = [[SomeClass alloc] init];

    ...

    return [myObj autorelease];
}

Вызывающий myMethod затем retain вернет возвращаемое значение, если они захотят стать владельцем возвращенного значения или проигнорируют его, если нет. Когда текущий NSAutoreleasePool истощится, myObj получит сообщение об освобождении. Если никакие другие объекты не владеют им (т.е. отправили ему сообщение retain), он будет освобожден.

Все это объясняется в Какао Руководство по программированию управления памятью . Даже если вы уже прочитали его, его всегда стоит прочесть.

Итак, чтобы ответить на ваши вопросы:

Во-первых, вы должны выпустить theBackendResponse. Вы потеряете память, если вы этого не сделаете. Вам не нужно знать, что accountDictionary делает со строкой: если ей нужно сохранить ссылку, она сохранит theBackendResponse. Вы владеете theBackendResponse, потому что вы alloc сделали это, поэтому вы должны отказаться от этого владения (через release или косвенно через autorelease).

Во-вторых, вы должны сохранить или скопировать аргумент в setAccountDictionary:, если хотите сохранить ссылку на этот объект или значение соответственно. Стандартный метод установки выглядит примерно так (при условии, что вам не нужна атомарная семантика):

-(void)setAccountDictionary:(NSDictionary*)newDict {
  if(newDict != accountDictionary) {
    id tmp = accountDictionary;
    accountDictionary = [newDict copy]; //Since newDict may be mutable, we make a copy so that accountDictionary isn't mutated behind our back.
    [tmp release];
  }
}

Вы также должны запомнить release accountDictionary в методе dealloc:

- (void)dealloc {
    [accountDictionary release];
    [super dealloc];
}

Поскольку вы, похоже, используете NSViewController, я предполагаю, что вы используете Leopard (OS X 10.5), и в этом случае вам, вероятно, следует использовать @property и @synthesize d, если возможно, метод получения / установки. Для этого добавьте

@property (copy,readwrite) NSDictionary * accountDictionary; 

объявление в класс @interface. И добавьте директиву @synthesize accountDictionary; в блоке @implementation для вашего класса контроллера.

4 голосов
/ 09 июня 2009

Как правило, один объект или метод не должен заботиться о том, как другой управляет памятью. Тот факт, что кто-то другой выпустил что-то автоматически, для вас не имеет значения. Проще подумать о концепции владения . Таким образом, retain и некоторые другие методы требуют права собственности, а release и autorelease отказываются от него. Если объект должен сохранять ссылку на другой объект, он должен требовать владения столько, сколько ему нужно. Таким образом, методы установки обычно либо сохраняют, либо копируют новое значение и освобождают, либо автоматически освобождают старое значение.

Я настоятельно рекомендую прочитать Руководство по управлению памятью Какао . Они не такие уж длинные и сложные, и их очень важно понимать.

3 голосов
/ 30 июля 2011

Метод метода доступа set должен всегда copy / retain входящее значение перед освобождением старого, в случае, когда старое значение является единственным объектом, которому принадлежит новое значение:

-(void)setAccountDictionary:(NSDictionary*)newDict {
    id old = accountDictionary;
    accountDictionary = [newDict copy];
    [old release];
}

Если accountDictionary относится к newDict и счет удержания для newDict равен 1, то вызов [accountDictionary release] до вызова [newDict copy] приведет к тому, что счет удержания достигнет 0 и, следовательно, освободит newDict.

В качестве примера неверного кода, где мы выпускаем старый словарь, а затем копируем новый словарь:

-(void)setAccountDictionary:(NSDictionary*)newDict {
    [accountDictionary release];
    accountDictionary = [newDict copy];
}

и иметь следующий код:

NSDictionary *dict = [obj accountDictionary];
[obj setAccountDictionary:dict];

Он придуман, но показывает, что в установщике accountDictionary и newDict относятся к одному и тому же экземпляру. Если счет сохранения равен 1, строка [accountDictionary release] уменьшит счет хранения до 0 и, таким образом, освободит экземпляр из памяти. [newDict copy] теперь будет ссылаться на недопустимый экземпляр.

2 голосов
/ 09 июня 2009

Apple описывает несколько концепций при реализации аксессоров: Методы доступа к управлению памятью
Если вы можете использовать Objective-C 2.0, я бы использовал свойства и точечный синтаксис. Свойства являются новыми в Objective-C 2.0 и обеспечивают автоматическое создание аксессоров.
В .h файле:

@property (retain) NSDictionary* accountDictionary;

В реализации:

@synthesize accountDictionary;

Synthesize генерирует методы доступа для вашего NSDictionary. (Если вы хотите предоставить собственную реализацию, вы также можете это сделать)

...