开发者

How To Load and Unload Images In The Correct Manner

I am having difficulty with images in my iPhone app. I load an image as follows:

UIImage *image = [[UIImage alloc] initWithContentsOfFile:[[NSBundle mainBundle] pathForResource:name ofType:@""]];

CGImageRef imageRef = image.CGImage;
NSInteger texWidth = CGImageGetWidth(*imageRef);
NSInteger texHeight = CGImageGetHeight(*imageRef);
GLubyte *textureData = (GLubyte *)malloc(texWidth * texHeight * 4);
CGContextRef textureContext = CGBitmapContextCreate(textureData, texWidth, texHeight, 8,
                                          texWidth * 4, CGImageGetColorSpace(*imageRef),
                                          kCGImageAlphaPremultipliedLast);


CGContextDrawImage(textureContext, CGRectMake(0.0, 0.0, (float)texWidth,
                                        开发者_JS百科      (float)texHeight), *imageRef);
CGContextRelease(textureContext);

glBindTexture(GL_TEXTURE_2D, location);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, texWidth, texHeight, 0, GL_RGBA,
                                       GL_UNSIGNED_BYTE, textureData);

free(textureData);

and I want to free all the memory that the image has used. I attempt to do that as follows:

CGImageRelease(imageRef);
free(image);

However, the memory does not appear to be freed according to Instruments. Am I missing something? Is it being cached by one of these functions? Furthermore, when I reload the image later, it appears to be loaded twice, i.e. the alpha channel is twice as much as it was the first time. And again, when I (attempt to) free the memory and come to reload it for a third time, the alpha channel is three times what it was the first time. The parts that are supposed to be almost transparent are becoming more and more opaque.

The issue with the transparency was not noticed in iOS 3, only iOS 4. But the issue with the memory not being freed was noticed in both.

Please can someone help me with this? I've spent so much time messing around with images! Also, I don't think I use a stupid amount of images: I am making a game that uses about 40 images, most of which are 128x128 PNGs. How come I run out of memory so quickly?? What is the "common" practice for this scenario? Am I right in trying to free the memory when the image isn't needed?

Replies will be greatly appreciated! Thank you.


The answer to freeing up memory when using OpenGL is simple: http://www.opengl.org/sdk/docs/man/xhtml/glDeleteTextures.xml

Freeing the memory used by UIImage is barely noticeable compared to freeing the texture used by OpenGL. The problem lies in the following code:

GLuint textures[100]; // allows total of 100 textures

location = textures[imageNo];

glBindTexture(GL_TEXTURE_2D, location);

And it is solved by:

void unloadImage(GLuint imageNo)
{
    [textureImages[imageNo] release];
    glDeleteTextures(1, &textures[imageNo]);
}

I really hope this becomes useful to someone else using OpenGL textures on the iPhone, because it's had me going round in circles for ages!

And thanks to @sergio who helped with my issue!


I think that you should do:

[image release];

instead of

CGImageRelease(imageRef);

In fact the object that you are allocating is image, then you get a reference to one of its members; you do not need to release the reference to the member, but to the original object you allocated. You do not need calling free(*image);

EDIT:

All your usage of *image and *imageRef does not seem correct to me; you should use instead image and imageRef:

CGImageRef imageRef = image.CGImage;
NSInteger texWidth = CGImageGetWidth(imageRef);
NSInteger texHeight = CGImageGetHeight(imageRef);
GLubyte *textureData = (GLubyte *)malloc(texWidth * texHeight * 4);
CGContextRef textureContext = CGBitmapContextCreate(textureData, texWidth, texHeight, 8,
                                      texWidth * 4, CGImageGetColorSpace(imageRef),
                                      kCGImageAlphaPremultipliedLast);

CGContextDrawImage(textureContext, CGRectMake(0.0, 0.0, (float)texWidth,
                                          (float)texHeight), imageRef);
CGContextRelease(textureContext);

glBindTexture(GL_TEXTURE_2D, location);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, texWidth, texHeight, 0, GL_RGBA,
                                   GL_UNSIGNED_BYTE, textureData);

free(textureData);

About memory consumption: I think that using the OpenGLES framework might exact a fixed penalty, i.e. increase the overall memory footprint of your app (due to loading the framework and instantiating I don't know which objects); but you should not experience an unexpected memory increase each time that you draw a texture.

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜