Reputation: 13916
I'm reading an image from disk into a UIImage, and using its CGImage in another worker queue block for media processing.
Now I'm getting EXC_BAD_ACCESS if I define a CGImageRef in the main queue, and use the CGImageRef in the worker queue. Like this:
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
}];
If I use uiimage.CGImage directly in the worker queue, then I don't get the exception. I think this is related to the ARC memory management. UIImage is an objective-c object, and CGImageRef is a pointer to an C struct. The UIImage is released before I can use its CGImage in the first case.
My question is how can I directly use a C pointer defined in main queue in another dispatch queue?
Upvotes: 2
Views: 883
Reputation: 162712
The uiimage
is autoreleased. Thus, most likely, the cgImage
is being deallocated when the UIImage
is autoreleased.
You could try retaining the cgImage
and then releasing it in the block. Or you could use the uiimage
in the block (add [uiimage self];
to the end of the block -- looks goofy, but works).
The underlying issue is what is called the interior pointer problem. You are grabbing a pointer to something inside an object, but not maintaining a strong reference to the object. When the object goes away, whatever the interior pointer points to is reaped and you are left with a dangling pointer.
I'd go with this:
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
}];
Upvotes: 2
Reputation: 122449
The reason you have this problem, and the reason that CGImageRetain()
fixes it, is because the CGImage
is not retained by the block. This is because CGImageRef
is not an Objective-C object pointer type. Blocks only automatically retain captured variables when they are Objective-C object pointer types.
So an alternate solution is to simply let the block capture an "object pointer type" version of it (all Core Foundation objects can be treated as Cocoa Objective-C objects, and vice versa):
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
}];
Upvotes: 3