解析 PFFile 下载顺序 iOS [英] Parse PFFile download order iOS

查看:48
本文介绍了解析 PFFile 下载顺序 iOS的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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

I'm storing 5 PFFiles in an array and using getDataInBackgroundWithBlock to download those files from Parse.

问题是它们在表格视图单元格中出现的顺序每次都不同,大概是因为文件大小不同导致文件下载速度不同.

The problem is the order at which they appear in the table view cells is different every time, presumably because the files are download at different speeds due to the different file sizes.

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 数组中?

The self.imageFiles array is in the correct order. How do I ensure that the images downloaded are added to the self.avatars array in the same order as the self.imageFiles?

推荐答案

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

The question has two parts: (1) explicitly, how to maintain the order of results of asynchronous operations, (2) implied by the use of cell, how to properly handle asynch requests in support of a tableview.

第一个问题的答案更简单:保留与请求参数相关联的请求结果.

The answer to the first question is simpler: keep the result of the request associated with the parameter for the request.

// 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).

Okay for part (1). For part 2, your cellForRowAtIndexPath code must recognize that cells are reused. By the time the asynch image fetch happens, the cell you're working on might have scrolled away. Fix this by not referring to the cell in the completion block (only the 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 再次被调用,除非在随后的调用中,我们将拥有一个现有图像并且单元格将立即被配置.

Reloading the row in the completion block will cause cellForRowAtIndexPath to be called again, except on that subsequent call, we'll have an existing image and the cell will get configured immediately.

这篇关于解析 PFFile 下载顺序 iOS的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆