在UITableView中,取消已离开屏幕的单元格的GCD操作的最佳方法是什么? [英] In a UITableView, best method to cancel GCD operations for cells that have gone off screen?
问题描述
我有一个 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屋!