Ответ 1
Вещь, которую вы хотите знать при смешивании asynch и таблиц, заключается в том, что асинхронная обработка заканчивается в неизвестное время в будущем, возможно, после прокрутки ячейки, удаления, повторного использования и т.д.
Кроме того, изображение, которое извлекается из Интернета, теряется, если эта ячейка прокручивается. Не уверен, что кеширование AFNetworking для вас, но лучше не предполагать. Здесь решение с использованием родной сети:
// ...
NSDictionary *post = [posts objectAtIndex:indexPath.row];
NSString *postpictureUrl = [post objectForKey:@"picture"];
// find a place in your model, or add one, to cache an actual downloaded image
UIImage *postImage = [post objectForKey:@"picture_image"];
if (postImage) {
cell.imageView.image = postImage; // this is the best scenario: cached image
} else {
// notice how we don't pass the cell - we don't trust its value past this turn of the run loop
[self asynchLoad:postpictureUrl forIndexPath:indexPath];
cell.imageView.image = [UIImage imageNamed:@"default"];
}
// ...
Теперь безвредная асинхронная загрузка без какой-либо сторонней помощи
- (void)asynchLoad:(NSString *)urlString forIndexPath:(NSIndexPath *)indexPath {
NSURL *url = [NSURL urlWithString:urlString];
NSURLRequest *request = [NSURLRequest requestWithURL:url];
[NSURLConnection sendAsynchronousRequest:request queue:[NSOperationQueue mainQueue] completionHandler:^(NSURLResponse *response, NSData *data, NSError *error) {
if (!error) {
// create the image
UIImage *image = [UIImage imageWithData:data];
// cache the image
NSDictionary *post = [posts objectAtIndex:indexPath.row];
[post setObject:image forKey:@"picture_image"];
// important part - we make no assumption about the state of the table at this point
// find out if our original index path is visible, then update it, taking
// advantage of the cached image (and a bonus option row animation)
NSArray *visiblePaths = [self.tableView indexPathsForVisibleRows];
if ([visiblePaths containsObject:indexPath]) {
NSArray *indexPaths = [NSArray arrayWithObject:indexPath];
[self.tableView reloadRowsAtIndexPaths:indexPaths withRowAnimation: UITableViewRowAnimationFade];
// because we cached the image, cellForRow... will see it and run fast
}
}
}];
}
Чтобы это сработало, сообщения должны быть созданы как NSMutableDictionary...
// someplace in your code you add a post to the posts array. do this instead.
NSDictionary *postData = // however you get a new post
[posts addObject:[NSMutableDictionary dictionaryWithDictionary:postData]];
В качестве альтернативы, если трудно изменить модель сообщений напрямую, вы можете настроить другую структуру для кэширования загруженных изображений. Изменчивый словарь с ключевыми строками URL-адреса является хорошей структурой для использования:
@property (nonatomic,strong) NSMutableDictionary *imageCache;
@synthesize imageCache=_imageCache;
// lazy init on the getter...
- (NSMutableDictionary *)imageCache {
if (!_imageCache) {
_imageCache = [NSMutableDictionary dictionary];
}
return _imageCache;
}
Теперь, при настройке ячейки, посмотрите, есть ли кэшированное изображение, проверив кеш...
// change to the cellForRowAtIndexPath method
NSString *postpictureUrl = [post objectForKey:@"picture"];
UIImage *postImage = [self.imageCache valueForKey:postpictureUrl];
И как только изображение загружается, кешируйте его...
// change to the asynchLoad: method I suggested
UIImage *image = [UIImage imageWithData:data];
[self.imageCache setValue:image forKey:urlString];