消除UIImage图像命名:FUD [英] Dispelling the UIImage imageNamed: FUD

查看:114
本文介绍了消除UIImage图像命名:FUD的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

2014年2月编辑:请注意,此问题可以追溯到iOS 2.0!从那时起,图像要求和处理已经发生了很大变化。 Retina使图像更大,加载它们稍微复杂一些。内置支持iPad和视网膜图像,你当然应该在你的代码中使用ImageNamed

Edit Feb 2014: Note that this question dates from iOS 2.0! Image requirements and handling have moved on a lot since then. Retina makes images bigger and loading them slightly more complex. With the built in support for iPad and retina images, you should certainly use ImageNamed in your code.

我看到很多人说 imageNamed 很糟糕,但同样数量的人说性能很好 - 特别是在渲染 UITableView 时。例如,请参见此SO问题这篇文章关于iPhoneDeveloperTips.com

I see a lot of people saying imageNamed is bad but equal numbers of people saying the performance is good - especially when rendering UITableViews. See this SO question for example or this article on iPhoneDeveloperTips.com

UIImage imageNamed 用于泄漏的方法,因此最好避免使用,但已在最近的版本中修复。我想更好地理解缓存算法,以便做出合理的决定,我可以信任系统来缓存我的图像,以及我需要加倍努力并自己做。我目前的基本理解是,它是由filename引用的 NSMutableDictionary UIImages 。它会变得更大,当内存耗尽时,它会变得更小。

UIImage's imageNamed method used to leak so it was best avoided but has been fixed in recent releases. I'd like to understand the caching algorithm better in order to make a reasoned decision about where I can trust the system to cache my images and where I need to go the extra mile and do it myself. My current basic understanding is that it's a simple NSMutableDictionary of UIImages referenced by filename. It gets bigger and when memory runs out it gets a lot smaller.

例如,是否有人确切知道 imageNamed背后的图像缓存不响应 didReceiveMemoryWarning ? Apple似乎不太可能不这样做。

For example, does anyone know for sure that the image cache behind imageNamed does not respond to didReceiveMemoryWarning? It seems unlikely that Apple would not do this.

如果您对缓存算法有任何了解,请在此处发布。

If you have any insight into the caching algorithm, please post it here.

推荐答案

tldr:ImagedNamed很好。它很好地处理内存。使用它并停止担心。

编辑2012年11月:请注意,这个问题可以追溯到iOS 2.0!从那时起,图像要求和处理已经发生了很大变化。 Retina使图像更大,加载它们稍微复杂一些。内置支持iPad和视网膜图像,您当然应该在代码中使用ImageNamed。现在,为了后人的缘故:

Edit Nov 2012: Note that this question dates from iOS 2.0! Image requirements and handling have moved on a lot since then. Retina makes images bigger and loading them slightly more complex. With the built in support for iPad and retina images, you should certainly use ImageNamed in your code. Now, for posterity's sake:

Apple开发论坛上的姐妹主题收到了一些更好的流量。具体来说, Rincewind 增加了一些权限。

The sister thread on the Apple Dev Forums received some better traffic. Specifically Rincewind added some authority.


iPhone OS 2.x中存在一些问题,即使在发出内存警告之后,imageNamed:cache也不会被清除。同时+ imageNamed:已经得到了很多用于缓存的功能,但为了方便起见,这可能比问题更加放大了问题。

There are issues in iPhone OS 2.x where the imageNamed: cache would not be cleared, even after a memory warning. At the same time +imageNamed: has gotten a lot of use not for the cache, but for the convenience, which has probably magnified the problem more than it should have been.

同时警告


在速度方面,人们普遍误解了发生的事情。 + imageNamed做的最大的事情就是解码来自源文件的图像数据,这几乎总是会大大增加数据大小(例如,屏幕大小的PNG文件在压缩时可能会消耗几十KB,但消耗的半个MB以上)解压缩 - 宽度*高度* 4)。相比之下+ imageWithContentsOfFile:每次需要图像数据时都会解压缩该图像。你可以想象,如果你只需要一次图像数据,那么你在这里什么也没有赢,除了有一个图像的缓存版本,并且可能比你需要的时间更长。但是,如果你有一个需要经常重绘的大图像,那么有其他选择,虽然我建议的主要是避免重绘那个大图像:)。

On the speed front, there is a general misunderstanding of what is going on. The biggest thing that +imageNamed: does is decode the image data from the source file, which almost always significantly inflates the data size (for example, a screen sized PNG file might consume a few dozen KBs when compressed, but consumes over half a MB decompressed - width * height * 4). By contrast +imageWithContentsOfFile: will decompress that image everytime the image data is needed. As you can imagine, if you only need the image data once, you've won nothing here, except to have a cached version of the image hanging around, and likely for longer than you need it. However, if you do have a large image that you need to redraw often, then there are alternatives, although the one I would recommend primarily is to avoid redrawing that large image :).

关于缓存的一般行为,它基于文件名进行缓存(因此+ imageNamed的两个实例:具有相同的名称应该导致对相同缓存数据的引用)并且缓存将根据您的请求动态增长更多图片来自+ imageNamed:。在iPhone OS 2.xa上,当收到内存警告时,bug会阻止缓存缩小。

With respect to the general behavior of the cache, it does cache based on filename (so two instances of +imageNamed: with the same name should result in references to the same cached data) and the cache will grow dynamically as you request more images via +imageNamed:. On iPhone OS 2.x a bug prevents the cache from being shrunk when a memory warning is received.


我的理解是+ imageNamed:cache应该尊重iPhone OS 3.0上的内存警告。如果您发现情况并非如此,请在有机会时进行测试并报告错误。

My understanding is that the +imageNamed: cache should respect memory warnings on iPhone OS 3.0. Test it when you get a chance and report bugs if you find that this is not the case.

那么,你有它。 imageNamed:不会粉碎你的窗户或谋杀你的孩子。它很简单,但它是一个优化工具。遗憾的是,它的命名很糟糕,而且没有相同的东西容易使用 - 因此人们过度使用它并在它完成工作时感到不安

So, there you have it. imageNamed: will not smash your windows or murder your children. It's pretty simple but it is an optimisation tool. Sadly it is badly named and there is no equivaluent that is as easy to use - hence people overuse it and get upset when it simply does its job

我添加了一个类别UIImage修复:

I added a category to UIImage to fix that:

// header omitted
// Before you waste time editing this, please remember that a semi colon at the end of a method definition is valid and a matter of style.
+ (UIImage*)imageFromMainBundleFile:(NSString*)aFileName; {
    NSString* bundlePath = [[NSBundle mainBundle] bundlePath];
    return [UIImage imageWithContentsOfFile:[NSString stringWithFormat:@"%@/%@", bundlePath,aFileName]];
}

Rincewind还包含一些示例代码来构建您自己的优化版本。我看不出这是值得的主要内容,但这是为了完整性。

Rincewind also included some example code to build your own optimised version. I can't see it is worth the maintentace but here it is for completeness.

CGImageRef originalImage = uiImage.CGImage;
CFDataRef imageData = CGDataProviderCopyData(
     CGImageGetDataProvider(originalImage));
CGDataProviderRef imageDataProvider = CGDataProviderCreateWithCFData(imageData);
CFRelease(imageData);
CGImageRef image = CGImageCreate(
     CGImageGetWidth(originalImage),
     CGImageGetHeight(originalImage),
     CGImageGetBitsPerComponent(originalImage),
     CGImageGetBitsPerPixel(originalImage),
     CGImageGetBytesPerRow(originalImage),
     CGImageGetColorSpace(originalImage),
     CGImageGetBitmapInfo(originalImage),
     imageDataProvider,
     CGImageGetDecode(originalImage),
     CGImageGetShouldInterpolate(originalImage),
     CGImageGetRenderingIntent(originalImage));
CGDataProviderRelease(imageDataProvider);
UIImage *decompressedImage = [UIImage imageWithCGImage:image];
CGImageRelease(image);

使用此代码的折衷是解码图像使用更多内存但渲染速度更快。

The trade off with this code is that the decoded image uses more memory but rendering is faster.

这篇关于消除UIImage图像命名:FUD的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆