Утечки памяти в функции создания изображения - PullRequest
2 голосов
/ 21 мая 2009

Я сейчас работаю над игрой для iPhone, и мне нужно создать анимацию на лету. Анимация основана на нескольких изображениях, а поскольку диапазон комбинаций изображений слишком велик и невозможно предварительно создать все последовательности, я хотел бы иметь возможность пересчитывать набор изображений каждый раз, когда ситуация меняется.

Функция создает серию изображений для использования в качестве анимационной последовательности. Мне нужна помощь с двумя вещами:

  1. Есть несколько больших утечек памяти, которые я не могу найти - мне нужна помощь, чтобы найти их
  2. Так как я новичок в iPhone, я хочу знать, есть ли лучший способ сделать это, если у вас есть лучшее предложение о том, как написать это, пожалуйста, поделитесь ...

Код:

(void) updateImages:(int) smallPicID
{
    CGRect smallPicRect;
    smallPicRect.size = CGSizeMake(25.0f, 25.0f);

    //TODO: add smallPic location for every image. Currently the values only match the first image...
    static const CGPoint smallPicLocation[11][SMALLPIC_LOCATION_COUNT] = 
    {
        { {126.0f, 153.0f},{105.0f, 176.0f}, {115.0f, 205.0f}, {145.0f, 211.0f}, {166.0f, 188.0f}, {156.0f, 159.0f} },
        { {183.0f, 91.0f}, {201.0f, 97.0f}, {205.0f, 115.0f}, {191.0f, 127.0f}, {173.0f, 122.0f}, {169.0f, 124.0f} },
        { {183.0f, 91.0f}, {201.0f, 97.0f}, {205.0f, 115.0f}, {191.0f, 127.0f}, {173.0f, 122.0f}, {169.0f, 124.0f} },
        { {183.0f, 91.0f}, {201.0f, 97.0f}, {205.0f, 115.0f}, {191.0f, 127.0f}, {173.0f, 122.0f}, {169.0f, 124.0f} },
        { {183.0f, 91.0f}, {201.0f, 97.0f}, {205.0f, 115.0f}, {191.0f, 127.0f}, {173.0f, 122.0f}, {169.0f, 124.0f} },
        { {183.0f, 91.0f}, {201.0f, 97.0f}, {205.0f, 115.0f}, {191.0f, 127.0f}, {173.0f, 122.0f}, {169.0f, 124.0f} },
        { {183.0f, 91.0f}, {201.0f, 97.0f}, {205.0f, 115.0f}, {191.0f, 127.0f}, {173.0f, 122.0f}, {169.0f, 124.0f} },
        { {183.0f, 91.0f}, {201.0f, 97.0f}, {205.0f, 115.0f}, {191.0f, 127.0f}, {173.0f, 122.0f}, {169.0f, 124.0f} },
        { {183.0f, 91.0f}, {201.0f, 97.0f}, {205.0f, 115.0f}, {191.0f, 127.0f}, {173.0f, 122.0f}, {169.0f, 124.0f} },
        { {183.0f, 91.0f}, {201.0f, 97.0f}, {205.0f, 115.0f}, {191.0f, 127.0f}, {173.0f, 122.0f}, {169.0f, 124.0f} },
        { {183.0f, 91.0f}, {201.0f, 97.0f}, {205.0f, 115.0f}, {191.0f, 127.0f}, {173.0f, 122.0f}, {169.0f, 124.0f} }
    };

    for(int i = 0; i < self.m_finalImages.count; ++i)
    {
        // start with base image
        UIImage * baseImg = [self.m_finalImagesEmpty objectAtIndex:i];
        CGImageRef baseImgCtx = baseImg.CGImage;

        // Create the bitmap context that matches the baseImg parameters
        CGColorSpaceRef colorSpace = CGColorSpaceCreateDeviceRGB();
        CGContextRef newImgCtx = CGBitmapContextCreate(NULL, 
                                                       CGImageGetWidth(baseImgCtx), 
                                                       CGImageGetHeight(baseImgCtx), 
                                                       8, 0, colorSpace, 
                                                       (kCGBitmapByteOrder32Little | kCGImageAlphaPremultipliedFirst));
        CGColorSpaceRelease(colorSpace); 

        if (newImgCtx == NULL) 
        { 
            // error creating context
            assert(0);
            return;
        }

        // Get empty drum image width, height.
        size_t w = CGImageGetWidth(baseImgCtx);
        size_t h = CGImageGetHeight(baseImgCtx);
        CGRect rect = {{0,0},{w,h}}; 

        // Draw the image to the bitmap context.
        // newImgCtx now contains the full empty drum image.
        CGContextDrawImage(newImgCtx, rect, baseImgCtx); 

        CGContextSaveGState(newImgCtx);
        // translate & scale because of origin difference between UIKit and CG
        CGContextTranslateCTM(newImgCtx, 0, h);
        CGContextScaleCTM(newImgCtx, 1, -1);

        int startLocation = 0;
        int endLocation = SMALLPIC_LOCATION_COUNT;

        // for each location
        for(int j = startLocation; j < endLocation; j++)
        {
            // if its empty, nothing to do, move to next bullet
            if (m_locationStatus[j] == CY_EMPTY)
                continue;

            UIImage * srcImg;
            switch (m_locationStatus[j]) 
            {
                case CY_FULL: srcImg = [self.m_finalImagesLoaded objectAtIndex:i];  break;
                case CY_USED:  srcImg = [self.m_finalImagesSpent objectAtIndex:i];  break;
            }

            // create small image containing only the smallpic from the src img
            smallPicRect.origin = smallPicLocation[i][j];
            CGImageRef smallpicCGImg = CGImageCreateWithImageInRect(srcImg.CGImage, smallPicRect);

            // draw the smallpic into the new context
            CGContextDrawImage(newImgCtx, smallPicRect, smallpicCGImg);         

            CGImageRelease(smallpicCGImg);
        }

        CGContextRestoreGState(newImgCtx);

        // update the image from the context
        UIImage *baseImg = [self.m_finalImages objectAtIndex:i];
        CGImageRef imgref = CGBitmapContextCreateImage(newImgCtx);
        //[baseImg release];
        [baseImg initWithCGImage:imgref];

        CGContextRelease(newImgCtx);
    }
}

1 Ответ

2 голосов
/ 21 мая 2009

Первое, что бросается в глаза, это создание imgref ближе к концу с CGBitmapContextCreateImage (), но без соответствующего CGImageRelease (), и сообщение baseImg initWithCGImage:, которое ничего не делает, только жует память. Я думаю, что вы хотите заменить раздел, начинающийся с «обновить изображение из контекста», на что-то вроде:

CGImageRef imgref = CGBitmapContextCreateImage(newImgCtx);
UIImage *replacmentBaseImg = [[UIImage alloc] initWithCGImage:imgref];
CGImageRelease(imgref);

[self.m_finalImages replaceObjectAtIndex:i withObject:replacementBaseImg];
[replacementBaseImg release];

CGContextRelease(newImgCtx);

Предполагается, что m_finalImages является NSMutableArray, и что вы должным образом высвободили другие изображения, которые были вставлены в этот массив, так что при их замене они будут освобождены.

В более крупной структурной ноте вы можете захотеть взглянуть на то, как нарисовать меньшие субизображения в отдельных слоях CAL, а затем поменять местами эти слои на экране и в разных местах, чтобы выполнить анимацию. Кварцевый рисунок дорог, и CALayers - это кэшированные изображения, хранящиеся в виде текстур на графическом процессоре. Другие люди выполняли эти спрайт-анимации с использованием CALayers и добились впечатляющих результатов.

...