Распределение памяти iPhone Objective C

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

Но если у меня есть следующий оператор в конце метода:

return [[UIImage alloc] initWithContentsOfFile:path];

Я владею объектом UIImage, потому что я выделил место в памяти, но у меня больше нет ссылки на него, потому что он был возвращен вызывающей стороне. В моем методе dealloc() я не могу его освободить, так как у меня нет ссылки.

Итак, мой вопрос: правильно ли это:

return [[[UIImage alloc] initWithContentsOfFile:path] autorelease];

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

Спасибо за вашу помощь.


person NYTom    schedule 20.08.2012    source источник


Ответы (5)


Весь смысл автовыпуска был построен вокруг возвращаемых объектов.

- (id)bad {
    MyObj *obj = [[MyObj alloc] init];
    return obj;
}

Этот код возвращает все правильно, но вы (как разработчик) должны быть уверены, что освободите объект позже.

- (id)moreBad {
    MyObj *obj = [[MyObj alloc] init];
    return [obj release];
}

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

- (id)good {
    MyObj *obj = [[MyObj alloc] init];
    return [obj autorelease];
}

Этот код является «отложенным выпуском». т.е. вы можете retain объект на стороне вызывающего абонента, и объект будет в безопасности. Это, безусловно, может быть сломано, если у вас нет NSAutoreleasePool в области видимости, но это довольно редкое состояние, и вы в основном знаете, когда это происходит (наиболее распространенный сценарий — запустить новый поток, где нет пула авторелиза «по умолчанию») .

Таким образом, общепринятой практикой является балансировка методов удержания (и подобных им) и методов выпуска в одной области действия. Следующее предложение — всегда иметь объекты alloc-init-autoreleased и переключаться на отдельные выпуски, если у вас есть проблемы с памятью (например, автоматическое освобождение множества объектов в цикле). Следующее предложение — переключиться на ARC.

person Farcaller    schedule 20.08.2012
comment
Реквизит для тщательного объяснения. - person Alexander; 20.08.2012

Ваши предположения верны. Когда вы возвращаете объект, вы должны передать его как объект авторелиза.

Вы используете автоматическое освобождение когда вам нужно отправить сообщение об отложенном выпуске — обычно при возврате объекта из метода...

person Alexander    schedule 20.08.2012
comment
Спасибо, но при использовании ARC, я думаю, я бы не стал использовать autorelease и позволил бы компилятору выполнять все управление памятью. - person NYTom; 20.08.2012
comment
Да, ARC позаботится об отправке релиза всем объектам. - person Alexander; 20.08.2012

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

- (MySomethingClass*)giveMeAFancyObject{
    MySomethingClass *obj = [[[MySomethingClass alloc] init] autorelease];
    obj.name = @"Something";
    // do some setting up maybe
    return obj;
}
person Daniel    schedule 20.08.2012

Однако, если вы используете release, строка будет освобождена до того, как будет возвращена (и метод вернет недопустимый объект). Используя autorelease, вы показываете, что хотите отказаться от владения, но разрешаете вызывающему методу использовать возвращаемую строку до ее освобождения.

person Prabhjot Singh Gogana    schedule 20.08.2012

Зачем пытаться его выделить? Просто скажи:

return [UIImage imageWithContentsOfFile:path];

Нечего выделять - нечего освобождать.

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

person John Smith    schedule 20.08.2012
comment
Я согласен, у класса UIImage есть такой метод, поэтому мне не нужно выделять, класс UIImage будет владеть объектом, поскольку он сам выделяет память. Я просто использовал UIImage в качестве примера возврата экземпляра класса, который вы выделили. - person NYTom; 20.08.2012
comment
Этот метод фактически возвращает автоматически выпущенный объект. - person Alexander; 20.08.2012
comment
Хорошо, если вернуть ранее выделенный объект (в рамках текущего метода, разумеется), сказав return [object_bla_bla autorelease]; этого достаточно, чтобы избежать утечек памяти. То же самое с return [[[Bla_bla_Type alloc] initWith_bla_bla_or_whatever] autorelease]; - person John Smith; 20.08.2012