【问题标题】:Parse PFFile download order iOS解析PFFile下载顺序iOS
【发布时间】:2023-03-19 13:16:02
【问题描述】:

我将 5 个 PFFile 存储在一个数组中,并使用 getDataInBackgroundWithBlock 从 Parse 下载这些文件。

问题是它们在表格视图单元格中出现的顺序每次都不一样,大概是由于文件大小不同,文件下载速度不同。

for (PFFile *imageFile in self.imageFiles) {
  [imageFile getDataInBackgroundWithBlock:^(NSData *imageData, NSError *error) {
    if (!error) {
      UIImage *avatar = [UIImage imageWithData:imageData];
      [self.avatars addObject:avatar];
      cell.userImageView.image = self.avatars[indexPath.row];
    }
  }];
}

self.imageFiles 数组的顺序正确。 如何确保下载的图片以与self.imageFiles相同的顺序添加到self.avatars数组中?

【问题讨论】:

    标签: ios objective-c iphone parse-platform for-in-loop


    【解决方案1】:

    虽然 danh 的回答已经回答了我的问题,但我确实在发布问题后不久就解决了这个问题。我正在捕获每个 imageFile 的索引,并确保它们按该顺序添加到 self.avatars 数组中。

    for (PFFile *imageFile in self.imageFiles) {
      NSInteger index = [self.imageFiles indexOfObject:imageFile];
      [imageFile getDataInBackgroundWithBlock:^(NSData *imageData, NSError *error) {
        if (!error) {
          UIImage *avatar = [UIImage imageWithData:imageData];
          self.avatars[index] = avatar;
          [self.tableView reloadData];
        }
      }];
    }
    

    然后cell.userImageView.image = self.avatars[indexPath.row]; 进入cellForRowAtIndexPath:

    【讨论】:

      【解决方案2】:

      问题有两部分:(1)明确,如何维护异步操作结果的顺序,(2)使用cell暗示,如何正确处理异步请求以支持tableview。

      第一个问题的答案比较简单:保持请求的结果与请求的参数相关联。

      // change avatars to hold dictionaries associating PFFiles with images
      @property(nonatomic,strong) NSMutableArray *avatars; 
      
      // initialize it like this
      for (PFFile *imageFile in self.imageFiles) {
          [avatars addObject:[@{@"pfFile":imageFile} mutableCopy]];
      }
      
      // now lets factor an avatar fetch into its own method
      - (void)avatarForIndexPath:(NSIndexPath *)indexPath completion:^(UIImage *, NSError *)completion {
      
          // if we fetched already, just return it via the completion block
          UIImage *existingImage = self.avatars[indexPath.row][@"image"];
          if (existingImage) return completion(existingImage, nil);
      
          PFFile *pfFile = self.avatars[indexPath.row][@"pfFile"];
          [pfFile getDataInBackgroundWithBlock:^(NSData *imageData, NSError *error) {
              if (!error) {
                  UIImage *avatar = [UIImage imageWithData:imageData];
                  self.avatars[indexPath.row][@"image"] = avatar;
                  completion(avatar, nil);
              } else {
                  completion(nil, error);
              }
          }];
      }
      

      好的,第 (1) 部分。对于第 2 部分,您的 cellForRowAtIndexPath 代码必须识别单元格被重用。当异步图像提取发生时,您正在处理的单元格可能已经滚动了。通过不引用完成块中的单元格(仅indexPath)来解决此问题。

          // somewhere in cellForRowAtIndexPath
          // we're ready to setup the cell's image view 
      
          UIImage *existingImage = self.avatars[indexPath.row][@"image"];
          if (existingImage) {
              cell.userImageView.image = existingImage;
          } else {
              cell.userImageView.image = // you can put a placeholder image here while we do the fetch
              [self avatarForIndexPath:indexPath completion:^(UIImage *image, NSError *error) {
                  // here's the trick that is often missed, don't refer to the cell, instead:
                  if (!error) {
                      [tableView reloadRowsAtIndexPaths:@[indexPath]];
                  }
              }];
          }
      

      重新加载完成块中的行将导致再次调用cellForRowAtIndexPath,除非在随后的调用中,我们将拥有一个现有的图像并且单元格将立即得到配置。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2023-03-14
        • 1970-01-01
        • 2015-12-29
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多