Вопрос состоит из двух частей: (1) в явном виде, как поддерживать порядок результатов асинхронных операций, (2) подразумевается использованием cell
, как правильно обрабатывать запросы asynch в поддержку табличного представления.
Ответ на первый вопрос проще: сохранить результат запроса, связанного с параметром запроса.
// 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
называться опять же, за исключением того, что на последующий вызов, мы будем иметь существующий образ и клетка получит сконфигурировано немедленно.