如何卸载 iPhone 图像以释放内存

发布于 2024-11-12 06:01:02 字数 2113 浏览 1 评论 0原文

我有一款 iPhone 游戏,它使用图像来显示内容,例如屏幕上的按钮来控制游戏。这些图像并不大,但我想“延迟”加载它们,并在不使用它们时从内存中卸载它们。

我有一个加载图像的函数,如下所示:

void loadImageRef(NSString *name, GLuint location, CGImageRef *textureImage)
{
    *textureImage = [UIImage imageNamed:name].CGImage;

    if (*textureImage == nil) {
        NSLog(@"Failed to load texture image");
        return;
    }

    NSInteger texWidth = CGImageGetWidth(*textureImage);
    NSInteger texHeight = CGImageGetHeight(*textureImage);

    GLubyte *textureData = (GLubyte *)malloc(texWidth * texHeight * 4);

    CGContextRef textureContext = CGBitmapContextCreate(textureData,
                                                        texWidth, texHeight,
                                                        8, texWidth * 4,
                                                        CGImageGetColorSpace(*textureImage),
                                                        kCGImageAlphaPremultipliedLast);

    CGContextTranslateCTM(textureContext, 0, texHeight);
    CGContextScaleCTM(textureContext, 1.0, -1.0);

    CGContextDrawImage(textureContext, CGRectMake(0.0, 0.0, (float)texWidth, (float)texHeight), *textureImage);
    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);

    glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
    glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
}

我将 CGImageRef 传递给该函数的原因是这样我可以稍后释放它。但我不知道这样做是否正确?

我按如下方式调用该函数(例如):

loadImageRef(@"buttonConfig.png", textures[IMG_CONFIG], &imagesRef[IMG_CONFIG]);

当我完成它时,我按如下方式卸载它:

unloadImage(&imagesRef[IMG_CONFIG]);

它调用该函数:

void unloadImage(CGImageRef *image)
{
    CGImageRelease(*image);
}

但是当我运行该应用程序时,我在卸载或加载时收到 EXC_BAD_ACCESS 错误第二次(即再次需要时)。我没有看到任何其他内容可以帮助确定问题的真正原因。

也许我从错误的角度攻击这个问题。延迟加载图像的常用方法是什么,卸载图像以释放内存的常用方法是什么?

预先非常感谢,

山姆

I have an iPhone game that uses images to display things such as buttons on screen to control the game. The images aren't huge, but I want to load them "lazily" and unload them from memory when they are not being used.

I have a function that loads images as follows:

void loadImageRef(NSString *name, GLuint location, CGImageRef *textureImage)
{
    *textureImage = [UIImage imageNamed:name].CGImage;

    if (*textureImage == nil) {
        NSLog(@"Failed to load texture image");
        return;
    }

    NSInteger texWidth = CGImageGetWidth(*textureImage);
    NSInteger texHeight = CGImageGetHeight(*textureImage);

    GLubyte *textureData = (GLubyte *)malloc(texWidth * texHeight * 4);

    CGContextRef textureContext = CGBitmapContextCreate(textureData,
                                                        texWidth, texHeight,
                                                        8, texWidth * 4,
                                                        CGImageGetColorSpace(*textureImage),
                                                        kCGImageAlphaPremultipliedLast);

    CGContextTranslateCTM(textureContext, 0, texHeight);
    CGContextScaleCTM(textureContext, 1.0, -1.0);

    CGContextDrawImage(textureContext, CGRectMake(0.0, 0.0, (float)texWidth, (float)texHeight), *textureImage);
    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);

    glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
    glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
}

The reason I pass the CGImageRef to the function is so that I can free it later. But I don't know if this is the correct thing to do?

I call the function as follows (for example):

loadImageRef(@"buttonConfig.png", textures[IMG_CONFIG], &imagesRef[IMG_CONFIG]);

And when I'm finished with it I unload it as follows:

unloadImage(&imagesRef[IMG_CONFIG]);

which calls the function:

void unloadImage(CGImageRef *image)
{
    CGImageRelease(*image);
}

But when I run the app, I get EXC_BAD_ACCESS error, either when unloading, or loading for the second time (i.e. when it is needed again). I don't see anything else to help determine the real cause of the problem.

Perhaps I am attacking this issue from the wrong angle. What is the usual method of lazy loading of images, and what is the usual way to unload the image to free up the memory?

Many thanks in advance,

Sam

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

赠我空喜 2024-11-19 06:01:02

如果您想确保内容不会被缓存,您应该不惜一切代价避免使用 [UIImage imageNamed:name] 方法。 imageNamed 缓存它提取的所有图像。您想使用

UIImage *image = [[UIImage alloc] initWithContentsOfFile:[[NSBundle mainBundle] pathForResource:fileNameWithoutExtension ofType:fileNameExtension]];

它,您可以在使用完对象后简单地释放该对象并释放内存。

Apple 已通过 [UIImage imageNamed:] 改进了缓存,但仍不能满足需求。

You should avoid using the [UIImage imageNamed:name] method at all costs if you want to ensure things don't stay cached. imageNamed caches all images it pulls through. You want to use

UIImage *image = [[UIImage alloc] initWithContentsOfFile:[[NSBundle mainBundle] pathForResource:fileNameWithoutExtension ofType:fileNameExtension]];

With that, you can simply release the object when you are done with it and free the memory.

Apple has improved caching with [UIImage imageNamed:] but it still isn't on demand.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文