当异步调用存在时,从cellForRowAtIndexPath返回单元格

时间:2013-11-17 20:52:39

标签: ios objective-c uitableview

在为视图返回单元格时,我在视图控制器中遇到问题。我正在使用Parse后端来获取文件。那里有2个异步调用。据我所知,此外的代码将首先执行,依赖于结果的代码应该在块中。

简而言之,我的代码如下:我有一个模型对象的模型数组。我使用该对象设置标签和屏幕上的图像。地点图像存储在解析后端中,在我的附件中它是左上角的图像。我试图检索它并在左上角的图像中显示它。

在每个NSLog旁边,我有它正在构建的模型对象的代码,即'Di2zPyCmn8'。这是一个模型对象id。

从我的日志记录中,您可以看到单元格在一切完成之前返回。这是有意义的,因为块是异步的。

任何人都可以提供一些帮助,以便我可以正确构建tableviews吗?

不正常行为是指我在Parse中的后端没有图像作为对象。 tableview单元格图像(左上角)应为空白。有时候,可以在那里找到来自其他后端对象的随机图像。

我认为这与细胞的流动和早期恢复有关。

当我在后端有图像时,该图像按预期显示在地点图像视图(左上角)中。

-(UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{


    static NSString *CellIdentifier = @"Cell";

    BIDActiveDealCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];

    if (cell == nil) {
        cell = [[BIDActiveDealCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifier];
    }

    //get model object from array and use it's properties to populate the fields from CustomCell.h
    if ([self.activeDealModelArray count] == 0) {
        cell.descriptionLabel.text = @"Array count is 0";

    }else{
BIDActiveDealModel *dealActiveModel = [[BIDActiveDealModel alloc]init];
        dealActiveModel = self.activeDealModelArray[indexPath.row];

    NSLog(@"cellforRow - start of else : %@", dealActiveModel.placeObjectId);
    cell.descriptionLabel.text = dealActiveModel.dealTitleModel;//Puts title field. Called description as too lazy to go back and change
    cell.dealPlaceNameLabel.text = dealActiveModel.placeDescription;
    //cell.dealPlaceImageView.image = dealActiveModel.placeImage;
    cell.dealImageView.image = dealActiveModel.dealImageModel;//Sets deal image
    cell.dealDescriptionLabel.text = dealActiveModel.dealDescriptionModel;
    NSLog(@"cellforRow - end of else : %@", dealActiveModel.placeObjectId);

    //Use placeObjectID (foreign key) to get that place from linkedBusinessParseClass. Then get image for that class.
    PFQuery *query = [PFQuery queryWithClassName:@"linkedBusinessParseClass"];
    NSLog(@"cellforRow - after pfQuery : %@", dealActiveModel.placeObjectId);
    [query getObjectInBackgroundWithId:dealActiveModel.placeObjectId block:^(PFObject *placeImageObject, NSError *error) {
        NSLog(@"cellforRow - start geObjectInBackground : %@", dealActiveModel.placeObjectId);
        if (!error) {
            PFFile *imageFile = [placeImageObject objectForKey:@"image"];
            [imageFile getDataInBackgroundWithBlock:^(NSData *data, NSError *error) {
                NSLog(@"cellforRow - start getDataInBackground (Image) : %@", dealActiveModel.placeObjectId);
                if (!error) {
                    UIImage *image = [UIImage imageWithData:data];
                    cell.dealPlaceImageView.image = image;
                }
                NSLog(@"cellforRow - end getDataInBackground (Image) : %@", dealActiveModel.placeObjectId);
            }];
        }
        NSLog(@"cellforRow - end geObjectInBackground : %@", dealActiveModel.placeObjectId);
    }];//end of query
}//end of else that checks array count is 0
NSLog(@"Absolute end - return cell");
return cell;


    Logging:
 cellforRow - start
 of else : Di2zPyCmn8
 cellforRow - end of else : Di2zPyCmn8
 cellforRow - after pfQuery : Di2zPyCmn8
 Absolute end - return cell

enter image description here

1 个答案:

答案 0 :(得分:6)

这是一个常见的错误。当你更努力地找到相关的帖子时,你可以在SO上找到很多关于这个问题。

基本上,您的完成块会捕获单元格对象的引用。但是,当最终执行完成块时,该单元在此期间已被重用。因此,访问它并可能将图像分配给单元格的视图元素是徒劳的(至少),因为单元格不再是单元格,因为块块捕获了单元格。

您应该与块一起捕获的是 indexPath ,然后通过向表视图发送消息{{,然后在块中检索此索引路径的单元格1}}以便在需要时获取正确的单元格

在完成框中:

所以,而不是:

cellForRowAtIndexPath:

使用

cell.dealPlaceImageView.image = image;

注意: 如果单元格BIDActiveDealCell* theCell = (BIDActiveDealCell*)[tableView cellForRowAtIndexPath:indexPath]; theCell.dealPlaceImageView.image = image; 不再可见,表格视图将返回theCell - 并且没有任何不良情况发生(尽管您的代码中还有一些其他问题,但这不会解决它们)。

编辑:可能的改进/问题:

  • 不要在辅助线程上调用消息给UIKit对象 - 仅主线程
  • 当有一个具有相同网址的待处理请求时,请避免启动请求
  • 利用图像缓存(尽管系统会在某种程度上执行此操作)
  • 使用占位符表示最终设置的对象(图像)