检索评论数

Retrieve number of comments

我正在尝试从 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]];

    }
}];

有人可以帮帮我吗?谢谢!

table 视图单元格需要一个异步接收的事实(计数)。在 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;

有时我会将缓存逻辑添加到网络代码中。如何做到这一点应该是显而易见的,但如果您愿意,我可以演示。

EDIT 希望你能从解决方案的逻辑中看出,当服务器数据发生变化时,客户端的缓存会过时,应该被丢弃。当 this 视图控制器知道更改时,它可以这样做:

// 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];
}

编辑 2 此处描述的延迟加载和缓存方法花费了大量精力来完成异步工作,因为每个 table 单元格都需要显示。为一行初始化缓存后,该行的显示很快,但是 table 在第一次滚动时会感觉有点颠簸。

我们必须在某个地方做计数工作,最好的地方可能是在保存评论后的云端。在那里我们可以获取评论所属的 post,计算它的评论总数,并将该总和保存在 post 上。这样你就可以跳过我上面的整个解决方案,只说类似...

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

但这假设您使用云代码在 Post 上维护评论数 属性。如果没有云代码,我们需要将初始工作转移到客户端的其他地方。它必须在加载 posts(您的 postArray)之后,但在重新加载 table 视图之前发生。在您的代码中找到该位置并调用这样的函数...

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