iOS上CGImage旋转方法存在内存泄漏问题

3

我有这段代码来旋转CGImage:

- (CGImageRef)rotateCGImageRef:(CGImageRef)imageRef toOrientation:(UIImageOrientation)orientation
{
    CGRect             bnds = CGRectZero;
    CGImageRef         copy = nil;
    CGContextRef       ctxt = nil;
    CGRect             rect = CGRectZero;
    CGAffineTransform  tran = CGAffineTransformIdentity;

    @autoreleasepool {
        bnds.size = CGSizeMake(CGImageGetWidth(imageRef), CGImageGetHeight(imageRef)); //self.size;
        rect.size = CGSizeMake(CGImageGetWidth(imageRef), CGImageGetHeight(imageRef)); //self.size;

        switch (orientation)
        {
            case UIImageOrientationUp:
                return imageRef;

            case UIImageOrientationUpMirrored:
                tran = CGAffineTransformMakeTranslation(rect.size.width, 0.0);
                tran = CGAffineTransformScale(tran, -1.0, 1.0);
                break;

            case UIImageOrientationDown:
                tran = CGAffineTransformMakeTranslation(rect.size.width, rect.size.height);
                tran = CGAffineTransformRotate(tran, degreesToRadians(180.0));
                break;

            case UIImageOrientationDownMirrored:
                tran = CGAffineTransformMakeTranslation(0.0, rect.size.height);
                tran = CGAffineTransformScale(tran, 1.0, -1.0);
                break;

            case UIImageOrientationLeft:
                bnds.size = swapWidthAndHeight(bnds.size);
                tran = CGAffineTransformMakeTranslation(0.0, rect.size.width);
                tran = CGAffineTransformRotate(tran, degreesToRadians(-90.0));
                break;

            case UIImageOrientationLeftMirrored:
                bnds.size = swapWidthAndHeight(bnds.size);
                tran = CGAffineTransformMakeTranslation(rect.size.height, rect.size.width);
                tran = CGAffineTransformScale(tran, -1.0, 1.0);
                tran = CGAffineTransformRotate(tran, degreesToRadians(-90.0));
                break;

            case UIImageOrientationRight:
                bnds.size = swapWidthAndHeight(bnds.size);
                tran = CGAffineTransformMakeTranslation(rect.size.height, 0.0);
                tran = CGAffineTransformRotate(tran, degreesToRadians(90.0));
                break;

            case UIImageOrientationRightMirrored:
                bnds.size = swapWidthAndHeight(bnds.size);
                tran = CGAffineTransformMakeScale(-1.0, 1.0);
                tran = CGAffineTransformRotate(tran, degreesToRadians(90.0));
                break;

            default:
                // orientation value supplied is invalid
                assert(false);
                return nil;
        }

        UIGraphicsBeginImageContext(bnds.size);
        ctxt = UIGraphicsGetCurrentContext();

        switch (orientation)
        {
            case UIImageOrientationLeft:
            case UIImageOrientationLeftMirrored:
            case UIImageOrientationRight:
            case UIImageOrientationRightMirrored:
                CGContextScaleCTM(ctxt, -1.0, 1.0);
                CGContextTranslateCTM(ctxt, -rect.size.height, 0.0);
                break;

            default:
                CGContextScaleCTM(ctxt, 1.0, -1.0);
                CGContextTranslateCTM(ctxt, 0.0, -rect.size.height);
                break;
        }

        CGContextConcatCTM(ctxt, tran);
        CGContextDrawImage(ctxt, rect, imageRef);

        //copy = UIGraphicsGetImageFromCurrentImageContext();
        copy = CGBitmapContextCreateImage(ctxt);
        UIGraphicsEndImageContext();
    }
    return copy;
}

但是分析器显示它有泄漏:

memory leak

我无法释放拷贝对象,因为我的方法正在返回它。

到底是什么在泄漏?

编辑: 以下是转换为 C 函数的最终代码:

CGImageRef CreateRotatedImage(CGImageRef imageRef, UIImageOrientation orientation)
{
    CGRect             bnds = CGRectZero;
    CGImageRef         copy = nil;
    CGContextRef       ctxt = nil;
    CGRect             rect = CGRectZero;
    CGAffineTransform  tran = CGAffineTransformIdentity;

    bnds.size = CGSizeMake(CGImageGetWidth(imageRef), CGImageGetHeight(imageRef)); //self.size;
    rect.size = CGSizeMake(CGImageGetWidth(imageRef), CGImageGetHeight(imageRef)); //self.size;

    switch (orientation)
    {
        case UIImageOrientationUp:
            return imageRef;

        case UIImageOrientationUpMirrored:
            tran = CGAffineTransformMakeTranslation(rect.size.width, 0.0);
            tran = CGAffineTransformScale(tran, -1.0, 1.0);
            break;

        case UIImageOrientationDown:
            tran = CGAffineTransformMakeTranslation(rect.size.width, rect.size.height);
            tran = CGAffineTransformRotate(tran, degreesToRadians(180.0));
            break;

        case UIImageOrientationDownMirrored:
            tran = CGAffineTransformMakeTranslation(0.0, rect.size.height);
            tran = CGAffineTransformScale(tran, 1.0, -1.0);
            break;

        case UIImageOrientationLeft:
            bnds.size = swapWidthAndHeight(bnds.size);
            tran = CGAffineTransformMakeTranslation(0.0, rect.size.width);
            tran = CGAffineTransformRotate(tran, degreesToRadians(-90.0));
            break;

        case UIImageOrientationLeftMirrored:
            bnds.size = swapWidthAndHeight(bnds.size);
            tran = CGAffineTransformMakeTranslation(rect.size.height, rect.size.width);
            tran = CGAffineTransformScale(tran, -1.0, 1.0);
            tran = CGAffineTransformRotate(tran, degreesToRadians(-90.0));
            break;

        case UIImageOrientationRight:
            bnds.size = swapWidthAndHeight(bnds.size);
            tran = CGAffineTransformMakeTranslation(rect.size.height, 0.0);
            tran = CGAffineTransformRotate(tran, degreesToRadians(90.0));
            break;

        case UIImageOrientationRightMirrored:
            bnds.size = swapWidthAndHeight(bnds.size);
            tran = CGAffineTransformMakeScale(-1.0, 1.0);
            tran = CGAffineTransformRotate(tran, degreesToRadians(90.0));
            break;

        default:
            // orientation value supplied is invalid
            assert(false);
            return nil;
    }

    UIGraphicsBeginImageContext(bnds.size);
    ctxt = UIGraphicsGetCurrentContext();

    switch (orientation)
    {
        case UIImageOrientationLeft:
        case UIImageOrientationLeftMirrored:
        case UIImageOrientationRight:
        case UIImageOrientationRightMirrored:
            CGContextScaleCTM(ctxt, -1.0, 1.0);
            CGContextTranslateCTM(ctxt, -rect.size.height, 0.0);
            break;

        default:
            CGContextScaleCTM(ctxt, 1.0, -1.0);
            CGContextTranslateCTM(ctxt, 0.0, -rect.size.height);
            break;
    }

    CGContextConcatCTM(ctxt, tran);
    CGContextDrawImage(ctxt, rect, imageRef);

    //copy = UIGraphicsGetImageFromCurrentImageContext();
    copy = CGBitmapContextCreateImage(ctxt);
    UIGraphicsEndImageContext();
    return copy;
}

调用这个C函数:

imageRef = CreateRotatedImage(imageRef, UIImageOrientationRight);
3个回答

2
我认为你的问题是从Obj-C方法返回了一个CGImageRefCGImageRef是C-struct指针的typedef,而不是NSObject,因此它不能自动释放。
我建议考虑两种选择 - 将方法转换为C函数或将返回值放入NSObject(例如UIImage)。
编辑:
CGImageRef CreateRotatedImage(CGImageRef imageRef, UIImageOrientation toOrientation) {
    [... your code ...]
}

呼叫:

CGImageRef rotatedImage = CreateRotatedImage(image, orientation);

第二个选项不好,因为我传入的是CGImage,而且期望得到的也是CGImage,而不是UIImage。至于第一个选项,我不太清楚如何创建C函数以及如何调用它...? - Borut Tomazin
你绝对应该学会它 :) 在你的代码中,你已经调用了 C 函数 20 次。回答已经被编辑过了。 - Sulthan

0

你需要释放你的CGImageRef copyCFType应该知道如何处理releaseautorelease。试试这个:

return (CGImageRef)[(id)copy autorelease];

首先,您需要将其转换为一个Objective-C指针。然后,您可以将其再次转换回CGImageRef。请参考这个答案:https://dev59.com/w1rUa4cB1Zd3GeqPiENt#7061168

您可以在返回的CGImageRef上调用CGImageRelease(imgRef); - fscheidl
如果您可以返回一个 UIImage,那么这将起作用:UIImage *copy = (__bridge_transfer id)CGBitmapContextCreateImage(ctxt); return copy; - fscheidl
不,我需要 CGImage 而不是 UIImage。不过还是谢谢你的建议。 - Borut Tomazin

0
你应该仔细阅读分析器所说的内容:这是一个潜在的泄漏。分析器不会告诉你这是否真的是一个泄漏,要获取这些信息,你需要从工具中运行泄漏检测工具。
分析器正确地警告你返回了一个需要自己释放的值。
在你的接收函数中,只需调用
CGImageRelease(img);

当你完成了CGImageRef的操作。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接