在UITableView中,取消已离开屏幕的单元格的GCD操作的最佳方法是什么? [英] In a UITableView, best method to cancel GCD operations for cells that have gone off screen?

查看:100
本文介绍了在UITableView中,取消已离开屏幕的单元格的GCD操作的最佳方法是什么?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有一个 UITableView ,可以使用GCD将URL中的图像异步加载到单元格中。问题是如果用户轻弹超过150行,150个操作排队并执行。我想要的是将已经过去和离开屏幕的那些出列/取消。

I have a UITableView that loads images from a URL into cells asynchronously using GCD. Problem is if a user flicks past 150 rows, 150 operations queue up and execute. What I want is to dequeue/cancel the ones that blew past and went off screen.

我该怎么做?

我的代码(非常标准):

My code at this point (pretty standard):

- (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是 BOOL ivar我设置为 viewWillDisappear 上,我认为这可以在此<$ c $时快速刷新队列c> UITableView 弹出导航控制器。

runQ is a BOOL ivar I set to NO on viewWillDisappear, which (I think) has the effect of flushing out the queue rapidly when this UITableView pops off the navigation controller.

所以,回到我原来的问题:如何取消单元格的图像获取操作屏幕已关闭?谢谢。

So, back to my original question: how do I cancel the image fetch operations for cells that have gone off screen? Thanks.

推荐答案

首先,滚动时不要排队操作。相反,只为 viewDidLoad 中的可见行加载图像,当用户停止滚动时:

First, don't queue operations while scrolling. Instead, load images for just the visible rows in viewDidLoad and when the user stops scrolling:

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

如果您仍希望能够取消加载不可见的单元格,您可以使用 NSBlockOperation 而不是GCD:

If you still want to be able to cancel loading for invisible cells, you could use NSBlockOperation instead of 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];
}

此处操作是一个 NSMutableDictionary 。如果要取消操作,可以通过单元格的 indexPath 检索它,取消它,并将其从字典中删除:

Here operations is an NSMutableDictionary. When you want to cancel an operation, you retrieve it by the cell's indexPath, cancel it, and remove it from the dictionary:

NSValue *operationHolder = [self.operations objectForKey:indexPath];
NSOperation *operation = [operationHolder nonretainedObjectValue];
[operation cancel];

这篇关于在UITableView中,取消已离开屏幕的单元格的GCD操作的最佳方法是什么?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆