問題は、たくさんのタイルを含む scrollView を管理していることです。URL から読み込まれた、または (最初の URL 読み込み後に) バックグラウンドでキャッシュされたファイルから読み込まれた各表示タイル表示画像。目に見えないタイルはリサイクルされます (新しいフレームを設定して再描画します)。
画像の読み込みはタイルの位置に依存します。
長距離スクロールでは、タイルごとに複数の再描画が呼び出されます。各タイルは、正しい画像を表示する前に、異なる画像を数回ロード (および表示) します。
したがって、問題は、新しいタイルを追加する前に、タイルに対して以前に追加されたすべての操作をキャンセルすることです。
接続されている操作を検出するためのコンテキスト オブジェクトを含めるためだけに NSInvocationOperation をサブクラス化し、新しい操作を追加する前に、同じタイルのすべての操作をキャンセルします。
-(void)loadWithColler:(TileView *)coller {
if (queue == nil) {
queue = [NSOperationQueue new];
}
NSInvocationOperationWithContext *loadImageOp = [NSInvocationOperationWithContext alloc];
[loadImageOp initWithTarget:self selector:@selector(loadImage:) object:loadImageOp];
[loadImageOp setContext:coller];
[queue setSuspended:YES];
NSArray *opers = [queue operations];
for (NSInvocationOperationWithContext *nextOperation in opers) {
if ([nextOperation context] == coller) {
[nextOperation cancel];
}
}
[queue addOperation:loadImageOp];
[queue setSuspended:NO];
[loadImageOp release];
}
そして、操作自体で isCancelled をチェックします。
-(void)loadImage:(NSInvocationOperationWithContext *)operation {
if (operation.isCancelled) return;
TileView *coller = [operation context];
/* TRY TO GET FILE FROM CACHE */
if (operation.isCancelled) return;
if (data) {
/* INIT WITH DATA IF LOADED */
} else {
/* LOAD FILE FROM URL AND CACHE IT */
}
if (operation.isCancelled) return;
NSInvocationOperation *setImageOp = [[NSInvocationOperation alloc] initWithTarget:coller selector:@selector(setImage:) object:cachedImage];
[[NSOperationQueue mainQueue] addOperation:setImageOp];
[setImageOp release];
}
しかし、それは何もしません。早期リターンが機能する場合もありますが、タイルは正しい画像の前に多くの画像をロードします。
では、どうすれば成功できるでしょうか?そして、この多くの不要な操作により、スクロール時にメインスレッドで遅延が発生する可能性がありますか? (遅延が存在し、理由がわからないため...すべてバックグラウンドでロードされます..)
アップデート:
NSLog の場合: 実行中に isCancelled: > loadImage メソッドをキャンセル: >
というわけで作業キャンセル。
ここで、最後の操作への参照を TileView オブジェクトに保存し、呼び出された操作が TileView 操作と等しい場合にのみ setImage 操作を実行します。
違いはありません...
次々に呼び出される 1 つのタイルにさまざまな画像をロードする操作が多数あるようです。
他に提案はありますか?
クリアランスの場合:
シングルトン DataLoader があります (それからのすべてのコード)。そして、すべてのタイルは drowRect でそれを呼び出します:
[[DataLoader sharedDataLoader] loadWithColler:self];
アップデート:
NSInvocationOperation サブクラス:
@interface NSInvocationOperationWithContext : NSInvocationOperation {
id context;
}
@property (nonatomic,retain,readwrite) id context;
@end
@implementation NSInvocationOperationWithContext
@synthesize context;
- (void)dealloc
{
[context release];
[super dealloc];
}
@end
助けてくれてありがとう!
解決:
以下の回答から: NSOperation からサブクラス化する必要があります
NSOperation をサブクラス化し、すべての loadImage: コードを「メイン」メソッドに配置すると (すべてのコードをここに移動し、他には何も移動しません)、すべてが完璧に機能します!
スクロールの遅延について:UIImageViewに画像をロードする原因となります((私が理解しているように)解凍とラスタライズのために長い時間がかかります)。
より良い方法は、CATiledLayer を使用することです。バックグラウンドでデータをロードし、はるかに高速に実行します。