图像创建功能中的内存泄漏

时间:2009-05-21 08:24:23

标签: iphone graphics memory-leaks uiimage

我目前正在开发iPhone游戏,需要动态创建一些动画。动画基于几个图像,由于图像组合的范围太大而无法预先创建所有序列,我希望每次情况发生变化时都能重新计算一组图像。 / p>

该函数创建一系列图像,用作动画序列。我需要帮助两件事:

  1. 我找不到几个大的内存泄漏 - 我需要帮助找到它们
  2. 由于我是iPhone的新手,我想知道是否有更好的方法,如果你有更好的建议如何写,请分享...
  3. 代码:

    (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 个答案:

答案 0 :(得分: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,并且您已正确释放已插入该数组中的其他图像,因此当您替换它们时,它们将被取消分配。

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