Objective c 使用在GCD调度队列块外部定义的C指针对象(CGImageRef)时出现内存问题

Objective c 使用在GCD调度队列块外部定义的C指针对象(CGImageRef)时出现内存问题,objective-c,multithreading,pointers,objective-c-blocks,grand-central-dispatch,Objective C,Multithreading,Pointers,Objective C Blocks,Grand Central Dispatch,我正在将一个映像从磁盘读取到一个UIImage中,并在另一个工作队列块中使用它的CGImage进行媒体处理 现在,如果我在主队列中定义CGImageRef,并在工作队列中使用CGImageRef,那么我将获得EXC_BAD_访问权限。像这样: UIImage *uiimage = [UIImage imageWithContentsOfFile:[aPhoto completeLargeThumbFilePath]]; CGImageRef cgImage = uiimage.CGImage;

我正在将一个映像从磁盘读取到一个UIImage中,并在另一个工作队列块中使用它的CGImage进行媒体处理

现在,如果我在主队列中定义CGImageRef,并在工作队列中使用CGImageRef,那么我将获得EXC_BAD_访问权限。像这样:

UIImage *uiimage = [UIImage imageWithContentsOfFile:[aPhoto completeLargeThumbFilePath]];

CGImageRef cgImage = uiimage.CGImage;

dispatch_queue_t    dispatchQueue = dispatch_queue_create("mediaInputQueue", NULL);
[writerInput requestMediaDataWhenReadyOnQueue:dispatchQueue usingBlock:^{

    // ... unrelated stuff
    CVPixelBufferRef buffer = (CVPixelBufferRef)[self pixelBufferFromCGImage:cgImage size:size];
    // ... unrelated stuff
}];
如果直接在工作队列中使用uiimage.CGImage,则不会出现异常。我认为这与ARC内存管理有关。UIImage是objective-c对象,CGImageRef是指向c结构的指针。在第一种情况下,UIImage在我可以使用它的CGImage之前就发布了


我的问题是如何在另一个调度队列的主队列中直接使用定义的C指针?

自动删除
uiimage
。因此,当
UIImage
被自动删除时,
cgImage
很可能被解除分配

您可以尝试保留
cgImage
,然后在块中释放它。或者,您可以在块中使用
uiimage
(将
[uiimage self];
添加到块的末尾--看起来很傻,但可以正常工作)

根本问题是所谓的内部指针问题。您正在获取指向对象内部某个对象的指针,但没有保持对该对象的强引用。当对象离开时,无论内部指针指向什么,都会被捕获,留下一个悬空的指针

我同意这一点:

UIImage *uiimage = [UIImage imageWithContentsOfFile:[aPhoto completeLargeThumbFilePath]];

dispatch_queue_t    dispatchQueue = dispatch_queue_create("mediaInputQueue", NULL);
[writerInput requestMediaDataWhenReadyOnQueue:dispatchQueue usingBlock:^{
    CGImageRef cgImage = uiimage.CGImage;

    // ... unrelated stuff
    CVPixelBufferRef buffer = (CVPixelBufferRef)[self pixelBufferFromCGImage:cgImage size:size];
    // ... unrelated stuff
}];

出现此问题的原因,以及
cgimagerain()
修复此问题的原因,是因为块未保留
CGImage
。这是因为
CGImageRef
不是Objective-C对象指针类型。块仅在为Objective-C对象指针类型时自动保留捕获的变量

这样,一个替代的解决方案是简单地让块捕获一个“对象指针类型”的版本(所有核心基础对象都可以被当作可可对象-C对象,反之亦然):


重复?在两种不同的情况下是相同的原因。谢谢,该帖中的讨论内容非常丰富!谢谢,所以CGImageRetain()和CGImageRelease()是解决方案!谢谢你的解决方案,我认为这对于没有retain方法的东西来说更一般,比如CGImageRetain()。在块外保留而在块内释放不是良好的内存管理实践,因为如果块未运行,则会发生泄漏;如果块多次运行,则会出现过度释放。一旦调度块,它将始终运行。GCD没有取消API。因此,在队列外保留而在块内释放是安全的,这是线程a上保留、线程B上释放的设计模式的延续。然而,我通常也更喜欢@newacct的模式,因为它使开发人员不再需要考虑这个问题。实际上我更喜欢移动
CGImageRef cgImage=uiimage.cgImage编码到块中,并将两个铸件完全挖沟;它们不是必需的。@bbum:Right,但这假设
requestMediaDataWhenRepayonQueue:usingBlock:
方法实现了您的期望。在本例中使用
uiimage.CGImage
是有效的,因为在本例中有一个“关联的”Objective-C对象,即uiimage对象。但是,1)可能是使用UIImage对象比CGImage对象使用更多的资源(我不确定这是否正确,但可能是其他对象),因此您可能不想保留它;或者2)一般来说,对于给定的核心基础对象,可能没有这样的关联ObjuleC对象。或者,使用内部指针假定对象将在包含对象的破坏中幸存。该死的如果你做了,该死的如果你不做。
UIImage *uiimage = [UIImage imageWithContentsOfFile:[aPhoto completeLargeThumbFilePath]];

CGImageRef cgImage = uiimage.CGImage;

id cgImageAsObject = (__bridge id)cgImage;

dispatch_queue_t    dispatchQueue = dispatch_queue_create("mediaInputQueue", NULL);
[writerInput requestMediaDataWhenReadyOnQueue:dispatchQueue usingBlock:^{

    // ... unrelated stuff
    CGImageRef cgImageAgain = (__bridge CGImageRef)cgImageAsObject;
    CVPixelBufferRef buffer = (CVPixelBufferRef)[self pixelBufferFromCGImage:cgImageAgain size:size];
    // ... unrelated stuff
}];