UIGraphicsGetImageFromCurrentImageContext() - 内存泄漏 [英] UIGraphicsGetImageFromCurrentImageContext() - Memory Leak

查看:2548
本文介绍了UIGraphicsGetImageFromCurrentImageContext() - 内存泄漏的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在用 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屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆