我使用异步来从xml获取图像。解析器工作正常,我可以输出URL。在异步中我试图将图像缓存到可变字典中。我被困在一个循环中,图像将不再输出。这是我坚持的代码。
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
NSLog(@"Got Here");
static NSString *CellIdentifier = @"NewsCell";
NewsCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
NSLog(@"Got Here 2");
// Configure the cell...
NewsItem *item = [newsItemsArray objectAtIndex:indexPath.row];
cell.newsTitle.text = item.title;
NSLog(@"Got Here 3");
NSMutableDictionary *record = [_records objectAtIndex:[indexPath row]];
if ([record valueForKey:@"actualImage"]) {
NSLog(@"Record Found");
[cell.newsImage setImage:[record valueForKey:@"actualImage"]];
} else {
NSLog(@"Record Not Found");
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT,(unsigned long)NULL), ^(void)
{
NSLog(item.image);
NSData *imageData = [NSData dataWithContentsOfURL:[NSURL URLWithString:item.image]];
dispatch_async(dispatch_get_main_queue(), ^(void){
[record setValue:[UIImage imageWithData:imageData] forKey:@"actualImage"];
[cell.newsImage setImage:[record valueForKey:@"actualImage"]];
if (tableView) {
[tableView reloadRowsAtIndexPaths:[NSArray arrayWithObject:indexPath] withRowAnimation:UITableViewRowAnimationNone];
}
});
});
}
return cell;
}
先谢谢你的帮助。
答案 0 :(得分:0)
您可以尝试以下代码。您还应该研究您的问题,并尝试找到其他现有的答案和解释。这是一个非常频繁的问题,无数次回答SO;)
例如:loading images in table using blocks
代码尝试修复最明显的问题,但无法保证它在所有边缘情况下都能正常工作。您需要调试和测试。
原始代码的主要问题是,它尝试在完成块中设置单元格的newsImage
属性。当执行该操作时,捕获的单元格可能不再与同一行相关联。请记住:细胞将被重复使用!
因此,在完成块中,更改的代码从在块开始时捕获的indexPath重新评估相应的单元格:
NewsCell* cell2 = [tableView cellForRowAtIndexPath:indexPath]; // cell equals nil, if not visible
返回的单元格可能不可见,在这种情况下,表格视图返回nil。
基本上,同样适用于记录变量。只是出于不同的原因:记录变量是一个具有自动范围的变量,即在方法返回时释放。在块中捕获它可能不是一个好主意。
因此,需要在块中重新评估。这基本上是[self.records objectAtIndex:[indexPath row]];
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
static NSString *CellIdentifier = @"NewsCell";
NewsCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
// Configure the cell...
NewsItem *item = [newsItemsArray objectAtIndex:indexPath.row];
cell.newsTitle.text = item.title;
NSMutableDictionary *record = [_records objectAtIndex:[indexPath row]];
if ([record valueForKey:@"actualImage"]) {
NSLog(@"Record Found");
[cell.newsImage setImage:[record valueForKey:@"actualImage"]];
} else {
NSLog(@"Record Not Found");
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT,(unsigned long)NULL), ^(void)
{
NSLog(item.image);
NSData *imageData = [NSData dataWithContentsOfURL:[NSURL URLWithString:item.image]];
dispatch_async(dispatch_get_main_queue(), ^(void){
NSMutableDictionary *record2 = [_records objectAtIndex:[indexPath row]];
[record2 setValue:[UIImage imageWithData:imageData]
forKey:@"actualImage"];
NewsCell* cell2 = [tableView cellForRowAtIndexPath:indexPath]; // cell equals nil, if not visible
if (cell2) {
[cell2.newsImage setImage:[record2 valueForKey:@"actualImage"]];
[tableView reloadRowsAtIndexPaths:[NSArray arrayWithObject:indexPath] withRowAnimation:UITableViewRowAnimationNone];
}
});
});
}
return cell;
}
答案 1 :(得分:0)
创建UITableViewCell
子类。当您需要在其中加载图像时,创建一个NSOperation
子类来执行实际的网络连接。 (有关示例,请参阅http://www.dribin.org/dave/blog/archives/2009/05/05/concurrent_operations/)。或者,使用处理此问题的第三方软件包,其中有数百万个。我目前最喜欢的是MKNetworkKit。存储对您的操作的引用。在单元格的prepareForReuse
中,如果连接尚未完成,请取消连接。如果第一个请求在第二个请求完成后发生,这将阻止您的单元格在滚动时获取错误的图像(更常见的是您会想到)。
答案 2 :(得分:0)
首先替换
[record setValue:[UIImage imageWithData:imageData] forKey:@"actualImage"]; with [record setObject:[UIImage imageWithData:imageData] forKey:@"actualImage"];
并且您的代码应该可以运行。由于字典总是空的,所以总是转到else块。 打印NSMutableDictionary,你会意识到这一点。
这不是缓存完成的方式。它不仅涉及记忆,还涉及编码实践。
请使用像NSCache或SDWebImage
这样的干净方法SDWebImage也负责缓存。 使用NSOperation发出请求而不是GCD。避免嵌套块和关注问题。 以下是干净代码的样子
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath { static NSString *CellIdentifier = @"cell"; NewsCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier forIndexPath:indexPath]; NewsItem *item = [newsItemsArray objectAtIndex:indexPath.row]; cell.newsTitle.text = item.title; // category from library [cell.imageView setImageWithURL:newsItem.imageURL]; if ([item needsRefresh] ) { cell.newsTitle.text = item.title; NewsOperation *operation = [[NewsOperation alloc] initForNewsItem:newItem completion:^(NewsItem *newsItem, NSError *error) { if (newsItem) { [tableView reloadRowsAtIndexPaths:@[indexPath] withRowAnimation:UITableViewRowAnimationNone]; } }]; [[self newsItemQueue] addOperation:operation]; } return cell; }