tldr:ImagedNamed 很好。它很好地处理内存。使用它并停止担心。
2012 年 11 月编辑:请注意,这个问题来自 iOS 2.0!从那时起,图像要求和处理发生了很大变化。Retina 使图像更大并且加载它们稍微复杂一些。借助对 iPad 和视网膜图像的内置支持,您当然应该在代码中使用 ImageNamed。现在,为了后代:
Apple Dev Forums 上的姊妹主题获得了更好的流量。具体来说,Rincewind增加了一些权限。
iPhone OS 2.x 中存在一些问题,即使在内存警告之后,也不会清除 imageNamed: 缓存。同时 +imageNamed: 已经得到了很多使用,不是为了缓存,而是为了方便,这可能比它应该的更放大了问题。
同时警告说
在速度方面,人们对正在发生的事情普遍存在误解。+imageNamed: 做的最重要的事情是从源文件中解码图像数据,这几乎总是会显着增加数据大小(例如,屏幕大小的 PNG 文件在压缩时可能会消耗几十 KB,但会消耗超过半 MB解压缩 - 宽度 * 高度 * 4)。相比之下 +imageWithContentsOfFile: 将在每次需要图像数据时解压缩该图像。正如您可以想象的那样,如果您只需要一次图像数据,那么您在这里一无所获,除了拥有图像的缓存版本,并且可能比您需要的时间更长。但是,如果您确实有需要经常重绘的大图像,那么还有其他选择,尽管我主要推荐的是避免重绘该大图像:)。
关于缓存的一般行为,它确实基于文件名进行缓存(因此 +imageNamed: 的两个实例具有相同的名称应该导致对相同缓存数据的引用)并且缓存将随着您通过以下方式请求更多图像而动态增长+图像命名:。在 iPhone OS 2.xa 上,当收到内存警告时,错误会阻止缓存收缩。
和
我的理解是 +imageNamed: 缓存应该尊重 iPhone OS 3.0 上的内存警告。有机会时进行测试,如果发现情况并非如此,请报告错误。
所以你有它。imageNamed:不会砸碎你的窗户或谋杀你的孩子。这很简单,但它是一个优化工具。可悲的是,它的名字很糟糕,并且没有任何等价物可以这么容易使用 - 因此人们过度使用它并且当它只是完成它的工作时会感到不安
我向 UIImage 添加了一个类别来解决这个问题:
// 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 还包含一些示例代码来构建您自己的优化版本。我看不出它值得维护,但这是为了完整性。
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);
使用此代码的权衡是解码后的图像使用更多内存但渲染速度更快。