6

UITableViewGCD を使用して URL からセルに画像を非同期的にロードする があります。問題は、ユーザーが 150 行を超えてフリックすると、150 の操作がキューに入れられて実行されることです。私が望むのは、過去に吹き飛ばされて画面から消えたものをデキュー/キャンセルすることです。

どうすればいいですか?

この時点での私のコード(かなり標準):

- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath

    // after getting the cell...

    dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
        if (runQ) {
            NSString *galleryTinyImageUrl = [[self.smapi getImageUrls:imageId imageKey:imageKey] objectForKey:@"TinyURL"];
            NSData *imageData = [[NSData alloc] initWithContentsOfURL:[NSURL URLWithString:galleryTinyImageUrl]];
            dispatch_async(dispatch_get_main_queue(), ^{
                if (imageData != nil) {
                    UITableViewCell *cell = [tableView cellForRowAtIndexPath:indexPath];
                    cell.imageView.image = [UIImage imageWithData:imageData];
                }
            });
        }
    });

runQ は、私がonBOOLに設定した ivar であり、これは (私が思うに)ナビゲーション コントローラーから飛び出したときにキューを急速にフラッシュする効果があります。NOviewWillDisappearUITableView

元の質問に戻りますが、画面から消えたセルの画像取得操作をキャンセルするにはどうすればよいですか? ありがとう。

4

3 に答える 3

7

まず、スクロール中に操作をキューに入れないでください。代わりにviewDidLoad、ユーザーがスクロールを停止したときに、表示されている行のみの画像を読み込みます。

-(void)scrollViewDidEndDecelerating:(UIScrollView *)scrollView {
    for (NSIndexPath *indexPath in [self.tableView indexPathsForVisibleRows]) {
        [self loadImageForCellAtPath:indexPath];
    }
}

それでも非表示セルの読み込みをキャンセルできるようにしたい場合はNSBlockOperation、GCDの代わりに使用できます。

self.operationQueue = [[[NSOperationQueue alloc] init] autorelease];
[self.operationQueue setMaxConcurrentOperationCount:NSOperationQueueDefaultMaxConcurrentOperationCount];

// ...

-(void)loadImageForCellAtPath:(NSIndexPath *)indexPath {
    __block NSBlockOperation *operation = [NSBlockOperation blockOperationWithBlock:^{
        if (![operation isCancelled]) {
            NSString *galleryTinyImageUrl = [[self.smapi getImageUrls:imageId imageKey:imageKey] objectForKey:@"TinyURL"];
            NSData *imageData = [[NSData alloc] initWithContentsOfURL:[NSURL URLWithString:galleryTinyImageUrl]];
            dispatch_async(dispatch_get_main_queue(), ^{
                if (imageData != nil) {
                    UITableViewCell *cell = [tableView cellForRowAtIndexPath:indexPath];
                    cell.imageView.image = [UIImage imageWithData:imageData];
                }
            });
        }
    }];

    NSValue *nonRetainedOperation = [NSValue valueWithNonretainedObjectValue:operation];
    [self.operations addObject:nonRetainedOperation forKey:indexPath];
    [self.operationQueue addOperation:operation];
}

これoperationsNSMutableDictionaryです。操作をキャンセルする場合は、セルで操作を取得してindexPathキャンセルし、辞書から削除します。

NSValue *operationHolder = [self.operations objectForKey:indexPath];
NSOperation *operation = [operationHolder nonretainedObjectValue];
[operation cancel];
于 2012-05-02T17:17:25.350 に答える
0

デキューされたセルを使用している場合、最善の方法は GCD をキャンセルすることです。

-[UITableViewCell prepareForReuse]

于 2012-05-02T06:19:49.550 に答える