2015-09-08 4 views
0

Я пытаюсь получить общее количество комментариев от PFQuery. По какой-то причине журнал показывает возвращаемый массив, но метка не изменяется с номером по мере необходимости. Вот код:Получить количество комментариев

- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath 
{ 
static NSString *CellIdentifier = @"FeedCell"; 

FeedCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier]; 
if (cell == nil) { 
    cell = [[FeedCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifier]; 
} 
    PFObject *post = [postArray objectAtIndex:indexPath.row]; 



[cell.captionView setText:[post objectForKey:@"tag"]]; 

cell.captionView.editable = NO; 

cell.captionView.text = [post objectForKey:@"description"]; 




PFFile *theImage = [post objectForKey:@"image"]; 
NSData *imageData = [theImage getData]; 

cell.photoImageView.image = [UIImage imageWithData:imageData]; 

cell.selectionStyle = UITableViewCellSelectionStyleNone; 

cell.captionView.selectable = NO; 


[cell.shareThis setTintColor:[UIColor clearColor]]; 

cell.comments.tag = indexPath.row; 
cell.likeForYa.tag = indexPath.row; 


[cell.likeLabel setText:@""]; 
PFQuery *commentsQuery = [PFQuery queryWithClassName:@"Comment"]; 


[commentsQuery whereKey:@"photo" equalTo:post.objectId]; 

NSLog(@"sement: %@", commentsQuery); 

[commentsQuery countObjectsInBackgroundWithBlock:^(int number, NSError *error) { 
    if (number == 1) { 
     cell.likeLabel.text = @"1 comment"; 
     NSLog(@"comment: %d", number);} 
    else if (number > 0) { 
     [cell.likeLabel setText:[NSString stringWithFormat:@"%d comments", number]]; 
     NSLog(@" plus: %d", number); 

    } 
}]; 

    return cell; 


    } 

Часть кода будет делать запрос в

PFQuery *commentsQuery = [PFQuery queryWithClassName:@"Comment"]; 
[commentsQuery whereKey:@"photo" equalTo:post.objectId]; 

NSLog(@"sement: %@", commentsQuery); 

[commentsQuery countObjectsInBackgroundWithBlock:^(int number, NSError *error) { 
    if (number == 1) { 
     cell.likeLabel.text = @"1 comment"; 
     NSLog(@"comment: %a", number);} 
    else if (number > 0) { 
     [cell.likeLabel setText:[NSString stringWithFormat:@"%d comments", number]]; 

    } 
}]; 

Может кто-то пожалуйста, помогите мне? Спасибо!

ответ

1

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

Изолировать код сети, чтобы оставаться в здравом уме:

- (void)commentCountForPost:(PFObject *)post withCompletion:(void (^)(NSNumber *))completion { 
    PFQuery *commentsQuery = [PFQuery queryWithClassName:@"Comment"]; 
    [commentsQuery whereKey:@"photo" equalTo:post]; 

    NSLog(@"sement: %@", commentsQuery); 

    [commentsQuery findObjectsInBackgroundWithBlock:^(NSArray *array, NSError *error) { 
     completion(@(array.count)); // wrap as an NSNumber 
    }]; 
} 

Кэш результатов, так что мы просим до один раз для каждой строки:

// keys will be indexPaths, values will be comment counts 
@property(nonatomic,strong) NSMutableDictionary *commentCounts; 

// be sure to initialize early to 
self.commentCounts = [@{} mutableCopy]; 

сейчас в cellForRowAtIndexPath, вспомните пару важных вещей: (a) проверьте кеш для уже полученного значения, (b) не сохраняйте ячейку в блоке завершения, она может ссылаться на неправильную строку к тому времени, когда выполняется блок. Вместо этого перезагрузите строку, зная, что кэшировать значение будет там:

// ... 
PFObject *post = postArray[indexPath.row]; 
// ... 
[cell.likeLabel setText:@""]; 
NSNumber *commentCount = self.commentCounts[indexPath]; 
if (commentCount) { 
    self.likeLabel.text = [NSString stringWithFormat:@"%@ comments", commentCount]; 
} else { 
    [self commentCountForPost:post withCompletion:^(NSNumber *count) { 
     self.commentCounts[indexPath] = count; // cache the result 
     [tableView reloadRowsAtIndexPaths:@[indexPath] withRowAnimation:UITableViewRowAnimationNone]; 
    }]; 
} 
return cell; 

Иногда я добавить логику кэша сетевого кода. Как это сделать должно быть очевидным, но я могу продемонстрировать, хотите ли вы.

EDIT Надеюсь, из логики решения видно, что при изменении данных сервера кеш клиента устарел и должен быть отброшен. Когда этого вид контроллер знает об изменении, он может сделать это:

// imagine we know the comment count changed at a specific indexPath 
[self.commentCounts removeObjectAtIndex:indexPath.row]; 
[self.tableView reloadRowsAtIndexPaths:@[indexPath]]; 

// or, imagine we know that the comment count changed someplace, or in more than one places. call this... 
- (void)emptyCacheAndReloadData { 
    [self.commentCounts removeAllObjects]; 
    [self.tableView reloadData]; 
} 

Но если другого вид контроллер делает изменения, это VC необходимо узнать об этом, и это другая проблема рода часто спрашивали о СО. Я бы посоветовал вам прочитать answer given here, который является правильным и достаточно полным. Если вы впервые решаете эту тему, вы можете - по понятным причинам - сначала попробовать небольшую комбинацию. Это было бы это (соответствие вашей интуиция о viewWillAppear):

- (void)viewWillAppear:(BOOL)animated { 
    [super viewWillAppear:animated]; 
    [self emptyCacheAndReloadData]; 
} 

EDIT 2 подход ленивых нагрузки и кэша, описанный здесь затрачивает усилия, чтобы сделать асинхронную работу, поскольку каждая ячейка таблицы нуждается дисплей. Как только кеш инициализируется для строки, отображение этой строки происходит быстро, но таблица будет немного ухабистой при первом прокрутке.

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

self.likeLabel.text = [NSString stringWithFormat:@"%@ comments", post[@"commentCount"]]; 

Но это предполагает, что вы сохраняете свойство счетчика комментариев в Post с помощью облачного кода. Без облачного кода нам нужно переместить начальную работу где-нибудь еще на клиенте. Это должно произойти после загрузки сообщений (ваш postArray), но перед перезагрузкой таблицы. Найдите это место в своем коде и вызовите такую ​​функцию ...

- (void)postsLoaded { 
    // build an array of indexPaths in your table. this is just a row for each post 
    NSMutableArray *indexPaths = [@[] mutableCopy]; 
    for (int i=0; i<self.postArray.count; i++) { 
     NSIndexPath *indexPath = [NSIndexPath indexPathForRow:i inSection:0]; 
     [indexPaths addObject:indexPath]; 
    } 
    // now preload the counts 
    [self preloadCountsForIndexPaths:indexPaths completion:^(BOOL success) { 
     [self.tableView reloadData]; 
    }]; 
} 

// this is a recursive method. to count comments on array of posts 
// count them on the first post, then count comments on the rest 
- (void)preloadCountsForIndexPaths:(NSArray *)indexPaths completion:(void (^)(BOOL))completion { 
    if (indexPaths.count == 0) return completion(YES); 
    NSIndexPath *indexPath = indexPaths[0]; 
    NSArray *remainingIndexPaths = [indexPaths subarrayWithRange:NSMakeRange(1, indexPaths.count-1)]; 
    PFObject *post = self.postArray[indexPath.row]; 
    [self commentCountForPost:post withCompletion:^(NSNumber *count) { 
     self.commentCounts[indexPath] = count; // cache the result 
     [self preloadCountsForIndexPaths:remainingIndexPaths completion:completion]; 
    }]; 
} 
+0

Спасибо, что нашли время, чтобы объяснить это! post.objectid находится внутри таблицы, как мне ее вызывать за пределами цикла? :) PFObject * post = [postArray objectAtIndex: indexPath.row]; это то, что сейчас, под номеромOfRowsInSection! – HalesEnchanted

+0

А я не заметил, что запрос был квалифицирован. См. Править. Просто добавлен параметр post в логику запроса. – danh

+0

Спасибо за прилипание! [tableView reloadRowsAtIndexPaths: @ [indexPath]]; возвращает ошибку, поскольку она говорит, что она не объявлена? – HalesEnchanted