解析PFFile下载命令iOS

时间:2015-04-25 16:34:56

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

我将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.imageFiles数组中?

2 个答案:

答案 0 :(得分:1)

这个问题有两个部分:(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再次被调用,除了在后续调用中,我们将有一个现有图像,并且将立即配置该单元格。

答案 1 :(得分:1)

虽然danh的回答已经回答了我的问题,但我确实设法在发布问题后立即解决了这个问题。我正在捕获每个imageFile的索引,并确保它们按顺序添加到std::vector数组中。

template<typename T> using Vec = std::vector<T>;    
Vec<Vec<Vec<float>>> arr3d(a,Vec<Vec<float>>(b,Vec<float>(c,0)));

然后在DELIMITER $$ CREATE TRIGGER `mydb`.`table0` AFTER INSERT ON `mydb`.`table0` FOR EACH ROW BEGIN IF ( SELECT table1.idtable1 FROM table2, table1, `table` WHERE table1.idtable1=table2.idtable2 and table0.idtable0=table1.idtable1 ) THEN UPDATE targettable SET targettable.column = 1 WHERE targettable.idtable=table1.idtable1; END IF; END;$$ delimiter ;

self.avatars