parsingPFFile下载订单的iOS

我将5个PFFiles存储在数组中,并使用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.avatars相同的顺序添加到self.avatars数组中?

这个问题有两个部分:(1)显式地说,如何保持asynchronous操作的结果顺序,(2)隐含的使用cell ,如何正确处理asynchronous请求以支持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代码必须认识到单元格被重用。 到asynchronous图像获取时,您正在处理的单元格可能已滚动。 通过不引用完成块中的单元格(仅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被再次调用,除了后续的调用,我们将有一个现有的图像,单元格将被立即configuration。

虽然丹答的回答已经回答了我的问题,但在发布问题之后,我确实设法解决了这个问题。 我捕获每个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: