检索评论数
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];
}];
}
我正在尝试从 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];
}];
}