对内存管理并不熟悉(最近才开始我的iOS旅程,我被ARC宠爱),我想成为一个好女孩,避免泄漏以及我知道如何。
我从AVFoundations captureStillImageAsynchronouslyFromConnection
的视频连接捕获静止图像,因为我想访问图像字节。我也在使用Core Foundation和Core Graphics。
现在,当iOS完成捕获块并尝试释放对象时,我遇到了错误的访问异常。我一定是过分了。
我认为我说得对:
编辑:为我的示例代码添加了一项优化,简称Matthias Bauch:CFDataCreateWithBytesNoCopy
的内存处理出错,我CFRelease
现在正确。这不会导致问题。
编辑2:感谢Matthias Bauch,我已经能够将其缩小到一个被调用的方法。除了其他所有内容,但是这种方法,我可以制作尽可能多的快照,没有例外。我在调用它的captureStillImageAsynchronouslyFromConnection
块下面添加了那个代码。我将继续以这种方式找出问题所在......
编辑3:在被调用的方法中,发布了2件我不负责的东西。感谢newacct,他一点一点地解释了它,我现在有了一种工作方法。我发布下面的工作代码。
带有块的 captureStillImageAsynchronouslyFromConnection
:
[[self imageOutput] captureStillImageAsynchronouslyFromConnection:videoConnection completionHandler: ^(CMSampleBufferRef imageSampleBuffer, NSError *error)
{ // get time stamp for image capture
NSDate *timeStamp = [NSDate date];
//get all the metadata in the image
CFDictionaryRef metadata = CMCopyDictionaryOfAttachments(kCFAllocatorDefault,
imageSampleBuffer,
kCMAttachmentMode_ShouldPropagate);
// get image reference
CVImageBufferRef imageBuffer = CMSampleBufferGetImageBuffer(imageSampleBuffer);
// >>>>>>>>>> lock buffer address
CVPixelBufferLockBaseAddress(imageBuffer, 0);
//Get information about the image
uint8_t *baseAddress = (uint8_t *)CVPixelBufferGetBaseAddress(imageBuffer);
size_t dataSize = CVPixelBufferGetDataSize(imageBuffer);
size_t bytesPerRow = CVPixelBufferGetBytesPerRow(imageBuffer);
size_t width = CVPixelBufferGetWidth(imageBuffer);
size_t height = CVPixelBufferGetHeight(imageBuffer);
// create a pointer to the image data
CFDataRef rawImageBytes = CFDataCreateWithBytesNoCopy(kCFAllocatorDefault, baseAddress, dataSize, kCFAllocatorNull);
// create the color space for the current device
CGColorSpaceRef colorSpace = CGColorSpaceCreateDeviceRGB();
//Create a bitmap context
CGContextRef newContext = CGBitmapContextCreate(baseAddress, width, height, 8, bytesPerRow, colorSpace, kCGBitmapByteOrder32Little | kCGImageAlphaPremultipliedFirst);
// <<<<<<<<<< unlock buffer address
CVPixelBufferUnlockBaseAddress(imageBuffer, 0);
// release core graphics object
CGColorSpaceRelease(colorSpace);
// Create a bitmap image from data supplied by the context.
CGImageRef newImage = CGBitmapContextCreateImage(newContext);
// release core graphics object
CGContextRelease(newContext);
BOOL saved = FALSE;
// save CGImage as TIFF file with Objective-C
saved = [[self photoIOController] writeToSubdirectoryWithImageRef:newImage orientation:[self orientation] timeStamp: timeStamp andMetadata: metadata];
// create UIImage (need to change the orientation of the image so that the image is displayed correctly)
UIImage *image= [UIImage imageWithCGImage:newImage scale:1.0 orientation:UIImageOrientationRight];
// release core graphics object
CGImageRelease(newImage);
// set property for display in StillImageViewController
[self setStillImage: image];
// release core foundation object
CFRelease(rawImageBytes);
// release core foundation object
CFRelease(metadata);
// send notification for the camera container view controller when the image has been taken
[[NSNotificationCenter defaultCenter] postNotificationName:kImageCapturedSuccessfully object:nil];
}];
似乎导致异常的方法:
参数:
imageRef 是CGImageRef newImage = CGBitmapContextCreateImage(newContext);
方向是来自UIDeviceOrientation
的{{1}},已过滤减去我未做出反应的
timeStamp 为UIDeviceOrientationDidChangeNotification
元数据为NSDate *timeStamp = [NSDate date];
代码:
CFDictionaryRef metadata = CMCopyDictionaryOfAttachments(kCFAllocatorDefault, imageSampleBuffer, kCMAttachmentMode_ShouldPropagate);
答案 0 :(得分:2)
Core Foundation对象的内存管理与Cocoa中Objective-C对象的内存管理完全一样 - 如果保留它,则必须释放它;如果你没有保留它,你不能释放它。命名约定略有不同。虽然Cocoa中的“保留”方法的名称以alloc
,retain
,new
,copy
和mutableCopy
开头,但在Core Foundation中,如果函数名称包含Create
或Copy
。
因此,考虑到这一点,让我们看看你的代码。
在第一段代码中:
metadata
:从Copy
返回,因此保留,所以必须发布imageBuffer
:从Get
而不是Copy
或Create
的函数返回,因此不会保留,因此不得发布rawImageBytes
:从Create
返回,因此保留,所以必须发布colorSpace
:从Create
返回,因此保留,所以必须发布newContext
:从Create
返回,因此保留,所以必须发布newImage
:从Create
返回,因此保留,所以必须发布在writeToSubdirectoryWithImageRef:
:
imageRef
,orientation
和metadata
:它们是参数,所以很明显你没有保留它,所以你不能发布它mutableMetadata
:从Create
返回,因此保留,因此您必须将其释放myKey
:未保留,因此不得发布myValue
:从Create
返回,因此保留,因此发布url
:它直接桥接(不是桥接保留或桥接传输),方法名称没有任何保留前缀,因此不会保留,因此不得发布destination
:从Create
返回,因此保留,因此发布请参阅?这一切都很简单。