Paging PFQueryTableViewController automatically

My goal is to configure pagination using the PFQueryTableViewController . I would be pleased with one of these solutions:

  • 1, Paging a table view automatically. As with objectsPerPage = 10 tableView loads the next 10 objects when the actual row is row 10. etc.

  • 2, paging with "load more cell" UITableViewCell . As I see it, this is a popular solution, so I will also like this option.

Actually, I am not getting errors when trying the second solution, it just just doesn't work. I added a new cell on the Storyboard and created a class for it, and checked AnyPic and other related codes as a starting point. As I can see, I should display the LoadMoreCell cell when the number of rows is less than objects.count . I tried several ways, but nothing works, I still can not display LoadMoreCell .

Here is my attempt:

 - (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath { [tableView deselectRowAtIndexPath:indexPath animated:YES]; if (indexPath.row < self.objects.count) { NSLog(@"THE NUMBER OF ACTUAL ROW %d", indexPath.row); NSLog(@"cell tapped"); } else { // load more [self loadNextPage]; NSLog(@"LOAD NEXT PAGE"); } } - (UITableViewCell *)tableView:(UITableView *)tableView cellForNextPageAtIndexPath:(NSIndexPath *)indexPath { static NSString *LoadMoreCellIdentifier = @"loadmore"; LoadMoreTableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:LoadMoreCellIdentifier]; if (!cell) { cell = [[LoadMoreTableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:LoadMoreCellIdentifier]; cell.selectionStyle = UITableViewCellSelectionStyleGray; cell.loadMoreLabel.text = @"LOAD MORE CELLS"; NSLog(@"NO CELL"); } return cell; } 

Another part of my implementation is the last part of the question code.

My initial question is about my first attempts (paging automatically).

My original question is:

I have a working PFQueryTableViewController , but I can not configure pagination for it. My plan is simple, I want to load the next page when the user scrolls to the bottom of the table. If the table displays 10 elements / pages, I would like to display the next 10 elements when cell 10 appears.

In fact, I detect when the user has reached the bottom of the table, and then calls [self loadNextPage] for new elements, but the application crashes with this error:

Application termination due to the uncaught exception 'NSInternalInconsistencyException', reason: 'attempt to delete line 10 from section 0, which contains only 10 lines before updating'

I really do not understand this problem, because the data source (array) contains more than 40 objects that can be loaded.

Here's how I control the method call (pagination is included in initWithCoder )

 - (void)scrollViewDidScroll:(UIScrollView *)aScrollView { CGPoint offset = aScrollView.contentOffset; CGRect bounds = aScrollView.bounds; CGSize size = aScrollView.contentSize; UIEdgeInsets inset = aScrollView.contentInset; float y = offset.y + bounds.size.height - inset.bottom; float h = size.height; float reload_distance = 10; if(y > h + reload_distance) { NSLog(@"load more rows"); [self loadNextPageInTable]; } } -(void) loadNextPageInTable { [self loadNextPage]; NSLog(@"NEW PAGE LOADED"); } 

And here is the table view setup

 - (id)initWithCoder:(NSCoder *)aDecoder { self = [super initWithCoder:aDecoder]; if (self) { self.parseClassName = @"followClass"; self.pullToRefreshEnabled = YES; self.paginationEnabled = YES; self.objectsPerPage = 10; } return self; } - (PFQuery *)queryForTable { if (![PFUser currentUser]) { return nil; } PFQuery *followQuery = [PFQuery queryWithClassName:@"self.parseClassName"]; [followQuery whereKey:@"followed" equalTo:[PFUser currentUser]]; return query; } -(NSInteger) tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section { return self.objects.count; } - (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath object:(PFObject *)object { static NSString *CellIdentifier = @"followCell"; FeedTableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier]; cell.followLabel.text = object[@"username"]; cell.avatar.file = object[@"image"]; [cell.avatar loadInBackground]; return cell; } 
+6
source share
4 answers

Here is the code that works in my test project. I get the error you get when numberOfRowsInSection not commented out. I see loading more cells, but it automatically loads the rest of the cells so I know if this helps

 #import "ParseDataTableViewController.h" @implementation ParseDataTableViewController - (id)initWithCoder:(NSCoder *)aDecoder { self = [super initWithCoder:aDecoder]; if (self) { // Custom the table // The className to query on //self.parseClassName = @"ParseTest"; // The key of the PFObject to display in the label of the default cell style // The title for this table in the Navigation Controller. self.title = @"Test"; // Whether the built-in pull-to-refresh is enabled self.pullToRefreshEnabled = YES; // Whether the built-in pagination is enabled self.paginationEnabled = YES; // The number of objects to show per page self.objectsPerPage = 15; } return self; } - (IBAction)nextPage:(id)sender { [self loadNextPageInTable]; } - (void)scrollViewDidScroll:(UIScrollView *)aScrollView { CGPoint offset = aScrollView.contentOffset; CGRect bounds = aScrollView.bounds; CGSize size = aScrollView.contentSize; UIEdgeInsets inset = aScrollView.contentInset; float y = offset.y + bounds.size.height - inset.bottom; float h = size.height; float reload_distance = 15; if(y > h + reload_distance) { NSLog(@"load more rows"); [self loadNextPageInTable]; } } -(void) loadNextPageInTable { [self loadNextPage]; NSLog(@"NEW PAGE LOADED"); } - (PFQuery *)queryForTable { NSPredicate *predicate = [NSPredicate predicateWithFormat:@"Name BEGINSWITH 't'"]; PFQuery *followQuery = [PFQuery queryWithClassName:@"ParseTest" predicate:predicate]; return followQuery; } /*-(NSInteger) tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section { return self.objects.count; }*/ - (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath object:(PFObject *)object { static NSString *CellIdentifier = @"DataCell"; UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier]; cell.textLabel.text = object[@"Name"]; return cell; } @end 
+3
source

In creating your cell, you have no way for the tableview to create a new cell if it does not already exist.

Create a new cell if it does not exist from the dequeuing mechanism:

 - (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath object:(PFObject *)object { static NSString *CellIdentifier = @"followCell"; FeedTableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier]; //adds new cell if one does not exist already if (!cell) { cell = [FeedTableViewCell alloc] initWithStyle:UITableViewCellStyleSubtitle reuseIdentifier:CellIdentifier]; //TODO: edit cell details } cell.followLabel.text = object[@"username"]; cell.avatar.file = object[@"image"]; [cell.avatar loadInBackground]; return cell; } 
+1
source

I created a demo application of the first solution. Here you are a demo . I have not used the PFQueryTableViewController ( PFQueryTableViewController only), but I think there will be no problem with this. In this demo, all the data is generated locally and to simulate the load time, I added a timer with an interval of 5 seconds.

Error:

Terminating app due to uncaught exception 'NSInternalInconsistencyException', reason: 'attempt to delete row 10 from section 0 which only contains 10 rows before the update'

means that you are trying to delete an element using indexPath.row = 10, but there is no element at this position. Lines are counted from 0, so the 10th (in this case, the last) element has indexPath.row = 9.

Hope this helps.

0
source

I am not familiar with the PFQueryTableViewController, but here I adapted the working solution from one of my previous projects:

 -(NSInteger) tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section { // totalObjectsCount - you need somehow to get this value, to stop loading next objects after you show all if (self.objects.count < self.totalObjectsCount) { return self.objects.count + 1; } else { return self.objects.count; } } - (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath object:(PFObject *)object { if (self.objects.count < self.totalObjectsCount && indexPath.row == [self tableView:tableView numberOfRowsInSection:indexPath.section] - 1) { LoadMoreCell *cell = [tableView dequeueReusableCellWithIdentifier:@"LoadMoreCell" forIndexPath:indexPath]; return cell; } else { // better if you use [dequeueReusableCellWithIdentifier: forIndexPath:] instead of dequeueReusableCellWithIdentifier FeedTableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:@"FollowCell" forIndexPath:indexPath]; cell.followLabel.text = object[@"username"]; cell.avatar.file = object[@"image"]; [cell.avatar loadInBackground]; return cell; } } - (void)tableView:(UITableView *)tableView willDisplayCell:(UITableViewCell *)cell forRowAtIndexPath:(NSIndexPath *)indexPath { if (self.objects.count < self.totalObjectsCount && indexPath.row == [self tableView:tableView numberOfRowsInSection:indexPath.section] - 1) { // isLoadingMoreData - BOOL value, which indicating, that you already fetching new objects, we don't wanna make same multiple requests if (!self.isLoadingMoreData) { // loadMoreData - function, where you load more objects [self loadMoreData]; } } } 
0
source

Source: https://habr.com/ru/post/978999/


All Articles