2015-04-25 3 views
2

Я храню 5 PFFiles в массиве и используя getDataInBackgroundWithBlock, чтобы загрузить эти файлы из Parse.Parse PFFile скачать заказ iOS

Проблема заключается в том, что порядок, в котором они отображаются в ячейках просмотра таблицы, различен каждый раз, по-видимому, потому, что файлы загружаются с различной скоростью из-за разных размеров файлов.

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?

ответ

1

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

1

В то время как ответ дань ответил на мой вопрос, мне удалось решить его вскоре после публикации вопроса. Я записываю индекс каждого файла 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:

Смежные вопросы