【发布时间】:2013-11-26 20:40:54
【问题描述】:
我使用UIImagePickerControllerSourceTypeCamera 和自定义cameraOverlayView 打开相机,这样我就可以在没有“使用照片”步骤的情况下拍摄多张照片。
这很好用,但保存照片功能存在内存泄漏。通过大量调试和研究,我将其范围缩小到 UIGraphicsGetImageFromCurrentImageContext 函数。
这是发生的代码的 sn-p:
UIGraphicsBeginImageContextWithOptions(timestampedImage.frame.size, timestampedImage.opaque, [[UIScreen mainScreen] scale]);
[[timestampedImage layer] renderInContext:UIGraphicsGetCurrentContext()];
UIImage *finalTimestampImage = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
我搜索了互联网,似乎UIGraphicsGetImageFromCurrentImageContext() 函数(引用自this SO question)“返回一个新的自动发布的UIImage 并将finalTimestampImage ivar 指向它。之前分配的@987654329 @ 从未真正释放,它的变量只是重新指向其他地方。”
我尝试了很多显然对其他人有效的解决方案:
在
UIGraphicsEndImageContext之后添加timestampedImage.layer.contents = nil;在
UIGraphicsEndImageContext之后添加CGContextRef context = UIGraphicsGetCurrentContext();和CGContextRelease(context);将上述 sn-p 包装在
NSAutoreleasePool将整个
saveThisPhoto函数包装在NSAutoreleasePool中相机弹出时创建
NSAutoreleasePool,调用didReceiveMemoryWarning时调用[pool release]在调用
didReceiveMemoryWarning时关闭摄像头弹出窗口,希望它能清除池以上所有可能的组合
然而我尝试的一切,当我在设备上反复拍照时,我可以看到Memory Utilized上升而不是下降。
有谁知道如何释放UIGraphicsGetImageFromCurrentImageContext 创建的自动释放对象?
或者,是否有另一种方法可以从UIImageView 中创建UIImage?
编辑:
这里是所要求的全部功能。那里添加了很多额外的版本,只是为了确保一切都被清理干净。我已经系统地测试了saveThisPhoto中每个代码块的内存泄漏,它只发生在UIGraphicsGetImageFromCurrentImageContext块(上面的sn-p)运行时。
- (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];
}
【问题讨论】:
-
您是否确认问题不在于使用
finalTimestampImage图像的进一步代码?也许某处有一个保留周期。 -
finalTimestampImage用于得到一个UIImageJPEGRepresentation保存到设备,那么它们都是released。我仍然相信这是另一个 SO 问题中提到的UIGraphicsGetImageFromCurrentImageContext函数创建的偷偷摸摸的UIImage。 -
不,您误解了前面的 SO 问题。 “先前分配的 UIImage”是
_renderImage = [[UIImage alloc] init];中的 UIImage,它在_renderImage = UIGraphicsGetImageFromCurrentImageContext();中泄漏。如果您像在 sn-p 中那样声明变量,它就不会泄漏。也许您可以发布更完整的代码示例。 -
感谢您的浏览,如果您有时间可以浏览,我已经为上面的问题添加了完整的功能。所以你相信,因为我从像
UIImage *finalTimestampImage = UIGraphicsGetImageFromCurrentImageContext();这样的函数中得到了UIImage(与另一个问题中的alloc] init]相反)它不应该泄漏?
标签: ios objective-c memory-leaks