Правильный способ обработки CGImageRef в контейнерах под ARC

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

Я получаю сообщение «Возможная утечка хранимого объекта…» в одной из своих строк. Вот основной цикл моего кода:

CGImageRef renderedRef = CGBitmapContextCreateImage(UIGraphicsGetCurrentContext());
[_array addObject: (__bridge_transfer id)renderedRef];//_array is an iVar

затем где-то в будущем я делаю это:

    CGImageRef iRef = (__bridge_retained CGImageRef)array[0];
//then I do something fancy with iRef
//at the end of the method, I get "Potential leak of an object stored…"
//I have no idea what to do
//I've tried CGImageRelease(iRef); but it still doesn't change the warning. 

Может ли кто-нибудь пролить свет на это? Кроме того, я пробовал просто использовать __bridge, но это не имеет значения.

Редактировать 1:

Я расширил результаты анализатора и следил за происходящим. Это произошло потому, что я использовал iRef в таком методе: [self doSomethingFancy:iRef]; и в этом методе iRef сохранялся, но не освобождался. Итак, это исправляет предупреждение, но я все еще немного озадачен.

Я не совсем понимаю, когда использовать различные приведения __bridge. При использовании ARC следующее увеличивает количество ссылок?

CGImageRef iRef = (__bridge CGImageRef)array[0];

Кроме того, в какой-то момент, если я скажу своему _array iVar удалить все объекты, будет ли это правильно уменьшать их счетчики ссылок?


person daveMac    schedule 11.12.2013    source источник
comment
CGImageRelease(iRef) здесь правильно. Если у вас все еще есть предупреждение, нажмите на синюю иконку, чтобы получить подробный отчет о том, что думает Анализатор.   -  person Martin R    schedule 12.12.2013
comment
@MartinR Я обновил свой вопрос, чтобы отразить мои выводы.   -  person daveMac    schedule 12.12.2013


Ответы (1)


// This WILL NOT increment the image's retain count.
CGImageRef iRef = (__bridge CGImageRef)array[0];

// This WILL increment the image's retain count.
CGImageRef iRef = (__bridge_retained CGImageRef)array[0];

Поскольку __bridge_retained увеличивает счетчик удержания, вам нужно будет уменьшить его в какой-то момент позже. Поскольку __bridge_retained действует как CFRetain, Apple создала оболочку __bridge_retained под названием CFBridgingRetain, которая напоминает вам об этом:

// This WILL increment the image's retain count.
CGImageRef iRef = CFBridgingRetain(array[0]);

Всякий раз, когда вы видите CFRetain или CFBridgingRetain, вы знаете, что вам нужно освободить объект в какой-то момент позже.

Точно так же вы можете использовать CFBridgingRelease вместо __bridge_transfer для уменьшения счетчика сохранения объекта CF. Пример:

[_array addObject:CFBridgingRelease(renderedRef)];

Вы можете использовать CFBridgingRelease для балансировки CFRetain или CFBridgingRetain. Он возвращает id, которым управляет ARC.

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

[_array removeAllObjects];

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

Таким образом, в этом коде нет утечки памяти:

CGImageRef image = CGImageCreate(...);
[_array addObject:CFBridgingRelease(image)];
[_array removeAllObjects];

или в этом коде:

CGImageRef image = CGImageCreate(...);
[_array addObject:CFBridgingRelease(image)];

CGImageRef image2 = CFBridgingRetain([_array lastObject]);
[_array removeLastObject];
CGContextDrawImage(gc, rect, image2);
CGImageRelease(image2);
person rob mayoff    schedule 11.12.2013
comment
Фантастика, это лучшее объяснение этой щекотливой проблемы, которое я видел. Спасибо, Роб. - person bcattle; 27.01.2015