检索评论数量

时间:2015-09-08 00:15:32

标签: ios parse-platform pfquery

我试图从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 个答案:

答案 0 :(得分:1)

表视图单元格需要异步接收的事实(计数)。在cellForRowAtIndexPath中尝试异步请求是很自然的,但这不是一个好习惯:(a)当用户滚动时会反复触发请求,以及(b)在请求完成时,可以重用需要该事实的单元(可以对应于不同的行)。这是一个更好的模式:

隔离网络代码,只是为了保持理智:

- (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;

有时我会将缓存逻辑添加到网络代码中。怎么做应该是显而易见的,但我可以证明你是否喜欢。

编辑希望您可以从解决方案的逻辑中看出,当服务器数据发生变化时,客户端的缓存会过时,应该被丢弃。当视图控制器知道更改时,它可以执行以下操作:

// 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需要了解它,并且这是一个经常被问及关于SO的不同问题。我鼓励你阅读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];
    }];
}