我试图从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]];
}
}];
有人可以帮帮我吗?谢谢!
答案 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];
}];
}