0

我正在使用异步从 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;
    }

提前感谢您的帮助。

4

3 回答 3

0

创建一个UITableViewCell子类。当您需要在其中加载图像时,请创建一个NSOperation执行实际网络连接的子类。(参见http://www.dribin.org/dave/blog/archives/2009/05/05/concurrent_operations/示例)。或者,使用处理此问题的 3rd 方包,有数百万个。我目前最喜欢的是 MKNetworkKit。存储对您的操作的引用。在单元格中prepareForReuse,如果连接未完成,请取消连接。如果第一个请求在第二个请求之后完成,这将防止您的单元格在滚动时获得错误的图像(发生的频率比您想象的要高)。

于 2013-10-10T18:42:56.553 回答
0

首先更换

[记录setValue:[UIImage imageWithData:imageData] forKey:@"actualImage"];

和

[记录setObject:[UIImage imageWithData:imageData] forKey:@"actualImage"];

你的代码应该可以工作。由于字典总是空的,它总是进入 else 块。打印 NSMutableDictionary 你就会意识到这一点。

这不是缓存的完成方式。这不仅与记忆有关,还与编码实践有关。

请使用干净的方法,如 NSCache 或SDWebImage

SDWebImage 也负责缓存。使用 NSOperation 而不是 GCD 来发出请求。以避免嵌套块和一致性问题。这是干净代码的样子

- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
    静态 NSString *CellIdentifier = @"cell";
    NewsCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier forIndexPath:indexPath];

    NewsItem *item = [newsItemsArray objectAtIndex:indexPath.row];

    cell.newsTitle.text = item.title;
     // 来自库的类别
    [cell.imageView setImageWithURL:newsItem.imageURL];

    if ([item needsRefresh] )
    {
         cell.newsTitle.text = item.title;

        NewsOperation *operation = [[NewsOperation alloc] initForNewsItem:newItem 完成:^(NewsItem *newsItem, NSError *error) {
            如果(新闻项目)
            {
                [tableView reloadRowsAtIndexPaths:@[indexPath] withRowAnimation:UITableViewRowAnimationNone];
            }
        }];
        [[self newsItemQueue] addOperation:operation];
    }

    返回单元格;
}

于 2013-10-10T18:48:01.153 回答
0

你可以试试下面的代码。您还应该研究您的问题并尝试找到其他现有的答案和解释。这是一个非常常见的问题,在 SO 上回答了无数次;)

例如:使用块加载表格中的图像

该代码试图解决最明显的问题,但不能保证它适用于所有边缘情况。您需要调试和测试。

原始代码的主要问题是,它试图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;
}
于 2013-10-10T18:19:28.360 回答