UIGraphicsGetImageFromCurrentImageContext() – 内存泄漏
我用UIImagePickerControllerSourceTypeCamera
和一个自定义cameraOverlayView
打开相机,这样我就可以在不使用“使用照片”步骤的情况下拍摄多张照片。
这工作得很好,但保存照片function有一个内存泄漏。 通过大量的debugging和研究,我将其缩小到了UIGraphicsGetImageFromCurrentImageContext
函数。
这是一个代码片段,它发生的地方:
UIGraphicsBeginImageContextWithOptions(timestampedImage.frame.size, timestampedImage.opaque, [[UIScreen mainScreen] scale]); [[timestampedImage layer] renderInContext:UIGraphicsGetCurrentContext()]; UIImage *finalTimestampImage = UIGraphicsGetImageFromCurrentImageContext(); UIGraphicsEndImageContext();
我已经search了互联网,似乎UIGraphicsGetImageFromCurrentImageContext()
函数(从这个SO问题引用) “返回一个新的自动释放的UIImage
并指向它的最后finalTimestampImage
伊娃。以前分配的UIImage
是从来没有实际释放,它的variables只是被指派到别的地方。“
我已经尝试了很多显然为别人工作的解决scheme:
-
添加
timestampedImage.layer.contents = nil;
在UIGraphicsEndImageContext
之后 -
添加
CGContextRef context = UIGraphicsGetCurrentContext();
和CGContextRelease(context);
在UIGraphicsEndImageContext
之后 -
用
NSAutoreleasePool
包装上面的代码片段 -
将整个
saveThisPhoto
函数包装在一个NSAutoreleasePool
-
当相机popup并调用
NSAutoreleasePool
时调用[pool release]
时创build一个NSAutoreleasePool
-
当
didReceiveMemoryWarning
被调用时closures相机popup,希望它会清除池 -
以上所有可能的组合
然而,我所尝试的一切,当我拍照时,我可以看到Memory Utilized
上升,而不是在我反复在设备上拍照时不下降。
有谁知道我可以释放由UIGraphicsGetImageFromCurrentImageContext
创build的autorelease对象吗?
另外,是否有一种替代方法来使UIImageView
的UIImage
?
编辑:
以下是所要求的全部function。 有很多额外的释放,只是为了确保一切都被清理。 我已经通过系统地testing了saveThisPhoto
每个代码块的内存泄漏,并且只有在UIGraphicsGetImageFromCurrentImageContext
块(上面的代码片段)运行时才会发生。
- (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]; }
您将variables设置为零,然后释放variables,其中一些已经自动释放。
通常情况下,使用释放时,你应该释放,他们设置为零。
[var release] var = nil;
但在其中一些你不应该被称为释放。
以下是你的主要罪魁祸首。
// clean up the one we won't use any more timestampedImage = nil; [timestampedImage release]; // SAVE NORMAL SIZE IMAGE TO DOCUMENTS FOLDER