我有一个iOS应用程序,它有一个带有自定义TableViewCells的UITableView,它包含一个UIImageView。图像是从Web服务加载的,因此在初始加载期间,我显示“加载”图像,然后使用gcd进行调度并获取与该单元格的数据匹配的图像。
当我使用DISPATCH_QUEUE_PRIORITY_HIGH全局队列执行图像提取时,我偶尔会在tableview单元格中加载错误的图像。如果我使用自己的自定义队列,那么正确的图像会填充到单元格中,但是tableview性能很糟糕。
这是代码......
// See if the icon is in the cache
if([self.photoCache objectForKey:[sample valueForKey:@"api_id"]]){
[[cell sampleIcon]setImage:[self.photoCache objectForKey:[sample valueForKey:@"api_id"]]];
}
else {
NSLog(@"Cache miss");
[cell.sampleIcon setImage:nil];
dispatch_queue_t cacheMissQueue = dispatch_queue_create("cacheMissQueue", NULL);
//dispatch_queue_t cacheMissQueue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_HIGH, 0ul);
dispatch_async(cacheMissQueue, ^{
if(sample.thumbnailFilename && sample.api_id){
NSData *thumbNailData = [[NSData alloc] initWithContentsOfFile:sample.thumbnailFilename];
UIImage *thumbNailImage = [[UIImage alloc]initWithData:thumbNailData];
if(thumbNailImage){
// Set the cell
dispatch_sync(dispatch_get_main_queue(), ^{
[[cell sampleIcon]setImage:thumbNailImage];
[cell setNeedsLayout];
});
// save it to cache for future references
NSLog(@"DEBUG: Saving to cache %@ for sample %@",sample.thumbnailFilename,[sample objectID]);
[self.photoCache setObject:thumbNailImage forKey:sample.api_id];
}
}
});
dispatch_release(cacheMissQueue);
}
答案 0 :(得分:1)
观看WWDC 2012会话#211有很大帮助,我将代码从使用GCD更改为NSOperationQueue,它解决了问题。
新代码......
[[self imgQueue]addOperationWithBlock:^{
if(sample.thumbnailFilename && sample.api_id){
NSData *thumbNailData = [[NSData alloc] initWithContentsOfFile:sample.thumbnailFilename];
UIImage *thumbNailImage = [[UIImage alloc]initWithData:thumbNailData];
if(thumbNailImage){
// Set the cell
[[NSOperationQueue mainQueue]addOperationWithBlock:^{
[[cell sampleIcon]setImage:thumbNailImage];
[cell setNeedsLayout];
}];
// save it to cache for future references
[self.photoCache setObject:thumbNailImage forKey:sample.api_id];
}
}
}];
答案 1 :(得分:0)
当您最终获得图像时,您需要在单元格的indexPath和图像之间建立关联。由于这是在一个背景线程,我建议你做的是使用块发布一个nofification到mainQueue,这样和这样的图像可用。仅在主线程上,您向tableView询问可见单元格数组,如果您有图像的单元格正在显示,则可以在此时直接设置图像(您在主线程上,您知道单元格是否有显示,并且它不会改变此runloop迭代。)如果单元格没有显示,没有问题,下次该单元格进入范围时,您将有图像等待它。我现在正在我的应用程序中执行此操作,已经过了好几个月,并且一切正常并且在响应性方面得到了很好的评价(就像你的应用程序将会这样做!)