UIGraphicsGetImageFromCurrentImageContext() - 内存泄漏 [英] UIGraphicsGetImageFromCurrentImageContext() - Memory Leak
问题描述
我正在用 UIImagePickerControllerSourceTypeCamera
和一个自定义 cameraOverlayView
打开相机,这样我可以拍摄多张没有使用的照片照片步骤。
I am opening the camera with UIImagePickerControllerSourceTypeCamera
and a custom cameraOverlayView
so I can take multiple photos without the "Use Photo" step.
这很好用,但保存照片功能有内存泄漏。通过大量的调试和研究,我将其缩小到 UIGraphicsGetImageFromCurrentImageContext
函数。
This is working great, but there is a memory leak in the save photo function. Through a lot of debugging and research I have narrowed it down to the UIGraphicsGetImageFromCurrentImageContext
function.
这是一个片段代码发生的地方:
Here is a snippet of code where it happens:
UIGraphicsBeginImageContextWithOptions(timestampedImage.frame.size, timestampedImage.opaque, [[UIScreen mainScreen] scale]);
[[timestampedImage layer] renderInContext:UIGraphicsGetCurrentContext()];
UIImage *finalTimestampImage = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
我已经搜索过互联网,似乎 UIGraphicsGetImageFromCurrentImageContext()
function(引自这个问题) 返回一个新的自动释放 UIImage
并将 finalTimestampImage
ivar指向它。之前分配的 UIImage
从未实际发布过,其中的变量只是被重新命名为其他地方。
I have scoured the internet and it seems that the UIGraphicsGetImageFromCurrentImageContext()
function (quoted from this SO question) "returns a new autoreleased UIImage
and points the finalTimestampImage
ivar to it. The previously allocated UIImage
is never actually released, the variable to it is just repointed to somewhere else."
我尝试了很多解决方案显然对其他人有效:
I've tried so many solutions that have apparently worked for others:
-
添加
timestampedImage.layer.contents = nil;
在UIGraphicsEndImageContext
添加 CGContextRef context = UIGraphicsGetCurrentContext() ;
和 CGContextRelease(context);
在 UIGraphicsEndImageContext
在 NSAutorele中包装上述代码段asePool
在<$ c $中包装整个 saveThisPhoto
函数c> NSAutoreleasePool
Wrapping the entire saveThisPhoto
function in an NSAutoreleasePool
当相机弹出时创建 NSAutoreleasePool
当 didReceiveMemoryWarning
被调用时调用 [pool release]
Creating an NSAutoreleasePool
when the camera pops up and calling the [pool release]
when didReceiveMemoryWarning
is called
调用 didReceiveMemoryWarning
时关闭相机弹出窗口,希望它将清除池
Closing the camera popup when didReceiveMemoryWarning
is called, hoping it will clear the pool
以上所有可能的组合
然而我尝试的一切,当我拍照时我都能看到内存使用
当我在设备上反复拍照时,上升而不是下降。
Yet everything I try, when I take photos I can see the Memory Utilized
rising and not falling when I'm repeatedly taking photos on the device.
有谁知道如何释放自动释放由 UIGraphicsGetImageFromCurrentImageContext创建的对象
?
Does anyone know how I can release the autorelease object created by UIGraphicsGetImageFromCurrentImageContext
?
或者,是否有另一种方法可以制作 UIImage
out of a $ code> UIImageView ?
Alternatively, is there an alternative way to make a UIImage
out of an UIImageView
?
编辑:
以下是所要求的完整功能。为了确保所有被清理,我们在那里添加了大量的额外发布。我已经完成并且系统地测试了 saveThisPhoto
中每个代码块的内存泄漏,它只发生在 UIGraphicsGetImageFromCurrentImageContext
块(上面的代码段)运行。
Here are the full functions as requested. There's a lot of extra releasing added in there just to try make sure everything is cleaned up. I have gone through and tested for the memory leak with each code block in saveThisPhoto
systematically, and it only occurs when the UIGraphicsGetImageFromCurrentImageContext
block (snippet above) is run.
- (void)imagePickerController:(UIImagePickerController *)picker didFinishPickingMediaWithInfo:(NSDictionary *)info {
NSLog(@"SAVING PHOTO");
[self saveThisPhoto:info];
picker = nil;
[picker release];
info = nil;
[info release];
}
- (void)saveThisPhoto:(NSDictionary *)info {
// Get photo count for filename so we're not overriding photos
int photoCount = 0;
if ([[NSUserDefaults standardUserDefaults] objectForKey:@"photocount"]) {
photoCount= [[[NSUserDefaults standardUserDefaults] objectForKey:@"photocount"] intValue];
photoCount++;
}
[[NSUserDefaults standardUserDefaults] setObject:[NSString stringWithFormat:@"%d", photoCount] forKey:@"photocount"];
[[NSUserDefaults standardUserDefaults] synchronize];
// Obtaining saving path
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSString *documentsDirectory = [paths objectAtIndex:0];
NSString *fileName = [NSString stringWithFormat:@"ri_%d.jpg", photoCount];
NSString *fileNameThumb = [NSString stringWithFormat:@"ri_%d_thumb.jpg", photoCount];
NSString *imagePath = [documentsDirectory stringByAppendingPathComponent:fileName];
NSString *imagePathThumb = [documentsDirectory stringByAppendingPathComponent:fileNameThumb];
// Extracting image from the picker and saving it
NSString *mediaType = [info objectForKey:UIImagePickerControllerMediaType];
// SAVE TO IPAD AND DB
if ([mediaType isEqualToString:@"public.image"]){
// Get Image
UIImage *editedImage = [info objectForKey:UIImagePickerControllerOriginalImage];
// Figure out image orientation
CGSize resizedSize;
CGSize thumbSize;
if (editedImage.size.height > editedImage.size.width) {
resizedSize = CGSizeMake(480, 640);
thumbSize = CGSizeMake(150, 200);
} else {
resizedSize = CGSizeMake(640, 480);
thumbSize = CGSizeMake(150, 113);
}
// MAKE NORMAL SIZE IMAGE
UIImage *editedImageResized = [editedImage resizedImage:resizedSize interpolationQuality:0.8];
// clean up the one we won't use any more
editedImage = nil;
[editedImage release];
// ADD TIMESTAMP TO IMAGE
// make the view
UIImageView *timestampedImage = [[UIImageView alloc] initWithImage:editedImageResized];
CGRect thisRect = CGRectMake(editedImageResized.size.width - 510, editedImageResized.size.height - 30, 500, 20);
// clean up
editedImageResized = nil;
[editedImageResized release];
// make the label
UILabel *timeLabel = [[UILabel alloc] initWithFrame:thisRect];
timeLabel.textAlignment = UITextAlignmentRight;
timeLabel.textColor = [UIColor yellowColor];
timeLabel.backgroundColor = [UIColor clearColor];
timeLabel.font = [UIFont fontWithName:@"Arial Rounded MT Bold" size:(25.0)];
timeLabel.text = [self getTodaysDateDatabaseFormat];
[timestampedImage addSubview:timeLabel];
// clean up what we won't use any more
timeLabel = nil;
[timeLabel release];
// make UIIMage out of the imageview -- MEMORY LEAK LOOKS LIKE IT IS IN THIS BLOCK
NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
UIGraphicsBeginImageContextWithOptions(timestampedImage.frame.size, timestampedImage.opaque, [[UIScreen mainScreen] scale]);
[[timestampedImage layer] renderInContext:UIGraphicsGetCurrentContext()];
UIImage *finalTimestampImage = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
timestampedImage.layer.contents = nil;
CGContextRef context = UIGraphicsGetCurrentContext();
CGContextRelease(context);
// clean up the one we won't use any more
timestampedImage = nil;
[timestampedImage release];
// SAVE NORMAL SIZE IMAGE TO DOCUMENTS FOLDER
NSData *webDataResized = UIImageJPEGRepresentation(finalTimestampImage, 1.0); // JPG
[webDataResized writeToFile:imagePath atomically:YES];
// clean up the one we won't use any more
finalTimestampImage = nil;
[finalTimestampImage release];
[pool release]; // to get rid of the context image that is stored
// SAVE TO DATABASE
[sqlite executeNonQuery:@"INSERT INTO inspection_images (agentid,groupid,inspectionid,areaid,filename,filenamethumb,filepath,orderid,type) VALUES (?, ?, ?, ?, ?, ?, ?, ?,?) ",
[NSNumber numberWithInt:loggedIn],
[NSNumber numberWithInt:loggedInGroup],
myInspectionID,
[[tableData objectAtIndex:alertDoMe] objectForKey:@"areaid"],
fileName,
fileNameThumb,
documentsDirectory,
[NSNumber numberWithInt:photoCount],
[NSNumber numberWithInt:isPCR]
];
// Clean up
webDataResized = nil;
[webDataResized release];
} else {
NSLog(@">>> IMAGE ***NOT*** SAVED");
}
NSLog(@"IMAGE SAVED - COMPLETE");
info = nil;
[info release];
}
推荐答案
你'在释放之前将变量设置为nil,有些已经自动释放。
You're setting your variables to nil before releasing them, and some are already auto released.
通常在使用release时你应该释放它们并将它们设置为nil。
Normally when using release you should release and them set to nil.
[var release]
var = nil;
但在其中一些中你不应该调用release。
But in some of these you should not be calling release.
以下是您的主要罪魁祸首。
The following one is your main culprit.
// clean up the one we won't use any more
timestampedImage = nil;
[timestampedImage release];
// SAVE NORMAL SIZE IMAGE TO DOCUMENTS FOLDER
这篇关于UIGraphicsGetImageFromCurrentImageContext() - 内存泄漏的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!