2009-05-29 13 views
116

編集:2014年2月:この質問はiOS 2.0からの日付です。それ以来、画像の要求と処理がずっと進んでいます。網膜は画像を大きくし、それらを少し複雑にします。 iPadと網膜の画像のサポートが組み込まれているので、あなたは確かにコードでImageNamedを使うべきです。UIImageの画像を取り除く名前付き:FUD

私は多くの人が人の悪いが同数がパフォーマンスが良いと言っているimageNamedを言って見る - UITableView Sをレンダリングする場合は特に。それが最善の回避されたが、最近のリリースで修正されてい漏れるために使用UIImageimageNamed方法

iPhoneDeveloperTips.comに例えば this SO questionまたは this articleを参照してください。私はキャッシュアルゴリズムを理解して、画像をキャッシュするためのシステムの信頼できる場所と余分な場所へ移動して自分でやる必要がある場所について合理的な判断を下したいと思っています。私の現在の基本的な理解は、ファイル名で参照される NSMutableDictionaryUIImagesであることです。それは大きくなり、メモリが足りなくなるとそれはずっと小さくなります。

たとえば、imageNamedの背後にある画像キャッシュがdidReceiveMemoryWarningに反応しないことを知っている人はいますか? Appleがこれをしないとは思わない。

キャッシングアルゴリズムについての洞察があれば、ここに投稿してください。

+1

私はサスペンス状態です。 :) – Kriem

+2

私も。私が思ったように、SOのような天才のように見えないようです。 –

+0

これについて調査しているようです。 UIImage imageNamedが最新のココアタッチバージョンに悪影響を与えるような実験を行ったことがありますか? UITableViewを作成し、ロット(数千)の行を追加し、すべての行に異なるイメージを表示するとパフォーマンスが低下するかどうかを確認します。おそらく人々はあなたの発見にコメントすることができます。 – stefanB

答えて

86

tldr:ImagedNamedは問題ありません。メモリをうまく処理します。それを使用して、心配しないでください。

2012年11月編集:この質問はiOS 2.0からの日付です。それ以来、画像の要件と処理が大きく前進しています。網膜は画像を大きくし、それらを少し複雑にします。 iPadと網膜画像のサポートが組み込まれているので、コードでImageNamedを使用してください。後世のために:

アップルデベロッパーフォーラムのsister threadは、より良いトラフィックを受け取りました。具体的にはRincewindに権限が追加されました。

メモリ警告の後でも、imageNamed:キャッシュが消去されない問題がiPhone OS 2.xにあります。同時に+ imageNamed:はキャッシュ用ではなく、利便性のために多用されていますが、おそらくこれ以上問題を拡大してしまったでしょう。スピード面では

は、何が起こっているかの一般的な誤解があることを警告しながら

。 + imageNamed:が行う最も大きなことは、ソースファイルから画像データをデコードすることです。これは、ほとんどの場合、データサイズを大幅に膨らませます(たとえば、画面サイズのPNGファイルは圧縮されたときに数十KBを消費しますが、解凍 - 幅*高さ* 4)。対照的に、+ imageWithContentsOfFile:画像データが必要になるたびに、その画像を解凍します。あなたが想像することができるように、画像データが一回だけ必要な場合は、キャッシュされたバージョンの画像がぶら下がり、必要以上に長い可能性があります。しかし、頻繁に再描画する必要がある大きなイメージを持っている場合は、代替案がありますが、主に推奨するのは、大きなイメージを再描画しないようにすることです。

キャッシュの一般的な動作に関しては、ファイル名に基づいてキャッシュを行います(同じ名前の2つの+ imageNamed:は同じキャッシュデータへの参照になります)。 + imageNamed経由でさらに画像をリクエストする: iPhone OS 2.xでは、メモリ警告が受信されたときにキャッシュが縮小するのを防ぐバグがあります。

私の理解では、ということ+ imageNamedです:キャッシュはiPhone OS 3.0上のメモリの警告を尊重すべきです。あなたがチャンスを取ったときにそれをテストし、そうでないとわかったらバグを報告してください。

だから、あなたはそれを持っています。 imageNamed:窓を壊したり子供を殺したりしません。それはかなりシンプルですが、最適化ツールです。

// 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]]; 
} 
:私はそれを修正するためにUIImageにカテゴリを追加しましたので、人々はそれを酷使し、それは単にその仕事

をしたときに怒る - 悲しいことに、それはひどく名前を付けて使用するように簡単です何equivaluentはありません

Rincewindには、独自の最適化バージョンを構築するためのサンプルコードも含まれています。私はそれがmaintentaceの価値があることを見ることができませんが、ここでそれは完全性のためです。

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); 

このコードとトレードオフは、デコードされたイメージがより多くのメモリを使用するがレンダリングが高速であることです。

+0

iOS11では、画像がxcassetカタログから来ている場合、[UIImage imageNamed:]がキャッシュから画像を取り除いていないようです。これはメモリ不足のためクラッシュします。 –

5

私の経験では、imageNamedによって作成されたイメージキャッシュはメモリ警告に応答しません。私は、私がmem管理までそれらを手に入れることができるほどのリーンな2つのアプリケーションを持っていましたが、memの不足のためにまだ説明できないほどクラッシュしていました。 imageNamedの使用を中止して画像をロードすると、両方のアプリケーションが劇的に安定しました。

私は両方のアプリケーションに多少の大きな画像がロードされていることは認めますが、それはまったく普通ではありません。最初のアプリケーションでは、ユーザーが同じイメージに2回戻ってくる可能性はほとんどないため、キャッシングをすべてスキップしました。 2番目には、あなたが言いたことをやっている本当にシンプルなキャッシングクラスを構築しました。つまり、UIImagesをNSMutableDictionaryに入れておき、メモリ警告を受け取ったらその内容をフラッシュします。 imageNamed:そのようなキャッシュがあれば、パフォーマンスの向上は見られませんでした。このすべては2.2で実行されていました。これに3.0の意味があるかどうかはわかりません。

あなたはここで私の最初のアプリから、この問題の周りに私の他の質問を見つけることができます。 StackOverflow question about UIImage cacheing

もう一つのノートは - InterfaceBuilderはカバーの下にimageNamedを使用しています。あなたがこの問題にぶつかったら何かを覚えておいてください。

+0

私はまったく同じ動作を見て、ファイルからの読み込みで直接解決しました。また、11,456 x 3,226 px、15MBという非常に大きな画像を読み込もうとしたときにも発生します。私の理論は、システムがImageNamedのキャッシュ操作によって途中でメモリ不足になることです。そして、この場合には処理が組み込まれていません。 – Dogweather

関連する問題