在ARC下处理容器中的CGImageRef的正确方法

4

我是新手,正在尝试将arc应用到我的项目中。我想要了解__bridge及其相关内容,以便在将CGImageRef添加到容器时正确地进行类型转换。

某一行代码上出现了“Potential leak of an object stored…”的警告。以下是我的代码循环的基本过程:

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使用removeAllObjects方法,是否会正确地减少它们的引用计数?

在这里使用CGImageRelease(iRef)是正确的。如果您仍然收到警告,请单击蓝色图标以获取有关分析器认为的详细报告。 - Martin R
@MartinR 我更新了我的问题以反映我的发现。 - daveMac
1个回答

7
// 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,因此苹果创建了一个名为CFBridgingRetain__bridge_retained包装器,以提醒您注意这一点:
// This WILL increment the image's retain count.
CGImageRef iRef = CFBridgingRetain(array[0]);

无论何时看到CFRetainCFBridgingRetain,您都需要稍后释放对象。
同样,您可以使用CFBridgingRelease代替__bridge_transfer来减少CF对象的保留计数。例子:
[_array addObject:CFBridgingRelease(renderedRef)];

你可以使用 CFBridgingRelease 来平衡 CFRetainCFBridgingRetain。它返回一个 ARC 管理的 id
普通的 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);

太棒了,这是我见过的关于这个棘手问题最好的解释。谢谢Rob。 - bcattle

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接