2014-10-17 4 views
0

Я использую PFQueryTableViewController с Parse в моем приложении IOS 8 Objective-c iPhone.UITableView и parse-laggy

Мой список состоит из ярлыка и UIImageView, где текст и изображение метки загружаются из строки в моем ядре анализа. Я использую этот код для достижения этой цели:

- (PFQuery *)queryForTable 
{ 
    PFQuery *query = [PFQuery queryWithClassName:@"Story"]; 

    return query; 
} 

#pragma mark - Table view data source 

- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView { 
// Return the number of sections. 
return 1; 
} 

- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section { 
// Return the number of rows in the section. 
return [[self objects] count]; 
} 

- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath object:(PFObject *)object 
{ 
static NSString *simpleTableIdentifier = @"cell"; 

UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:simpleTableIdentifier]; 
if (cell == nil) { 
    cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:simpleTableIdentifier]; 
} 

// Download the header image from parse 
PFFile *imageFile = [object objectForKey:@"Image"]; 
[imageFile getDataInBackgroundWithBlock:^(NSData *imageData, NSError *error) { 
    if (!error) { 
     UIImage *cellImage = [UIImage imageWithData:imageData]; 

     // Set the cellImage to the cell if it's not nil 
     if (cellImage == nil) { 
      // nil - do nothing 
      NSLog(@"nil"); 
     } else { 
      NSLog(@"not nil"); 
      // Set the image 
      UIImageView *cellImageView = (UIImageView *)[cell viewWithTag:40]; 
      cellImageView.image = cellImage; 
     } 
    } 
}]; 

// Configure the cell 
UILabel *nameLabel = (UILabel*) [cell viewWithTag:10]; 
nameLabel.text = [object objectForKey:@"Title"]; 
nameLabel.textColor = [UIColor whiteColor]; 

// Make the cell transparent 
cell.backgroundColor = [UIColor clearColor]; 
cell.backgroundView = [UIView new]; 
cell.selectedBackgroundView = [UIView new]; 

// Resize the cell 
[cell sizeToFit]; 

return cell; 
} 

-(void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath { 
// Hide the tabBar and show the readButton 
[self hideTabBar:self.tabBarController]; 

// Segue over to the viewing page 
[self performSegueWithIdentifier:@"detailSegue" sender:self]; 

// Get the tapped cell 
UITableViewCell *cell = [tableView cellForRowAtIndexPath:indexPath]; 

NSString *title = ((UILabel*) [cell viewWithTag:10]).text; 

// Set selectedStory 
MyManager *sharedManager = [MyManager sharedManager]; 
sharedManager.selectedStory = title; 

// Set openedStory to YES as we opened a story 
openedStory = YES; 
} 

Этот код работает хорошо, но прокрутка немного лага, который я думаю, потому что это загрузив изображение, когда показывается клетка. Я думал о создании простого решения, создав массив изображений локально и загружаю их только один раз, но при загрузке приложения он должен загружать 1 раз минимум времени. Мне нужно каким-то образом запустить метод загрузки асинхронно (или другое решение, которое будет работать).

Как я могу это достичь?

(я использую раскадровки)

EDIT

enter image description here

Заранее спасибо! Эрик

EDIT 2:

- (void)tableView:(UITableView *)tableView willDisplayCell:(UITableViewCell *)cell forRowAtIndexPath:(NSIndexPath *)indexPath 
{ 
if (![self.shownIndexes containsObject:indexPath]) { 

    [self.shownIndexes addObject:indexPath]; 
    UIView *weeeeCell = [cell contentView]; 

    weeeeCell.layer.transform = self.initialTransform; 
    weeeeCell.layer.opacity = 0.8; 

    [UIView animateWithDuration:1.25 delay:0.0 usingSpringWithDamping:1.0 initialSpringVelocity:0.5 options:0 animations:^{ 
     weeeeCell.layer.transform = CATransform3DIdentity; 
     weeeeCell.layer.opacity = 1; 
    } completion:^(BOOL finished) {}]; 
} 
} 

и

   if ([[tableView indexPathsForVisibleRows] containsObject:indexPath]) { 
       [tableView reloadRowsAtIndexPaths:@[indexPath] withRowAnimation: UITableViewRowAnimationAutomatic]; 
      } 

ответ

1

Ваша гипотеза о проблеме правильно, и ваша идея о решении прав, тоже. Дополнительное требование, которое вы упомянули о предварительной загрузке изображений, немного нечеткое.

Должен ли быть загружен до появления таблицы? Если они загружаются асинхронно, какими они должны быть, вам необходимо заблокировать доступ пользователя к таблице до тех пор, пока запросы не будут завершены. Вы заменяете плохой опыт, когда не видите изображения сразу с худшим опытом, не видя стола вообще.

Я думаю, что лучшим ответом является просто нагрузка лениво. Контур раствора:

Объявите словарь изображений (будет индексироваться по indexPaths) и обязательно инициализировать его в пустой словарь ...

@interface MyViewController() // replace 'MyViewController' with your class 
@property(strong,nonatomic) NSMutableDictionary *images; 
@end 

Используйте эту коллекцию в cellForRowAtIndexPath. ..

- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath object:(PFObject *)object { 
    static NSString *simpleTableIdentifier = @"cell"; 

    UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:simpleTableIdentifier]; 
    if (cell == nil) { 
     cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:simpleTableIdentifier]; 
    } 

    UIImageView *cellImageView = (UIImageView *)[cell viewWithTag:40]; 
    UIImage *cachedImage = self.images[indexPath]; 
    if (cachedImage) { 
     cellImageView.image = cachedImage; 
    } else { 
     cellImageView.image = // put a place holder image here 

     // load lazily, but read on. the code in the callback should assume 
     // nothing about the state of the table when it runs 

     PFFile *imageFile = [object objectForKey:@"Image"]; 
     [imageFile getDataInBackgroundWithBlock:^(NSData *imageData, NSError *error) { 
      // what if this gets run a second time before the first request finishes? 
      // no worries, check for that here: 
      if (!error && !self.images[indexPath]) { 
       UIImage *cellImage = [UIImage imageWithData:imageData]; 
       self.images[indexPath] = cellImage; 
       // this is important: don't refer to cell in here, it may be 
       // scrolled away and reused by the time this closure runs 
       // the code we just wrote to init the cellImageView works just fine 
       // call that using reload 

       if ([[tableView indexPathsForVisibleRows] containsObject:indexPath]) { 
        [tableView reloadRowsAtIndexPaths:@[indexPath] withRowAnimation:UITableViewRowAnimationAutomatic]; 
       } 
      } 
     }]; 
    } 

    // Configure the cell 
    UILabel *nameLabel = (UILabel*) [cell viewWithTag:10]; 
    nameLabel.text = [object objectForKey:@"Title"]; 
    nameLabel.textColor = [UIColor whiteColor]; 

    // Make the cell transparent 
    cell.backgroundColor = [UIColor clearColor]; 
    cell.backgroundView = [UIView new]; 
    cell.selectedBackgroundView = [UIView new]; 

    // Resize the cell 
    [cell sizeToFit]; 

    return cell; 
} 

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

- (void)prepareToBeShown { 
    NSArray indexPaths = [self.tableView indexPathsForVisibleRows]; 
    [self.tableView reloadRowsAtIndexPaths:indexPaths];  
} 

EDIT 2:

- (void)tableView:(UITableView *)tableView willDisplayCell:(UITableViewCell *)cell forRowAtIndexPath:(NSIndexPath *)indexPath 
{ 
    if (![self.shownIndexes containsObject:indexPath]) { 

     [self.shownIndexes addObject:indexPath]; 
     UIView *weeeeCell = [cell contentView]; 

     weeeeCell.layer.transform = self.initialTransform; 
     weeeeCell.layer.opacity = 0.8; 

     [UIView animateWithDuration:1.25 delay:0.0 usingSpringWithDamping:1.0 initialSpringVelocity:0.5 options:0 animations:^{ 
      weeeeCell.layer.transform = CATransform3DIdentity; 
      weeeeCell.layer.opacity = 1; 
     } completion:^(BOOL finished) {}]; 
    } 
} 
+0

Я думаю, что получаю вашу мысль, но я не совсем понимаю смысл и как реализовать свой код. Не могли бы вы рассказать? – Erik

+0

@ Erik - см. Редактирование. Размещено предложение кода в контексте. Просто вставьте переменную экземпляра и улучшенный cellForRowAtIndexPath в свой контроллер представления. – danh

+0

Отличный ответ - полное, сжатое объяснение –

0

Вы думали об использовании PFImageView вместо UIImageView?

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

+0

Разве это не то, что делает мой код? Я использую метод getDataInBackgroundWithBlock, поэтому, если я использую PFImageView, я должен быть хорошим? – Erik

+0

Вместо этого вы также можете попробовать fetchIfNeededInBackgroundWithBlock. – hybrdthry911

+0

Где? Не могли бы вы уточнить :) – Erik