UIImage imageNamed не автоматически высвобождает правильно - PullRequest
3 голосов
/ 28 мая 2010

По какой-то причине поведение сохранения / выпуска в следующем коде полностью сбило меня с толку.

selectedImage = [UIImage imageNamed:@"icon_72.png"];
[selectedImage release];

Это должно сломаться, но не . Зачем? Я думал, что imageNamed самовыпускается автоматически, что означает, что освобождение здесь избыточно и должно прерваться, когда произойдет автоматическое освобождение.

Вот фрагменты, относящиеся к selectedImage из файлов .h и .m:

@property (nonatomic, readonly) UIImage *selectedImage;
@synthesize delegate, selectedImage, spacerBottom, currentIndex;

Другие примечания, это делает перерыв:

selectedImage = [UIImage imageNamed:@"icon_72.png"];
[selectedImage release];
[selectedImage release];
//objc[55541]: FREED(id): message release sent to freed object=0x59245b0
//Program received signal:  “EXC_BAD_INSTRUCTION”.

Как делает это:

selectedImage = [UIImage imageNamed:@"icon_72.png"];
[selectedImage release];
[selectedImage autorelease];
//objc[55403]: FREED(id): message autorelease sent to freed object=0x59b54c0
//Program received signal:  “EXC_BAD_INSTRUCTION”.

И так делает следующее:

selectedImage = [UIImage imageNamed:@"icon_72.png"];
[selectedImage autorelease];
[selectedImage release];
//objc[55264]: FREED(id): message release sent to freed object=0x592c9a0
//Program received signal:  “EXC_BAD_INSTRUCTION”.

И так делает это:

selectedImage = [UIImage imageNamed:@"icon_72.png"];
[selectedImage autorelease];
[selectedImage autorelease];
//objc[55635]: FREED(id): message release sent to freed object=0x5b305d0
//Program received signal:  “EXC_BAD_INSTRUCTION”.

Ответы [ 4 ]

11 голосов
/ 28 мая 2010

-imageNamed: возвращает автоматически выпущенное изображение, которое, как говорит deanWombourne, будет автоматически выпущено в будущем (точное время не определено).

Причина, по которой он не выпускается автоматически, как вы, возможно, уже привыкли, в том, что -imageNamed также кэширует возвращаемое изображение. Кеш сохраняет изображение.

По сути, цикл сохранения выглядит примерно так:

  • -imageNamed: вызвано,
    • Система выделяет и инициализирует образ - сохраняет количество = 1;
    • Образ системного кэша - сохранить счет = 2;
    • Система автоматически выпускает изображение и возвращает вам - оставьте счет = 1; (теоретически изображение все еще имеет счет 2, поскольку пул автоматического выпуска еще не выпустил его).
  • вы вызываете команду release на изображении - значение count должно быть равно 0, а объект должен быть освобожден.
  • В какой-то момент в будущем (в конце цикла выполнения) пул автоматического освобождения должен освободить образ и произойдет сбой, потому что вы перепустили его.

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

Надеюсь, это прояснит ситуацию.

8 голосов
/ 28 мая 2010

Странно и странно, да. Но не совсем необъяснимо. это то, что я думаю, что происходит.

Ты прав; imageNamed: возвращает автоматически освобожденный объект. это означает, что он выйдет когда-нибудь в будущем, так что если вы сразу же вызовете release для него, это не вызовет ошибку - релиз не является экстрасенсорным, он не знает, что пул авто-выпусков также выпустит его! 1004 *

Если вы оставили свой код в пуле автоматического выпуска, в конце концов попытаетесь снова его освободить, и , тогда вы получите ожидаемую ошибку.

Вы на самом деле ответили на наш собственный вопрос - вы говорите «должен сломаться, когда происходит авто-релиз», что абсолютно правильно, когда происходит авто-релиз, он сломается:)

Другие примеры не работают, потому что вы заставляете выпуски происходить, либо вызывая их напрямую, либо делая достаточно вещей, чтобы пул автозапуска запускался и вызывал релиз для вас. (Вы не можете предсказать, когда пул авто-релиза будет запущен, вы можете просто знать, что в какой-то момент цикла запуска автоматически освобожденные вещи могут быть освобождены.)

0 голосов
/ 21 сентября 2010

Когда я создаю эту категорию:

@implementation UIImage (ReleaseChecks)

+ (id)allocWithZone:(NSZone *)zone
{
    id o = [super allocWithZone:(NSZone *)zone];
    NSLog(@"Image post-ALLOC: 0x%x",
                (unsigned int)o );
    return o;
}

- (id)autorelease
{
    NSLog(@"Image pre-AUTORELEASE: 0x%x; Retain Count %u",
                (unsigned int)self,
                (unsigned int)[self retainCount]
                );
    return [super autorelease];
}

- (void)release
{
    NSLog(@"Image pre-RELEASE: 0x%x\n; Retain Count %u",
                (unsigned int)self,
                (unsigned int)[self retainCount]
                );
    [super release];
}

- (void)dealloc {
    NSLog(@"Image pre-DEALLOC: 0x%x\n; Retain Count %u",
                (unsigned int)self,
                (unsigned int)[self retainCount]
                );
    [super dealloc];
}

Похоже, что -autorelease не вызывается при выделении с + imageNamed :.

Однако, когда я создал целую кучу из них с + imageNamed: и позже получил предупреждение о памяти, я вижу их все release и dealloc.Это было проверено на iPhone Simulator 4.0.

0 голосов
/ 28 мая 2010

Вы говорите, что "Это должно сломаться"

selectedImage = [UIImage imageNamed:@"icon_72.png"];
[selectedImage release];

Вы не правы.

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

Как работает UIImage - это деталь реализации, а не ваша забота. Все, что вы знаете, это то, что вы должны быть в состоянии ОЖИДАТЬ, что это сработает, если вы будете следовать правилам, которые, как я считаю, сейчас называются NARC, и которые вы еще не сделали здесь. Нигде объекты не могут «сломаться», если вы используете их неправильно. Вы не можете рассчитывать на освобождение объектов при их использовании, что не является частью контракта на управление памятью.

Не все объекты Apple работают как классы / экземпляры учебников - в действительности объекты могут кэшироваться, повторно использоваться, перерабатываться или вообще не быть объектами.

Не волнуйтесь, следуйте правилам.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...