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对象吗?

另外,是否有一种替代方法来使UIImageViewUIImage

编辑:

以下是所要求的全部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