2009-06-17 1 views
2

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

Скажем, у меня есть класс с именем Complex, который используется для проведения комплексных чисел, который имеет метод -(Complex*)add:(Complex*)c;, который добавляет переданным в комплексном числе к self (Complex является изменяемым объектом, скажем).

Так что я могу назвать это таким образом:

Complex *c = [[Complex alloc] withReal: -3.0 andImag: -2.4]; // c = -3.0-2.4i 
[c add : [[Complex alloc] withReal: 1.0 andImag: 2.0]]; // now c = -2.0-0.4i 

Что происходит с памятью, используемой для временного объекта, созданного в вызове add? Я предполагаю, что это утечка памяти; это правильный код?

Complex *c = [[Complex alloc] withReal: -3.0 andImag: -2.4]; // c = -3.0-2.4i 
Complex *b = [[Complex alloc] withReal: 1.0 andImag: 2.0]; // b = 1+2i 
[c add : b]; // now c = -2.0-0.4i 
[b release]; 

Bonus noob question: будет ли сделка с Objective-C 2.0 GC справиться с ситуацией?

ответ

2

Во-первых, с моей шляпой «лучшие практики», когда вы создаете пользовательские классы, Идиома Objective-C - это имя инициализаторов (эквивалент «конструкторов» на других языках) с ведущим «init». Кроме того, старайтесь не сокращать части селектора методов или именованные параметры.

Например, вместо этого:

- (id) withReal:(double)r andImag:(double)i { ... } 

Вы должны рассмотреть это сделать:

- (id) initWithReal:(double)real imaginary:(double)imaginary { ... } 

«и» до того, как вторая часть является делом вкуса - это вполне приемлемо использовать это, но я предпочитаю это без, так как вы, вероятно, не будете использовать его для методов с параметрами 3+. Например, это было бы более подробным, чем необходимо, если бы вы создавали цвет RGB для использования -initWithRed:andGreen:andBlue: - запись/использование -initWithRed:green:blue: обычно предпочтительнее.


Для самого вопроса, то я полностью согласен, что создание класса удобства конструктора это отличный способ пойти на таких ситуации. Это визуально намного чище, чем alloc-init-autorelease каждый раз, когда вам нужен экземпляр throwaway. Соответствующие изменения выше, я бы подправить @ ответ Кента, чтобы выглядеть следующим образом:

+ (Complex*) complexWithReal:(double)real imaginary:(double)imaginary { 
    return [[Complex alloc] initWithReal:real imaginary: imaginary] autorelease]; 
} 

Для бонусного вопроса, да, Objective-C 2.0 в GC будет справиться с этим очень хорошо; наиболее хорошо написанный код сохранения-освобождения работает так же, как и под GC, особенно если вы стараетесь установить указатели на нуль, когда они вам больше не нужны. Когда GC включен, вызовы keep/release/autorelease по существу не работают, и объекты собираются, когда нет ссылок на них. Когда последний указатель на объект потерян или выходит из локальной области, объект имеет право на сбор. (Технически, GC учитывает только ссылки, но если вы сознательно не используете слабые ссылки, то различие, вероятно, сейчас не имеет значения.) Просто помните, что сбор мусора в настоящее время НЕ поддерживается на iPhone.

+0

Спасибо за советы GC - но это будет какое-то время, прежде чем у меня будет царапина, чтобы начать играть с iPhone;) – decitrig

+0

Уверенная вещь. GC отлично, если вы можете использовать его, хотя это означает, что вам нужно отказаться от поддержки Tiger, и все используемые вами фреймворки должны поддерживать GC. Но со временем это станет более распространенным явлением, и кто знает, возможно, по мере того, как iPhone станет быстрее, они также начнут поддерживать GC. :-) –

2

В первом примере:

[c add : [[Complex alloc] withReal: 1.0 andImag: 2.0]]; 

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

Вы можете изменить его autorelease «временный» объект:

[c add : [[[Complex alloc] withReal: 1.0 andImag: 2.0] autorelease]]; 

Вы, вероятно, использовать Инициализировать имя, чтобы указать на то, что объект не autoreleased и пользователь должен обрабатывать память управление:

initWithReal:(double)r andImag:(double)i 

Второй пример верен.

Какао предоставляет множество методов (как статические, так и элемент), которые возвращают autoreleased объектов, например [NSString stringWithString:@"example"], чтобы вы могли создать методы, которые возвращают autoreleased объектов, так что вам не придется иметь дело с выпуском:

Complex * c = [Complex complexWithReal:1.0 andImag:2.0] 

Вы могли бы также создать метод, который использует необработанные данные, например что-то вроде addReal:(double)r andImag:(double)i, чтобы вы могли пропустить шаг alloc/init.

Другой вариант - использовать конструкции, используемые в какао (CGRect и т. Д.). Они те же, что и в C, означают, что они выделены в стеке, и они исчезают после того, как они выходят за пределы области действия, в отличие от выделенных объектов в куче с alloc/init. Хорошо для маленьких объектов, которые часто используются, но часто вы не хотите их держать.

Что касается GC, я не вижу причин, по которым GC не сможет справиться с выпуском объекта. Я не использовал его много, хотя (смотрел только пару примеров - я предпочитаю управлять памятью самостоятельно - если только используя python ...)

1

stefanB является правильным. так как вы будете делать много из этого «на лету» (я бы предположил ...), было бы целесообразно построить статический «удобный» конструктор (есть много примеров из них в appKit & co.)

+(Complex*) complexWithReal:(double)r andImag:(double)i 
{ 
    return [[Complex alloc] initWithReal:r andImag:i] autorelease]; 
} 

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

[c add : [Complex complexWithReal:2.0 andImage:1.0]] 

получайте удовольствие!

 Смежные вопросы

  • Нет связанных вопросов^_^