Утечка памяти методом ротации CGImage на iOS - PullRequest
3 голосов
/ 22 февраля 2012

У меня есть этот код для поворота 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;
}

Но Analyzer говорит, что у него есть утечка: memory leak

Я не могу освободить объект копирования, потому что я его возвращаю.

Что на самом деле подтекает?

EDIT: Вот окончательный код, преобразованный в функцию 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 голосов
/ 22 февраля 2012

Я думаю, что ваша проблема в том, что вы возвращаете CGImageRef из метода Obj-C. CGImageRef - это определение типа для указателя на C-struct, а не NSObject, и поэтому оно не может быть автоматически освобождено.

Я бы рассмотрел два варианта - преобразовать метод в функцию C или поместить возвращаемое значение в NSObject (например, UIImage).

EDIT:

CGImageRef CreateRotatedImage(CGImageRef imageRef, UIImageOrientation toOrientation) {
    [... your code ...]
}

Звоните:

CGImageRef rotatedImage = CreateRotatedImage(image, orientation);
0 голосов
/ 22 февраля 2012

Вы должны прочитать то, что говорит анализатор: это потенциальная утечка.Analyzer не скажет вам, действительно ли это утечка или нет, чтобы получить эту информацию, необходимую для запуска инструмента Leaks из инструментов.

Analyzer правильно предупреждает вас о том, что вы возвращаете значение, которое вам придется выпуститьсебя.

В вашей функции приема просто позвоните

CGImageRelease(img);

После того, как вы закончите с CGImageRef.

0 голосов
/ 22 февраля 2012

Вы должны освободить свой CGImageRef copy. CFType должен знать, как обращаться с release и autorelease. Попробуйте это:

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

Сначала вы должны привести его к указателю Objective-C. Затем вы возвращаете его в CGImageRef. Смотрите этот ответ: https://stackoverflow.com/a/7061168/656036

...