Проблемы с управлением памятью в Objective C

Я знаю, что это обсуждалось до тошноты, но я просто не понимаю управления памятью. Я понимаю, что сохранение сохраняет объект в живых, а copy дает отдельную копию объекта.

Чего я не понимаю, так это того, что когда дело доходит до ivars и свойств, сохранение в качестве свойства означает, что установщик освобождает старое значение и сохраняет новое:

property = newValue;
// retain
if (property != newValue)
{
   [property release];
    property = [newValue retain];
}

но я видел примеры, в которых они назначают статические строки для сохраненных свойств ivars, например.

self.stringProperty = @"something";
(some other code)
self.stringProperty = @"somethingElse";

Второй вызов для установки строки должен вызывать освобождение статической строки, что недопустимо, почему программа не аварийно завершает работу?

Кроме того, если объект объявлен со свойством сохранения, а затем ему что-то назначается с помощью init, например

@property(retain)someArray;

someArray = [[NSArray alloc] initWithArray:arbArray];

означает ли это, что someArray теперь имеет счетчик сохранения 2, но если он был создан с помощью

someArray = [NSArray arrayWithArray:arbArray];

счетчик удержания равен только 1, потому что второй - заводской метод?


person Spider-Paddy    schedule 09.07.2010    source источник
comment
Извините, я имел в виду self.someArray в обоих примерах.   -  person Spider-Paddy    schedule 12.07.2010


Ответы (3)


Второй вызов для установки строки должен вызывать освобождение статической строки, что недопустимо, почему программа не аварийно завершает работу?

Вы можете передать release в постоянную строку, это просто не будет делать ничего значимого, поэтому эти строки кода действительны.

Означает ли это, что someArray теперь имеет счетчик сохранения 2, но если он был создан с помощью ... счетчик сохранения равен только 1, потому что второй метод является фабричным?

Ну, во-первых,

someArray = [[NSArray alloc] initWithArray:arbArray];

не использует методы, созданные @property, он просто обращается к ivar напрямую. Чтобы использовать методы свойств, вам нужно использовать self.someArray = ...;.

Но да,

[[NSArray alloc] initWithArray:arbArray]

возвращает объект с эффективным счетчиком удержания 1, и

[NSArray arrayWithArray:arbArray]

возвращает объект с эффективным счетчиком сохранения, равным 0, поэтому, если вы действительно пропустили их через установщик "сохранения", созданный @property, у ivar будет эффективное количество удержаний 2 и 1 соответственно.

person mipadi    schedule 09.07.2010
comment
Спасибо. Я не могу вспомнить все 5 критериев хорошего общения, но ваш ответ соответствовал 3, которые я помню: ясно, кратко, правильно. - person Spider-Paddy; 12.07.2010

Это не тот вопрос, но все же ...

Статические строки - это особые случаи во многих отношениях, одним из которых является то, что вы можете retain и release их сколько душе угодно, без какого-либо эффекта.

Кстати, NString свойства часто имеют copy, а не retain семантику, что в любом случае сняло бы этот вопрос, если бы это имело значение. Но это не так.

Во втором случае присвоение свойству retain непосредственно из alloc (или copy, или другого вызова, подтверждающего право собственности) является плохой практикой и будет утечкой, если вы не добавите соответствующий release впоследствии или autorelease во время, например:

self.someArray = [[[NSArray alloc] initWithArray:arbArray] autorelease];

Но на самом деле нет причин не использовать метод класса в этом конкретном случае.

person walkytalky    schedule 09.07.2010
comment
Вторая часть, касающаяся счетчиков удержания, была моим фактическим вопросом, первая часть была просто чем-то, что меня беспокоило, но я разделю вопросы в будущем. Спасибо за ответ. - person Spider-Paddy; 12.07.2010

Второй вызов для установки строки должен вызывать освобождение статической строки, что недопустимо, почему программа не аварийно завершает работу?

Это не статическая строка, это постоянная строка. Однако это не имеет отношения к вопросу, но на самом деле вам разрешено отправлять -retain любому объекту Objective-C, производному от NSObject кроме NSAutoreleasePool. Если вы посмотрите на keepCount (немного непослушно, но поскольку мы обсуждаем реализацию, хорошо) константы NSString, например.

NSLog(@"retain count = %u", [@"foo" retainCount]);

вы, скорее всего, обнаружите, что для него установлено действительно большое число (на самом деле UINT_MAX). Это сигнал среде выполнения, чтобы игнорировать призывы к освобождению и сохранению.

Кстати, если вы забудете освободить объекты, программа не выйдет из строя сразу. Фактически, если у вас много оперативной памяти, вы можете не заметить этого, пока ОС не начнет менять местами.

означает ли это, что someArray теперь имеет счетчик сохранения 2, но если он был создан с помощью

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

self.someArray = [[NSArray alloc] initWithArray:arbArray];

будет утечка.

self.someArray = [NSArray arrayWithArray:arbArray];

было бы хорошо.

person JeremyP    schedule 09.07.2010