2010-04-19 2 views
1

Я пытаюсь обернуть голову вокруг одной части модели памяти Objective-C (в частности, на iPhone, поэтому нет GC). Мой фон C/C++/Java, и у меня возникла проблемы с следующим фрагментом кода (также интересно, если я делаю это в «Objective-C пути» или нет):Модель памяти Objective-C

- (NSSet *) retrieve 
{ 
    NSMutableSet *set; 

    set = [NSMutableSet new]; 
    // would normally fill the set in here with some data 

    return ([set autorelease]); 
} 

- (void) test 
{ 
    NSSet *setA; 
    NSSet *setB; 

    setA = [self retrieve]; 
    setB = [[self retrieve] retain]; 

    [setA release]; 
    [setB release]; 
} 

старта EDIT

Основываясь на комментарии ниже, обновленный метод извлечения:

- (NSSet *) retrieve 
{ 
    NSMutableSet *set; 

    set = [[[NSMutableSet alloc] initWithCapacity:100] autorelease]; 
    // would normally fill the set in here with some data 

    return (set); 
} 

конец РЕДАКТИРОВАТЬ

Приведенный выше код дает предупреждение для [выпуска Seta] «Неправильная декремента счетчика ссылок на объективистские t на данный момент не принадлежит вызывающему ».

Я полагаю, что «новый» установил счетчик ссылок на 1. Затем «сохранить» вызов добавит 1, а вызов «release» опустит его на 1. Учитывая, что не будет установленА имеет счетчик ссылок 0 в конце и setB имеют счетчик ссылок 1 в конце?

Из того, что я выяснил методом проб и ошибок, setB верен, и утечки памяти нет, но я хотел бы понять, почему это так (что не так с моим пониманием «нового», «автореферат», «сохранить» и «освободить»).

ответ

3

Не думайте об абсолютных цифрах. Это может быть очень обманчиво.Думайте о сохранении и выпуске в качестве дельт, если у вас должно быть число - в этом случае уже сбалансировал new (+1 дельта и -1 дельта), чтобы этот метод правильно управлял своей памятью, а приемник не нужно что-либо сделать, если он не хочет держать объект дольше.

Определенно читайте memory management docs. Это действительно так же просто, как следовать описанным там правилам. Это очень простой договор собственности, в котором вы претендуете на право собственности, когда хотите, чтобы объект оставался в стороне и отказывался от владения, когда вам все равно. В приведенном выше случае вы отказываетесь от собственности в методе retrieve, поэтому, пытаясь отказаться от права собственности, когда у вас его нет, это, очевидно, ошибка.

1

http://www.macresearch.org/difference-between-alloc-init-and-new

Вы, вероятно, хотите

NSMutableSet *set = [[NSMutableSet alloc] initWithCapacity: someNumber]; 

или

NSMutableSet *set = [NSMutableSet setWithCapacity: someNumber]; 
+0

Это совершенно не имеет отношения к делу. 'new' эквивалентно' alloc' + 'init', поэтому последствия управления памятью не сложнее. – Chuck

+0

Возможно, вы пропустили часть вопроса, в которой содержался текст «также интересно, делаю ли я это в« Objective-C way »или нет,« Chuck. –

4

я хоть что "новый" установить счетчик ссылок на 1. Затем "сохранить" вызов будет добавьте 1, и вызов «release» опустит его на 1. Учитывая, что не будет установленА имеет счетчик ссылок 0 в конце и setB имеет ссылку c ount 1 в конце?

Вы оставляете autorelease. Когда -(void)test получает набор, его количество удержания равно 0. Вы не сохраняете setA, поэтому он уже имеет счетчик удержания 0 при попытке его выпуска, следовательно, сообщение об ошибке.

fundamental rule for memory management довольно прост: звонки в alloc, new и copy* должны быть уравновешены вызовами release/autorelease. Первые берут на себя ответственность, последние отказываются от собственности.

Единственная сложная часть - это иметь дело с shared objects, где вы не берете на себя ответственность за объект, поэтому его можно отбросить между временем, когда вы получите ссылку на него и когда вы его используете. Это имеет простое решение: если есть сомнения, сохраните его.

Вы можете сделать вещи еще проще, используя properties во многих ситуациях.

+0

Жаль, что я мог бы выбрать два ответа ... что ваши и патроны имеют идеальный смысл. Благодаря! – TofuBeer

2

Как подсказки сообщения профайлера, вы должны думать о правах собственности. Как отмечено в memory management rules, всякий раз, когда у вас есть объект, который вы создали с помощью +alloc, +new, -copy или -mutableCopy, вы являетесь его владельцем и несете ответственность за его выпуск. (Фактически, +new является только сокращением для [[MyClass alloc] init].)

-retain принимает объект, из которого вы изначально не владели и не создали его.

-release принимает объект, который у вас есть, и освобождает его.

-autorelease принимает объект, который у вас есть, и освобождает его право собственности , но также гарантирует, что объект будет существовать хотя бы немного дольше.

Ваш метод -retrieve не передает права собственности на возвращаемый им объект. Это хорошо - это следует за правилами управления памятью (метод не +alloc, +new, -copy, или -mutableCopy). Поэтому использование -release на нем без использования -retain является ошибкой. Было бы одинаково справедливо не сохранять или освобождать результат от -retrieve, если объект будет иметь временный срок службы - ваш -autorelease гарантирует временное существование объекта.

+0

Означает ли это, что я должен создать пул автоматического выпуска в методе тестирования? В противном случае setA и setB не будут в конечном итоге выпущены до окончания программы (так как пул автозапуска в основном настроен)? – TofuBeer

+0

@TofuBeer: Нет. В любой программе, основанной на NSApplication, пул авторезистов создается в начале и уничтожается в конце каждой итерации через runloop. (Это задокументировано в документах управления памятью John, связанных в разделе «Autorelease Pools», если вы хотите прочитать об этом.) – Chuck

+1

Итак, бедный mans GC - спасибо :-) – TofuBeer

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