2

我目前正在开发一款 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);
    }
}
4

1 回答 1

2

我首先想到的是在末尾附近使用 CGBitmapContextCreateImage() 创建 imgref,但没有匹配的 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 并且您已正确释放已插入该数组中的其他图像,因此当您替换它们时它们会被释放。

在更大的结构上,您可能希望将较小的子图像绘制到单独的 CALayer 中,然后在各个位置将这些层交换进出屏幕以完成动画。Quartz 绘图很昂贵,而 CALayers 是作为纹理存储在 GPU 上的缓存图像。其他人使用 CALayers 执行了这些基于精灵的动画,并取得了令人印象深刻的性能。

于 2009-05-21T13:13:39.867 回答