あなたのアルゴリズムはかなり良さそうです。典型的な落とし穴の多くを回避しました。UI パフォーマンスの問題が解決しない場合は、次のことをお勧めします。
画像をメモリにキャッシュしてみてください。NSMutableArray
またはを使用できますNSMutableDictionary
が、iOSアプリで画像をキャッシュする最良の方法は? Caleb はNSCache
、プロセスを簡素化するクラスの利点について説明します。画像をキャッシュする場合は、メモリ不足に対応し、必要に応じてキャッシュを消去してください。didReceiveMemoryWarning
通知センターの に返信したり、オブザーバーとして自分を追加したりできますUIApplicationDidReceiveMemoryWarningNotification
。
キャッシュされた画像がサムネイル サイズであることを確認してください。そうしないと、UI が常に少しカクカクしてしまい (サイズ変更アルゴリズムが必要な場合はお知らせください)、不必要にメモリを使い果たしてしまいます。
画像の更新をメイン キューにディスパッチするときは、非同期で行う必要があります (ブロックがメイン キューに送り返されて終了するのを待つときに、バックグラウンド キューがぶらぶらしてリソースを拘束するのはなぜですか...高速スクロール中にバックアップされた画像がいくつかある場合は特に問題になります); と
cellForRowAtIndexPath
メイン キューにディスパッチするときは、取得元のセルがそうではないことを確認する必要がありますnil
(セルのロード ロジックがバックアップされすぎた場合 (特に低速のデバイスで)、理論的には、問題のセルがスクロールされてオフになる可能性があるためです)。画面とアルゴリズムがクラッシュする可能性があります)。
私はあなたと非常によく似たアルゴリズムを使用しており、GCD 構造はほぼ同じで (上記の注意事項があります)、古いデバイスでも非常にスムーズにスクロールできます。コードを投稿してほしい場合は、喜んで投稿します。
それでも問題が解決しない場合は、CPU プロファイラーがボトルネックを特定し、どこに注意を向けるべきかを知らせるのに非常に役立ちます。Instruments を使用してパフォーマンスのボトルネックを特定する方法に焦点を当てた素晴らしい WWDC セッションがオンラインで利用できます。
これが私のコードです。でviewDidLoad
、イメージ キャッシュを初期化します。
- (void)initializeCache
{
self.imageCache = [[NSCache alloc] init];
self.imageCache.name = @"Custom Image Cache";
self.imageCache.countLimit = 50;
}
そして、私はこれを私の中で使用しますtableView:cellForRowAtIndexPath
:
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
static NSString *CellIdentifier = @"ilvcCell";
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
// set the various cell properties
// now update the cell image
NSString *imagename = [self imageFilename:indexPath]; // the name of the image being retrieved
UIImage *image = [self.imageCache objectForKey:imagename];
if (image)
{
// if we have an cachedImage sitting in memory already, then use it
cell.imageView.image = image;
}
else
{
cell.imageView.image = [UIView imageNamed:@"blank_image.png"];
// the get the image in the background
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
// get the UIImage
UIImage *image = [self getImage:imagename];
// if we found it, then update UI
if (image)
{
dispatch_async(dispatch_get_main_queue(), ^{
// if the cell is visible, then set the image
UITableViewCell *cell = [self.tableView cellForRowAtIndexPath:indexPath];
if (cell)
cell.imageView.image = image;
[self.imageCache setObject:image forKey:imagename];
});
}
});
}
return cell;
}
と
- (void)didReceiveMemoryWarning
{
[super didReceiveMemoryWarning];
[self.imageCache removeAllObjects];
}
余談ですが、別のスレッドにジャストインタイムで画像をロードするのではなく、キャッシュされた画像を別のキューにプリロードすることを検討する可能性のあるさらなる最適化の 1 つです。これは私にとって十分に高速であるように思われるため、必要ではないと思いますが、UI を高速化するためのもう 1 つのオプションです。