Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP

Loading…

Add Example App for RKPaginator #1035

Open
blakewatters opened this Issue · 21 comments
@blakewatters

This component needs an example app. Should include managed and unmanaged.

@blakewatters blakewatters was assigned
@rispie

RKPaginator is back in the RC, an example would be welcome!

@tabuchid

+1 on the example app. Working on getting RKPaginator worked into my app.

@smakman

+1 would like to see an example as well

@praveenr019

+1 for an example.

@smakman

I've got pagination working like this now:

RKObjectManager *objectManager = [RKObjectManager sharedManager];

// Setup some basic mapping
RKObjectMapping *postMapping = [RKObjectMapping mappingForClass:[Post class]];
[postMapping addAttributeMappingsFromDictionary:@{
    @"id": @"id",
    @"content": @"content",
    @"photo": @"photo"
}];

RKResponseDescriptor *postResponseDescriptor = [RKResponseDescriptor 
responseDescriptorWithMapping:postMapping pathPattern:nil keyPath:@"data" 
statusCodes:[NSIndexSet indexSetWithIndex:200]];

[objectManager addResponseDescriptor:postResponseDescriptor];

// Pagination mapping
RKObjectMapping *paginationMapping = [RKObjectMapping mappingForClass:[RKPaginator class]];

[paginationMapping addAttributeMappingsFromDictionary:@{
    @"pagination.per_page": @"perPage",
    @"pagination.total_pages": @"pageCount",
    @"pagination.total_objects": @"objectCount",
}];

[objectManager setPaginationMapping:paginationMapping];

Then in your UITableViewController's viewDidLoad:

// Create weak reference to self to use within the paginators completion block
__weak typeof(self) weakSelf = self;

// Setup paginator
if (!paginator) {

    RKObjectManager *objectManager = [RKObjectManager sharedManager];

    NSString *requestString = [NSString stringWithFormat:@"/posts?page=:currentPage&per_page=:perPage"];

    paginator = [objectManager paginatorWithPathPattern:requestString];
    paginator.perPage = 20; // this will request /posts?page=N&per_page=20

    [paginator setCompletionBlockWithSuccess:^(RKPaginator *paginator, NSArray *objects, NSUInteger page) {

        if (page == 1) {
            [weakSelf.objects removeAllObjects];
        }
        [weakSelf.objects addObjectsFromArray:objects];
        [weakSelf.tableView reloadData];

    } failure:^(RKPaginator *paginator, NSError *error) {
        NSLog(@"Failure: %@", error);
    }];
}

[paginator loadPage:1];
@praveenr019

Works like a Charm.

Thanks Smakman !

@smakman

You're welcome:)

@tabuchid

Also there are examples in the tests.

@blakewatters

I appreciate you jumping in with insight @smakman and @DougTabuchi

@vrao423

@smakman @blakewatters I have a question about your example. Where in a UICollectionView or tableview should I call loadNextPage. I was thinking I should do this in collectionView:cellForItemAtIndexPath:

-(UICollectionViewCell *)collectionView:(UICollectionView *)collectionView cellForItemAtIndexPath:(NSIndexPath *)indexPath {

   UICollectionViewCell *cell = [collectionView dequeueReusableCellWithReuseIdentifier:@"ItemImageCell" forIndexPath:indexPath];

   if([indexPath.row > self.objects count])
        [self.paginator loadNextPage]; 

   //code to setup cell      

}

-(NSInteger)collectionView:(UICollectionView *)collectionView numberOfItemsInSection:(NSInteger)section {

       if (self.paginator.loaded) {
            return [self.paginator objectCount];
       }

      return 0;

 }

But since loadNextPage happens asynchronously, I am not sure how to setup the cell.

@praveenr019

@vrao423 Callback happens through paginator success block which is assigned first time paginator is called.

You might want to due it in scrollViewDidScroll delegate method of collectionView:

#define SCROLL_THRESHOLD_FOR_NEXT_PAGE_LOAD 0.8

- (void)scrollViewDidScroll:(UIScrollView *)scrollView
{
    if (scrollView.contentOffset.y > (SCROLL_THRESHOLD_FOR_NEXT_PAGE_LOAD * scrollView.contentSize.height)) {        
            [paginator loadNextPage];
        }
}
@holysin

Hi, smakman, maybe there is a problem for your code. As we know, when pull and refresh our data, we set the page to 1, and clear the local data. but if we use core data to save our data, when the net request hasn't finished, we tap one cell to look the detail info for the item that cell corresponds, and there is a possible scene that, when detail page load the info and save to core data, our request just finished, and remove all the local data. so this cause crash.

there may be a solution that when pull & refresh the data, we unable the touch event for the tableview, but the user experience will be bad.

Oh, I got that, the best solution should be update the exist ones and insert the non-exist ones, so we have not to forbid the user to jump to the detail page.

@rahulgautam

@smakman @blakewatters How could we use paginator when my rest-api returns meta data like

api: url/?limit=20&offset=1

{
 next: true 
 limit: 20,
 offset: 0,
 prev: false
}

For this structure loadPage don't work for me, as it works on currentPage, could we have a function that use offset and limit and still provide us functionality like nextPaget, prevPage etc.

Simple hint or a demo code would be a great help
Thanks in advance

@richarddwalsh

I have the method implemented however my pagination is passed through the headers how would I map to that?

@blakewatters

@richarddwalsh you can map headers via @metadata mapping. Its covered in the headers and the wiki

@richarddwalsh

But can those values be used in the ObjectMapping for RKPaginator?

-Edit-
Disregard I figured that out, thanks for the tip @blakewatters

@richarddwalsh

Okay spoke too soon, it appears that the page number is not increasing for current Page.

I've implemented the loadNextPage like:

- (void)tableView:(UITableView *)tableView willDisplayCell:(UITableViewCell *)cell forRowAtIndexPath:(NSIndexPath *)indexPath
{
    NSInteger sections = [self.tableView numberOfSections];
    NSInteger rows = [self.tableView numberOfRowsInSection:[indexPath section]];

    if ([indexPath section] == sections - 1 && [indexPath row] == rows - 1) {
        NSLog(@"Last Row");
        [_paginator loadNextPage];
    }
}

I can see the call happening, but the currentPage remains at 1.

update
it seems my mapping with the metadata option is not working,

RKObjectMapping *paginationMapping = [RKObjectMapping mappingForClass:[RKPaginator class]];
    [paginationMapping addAttributeMappingsFromDictionary:@{
                                                            @"@metadata.HTTP.response.headers.pageSize":        @"perPage",
                                                            @"@metadata.HTTP.response.headers.pageCount":     @"pageCount",
                                                            @"@metadata.HTTP.response.headers.objectCount":   @"objectCount",
                                                            }];

    [manager setPaginationMapping:paginationMapping];
@obuseme

@rahulgautam - I have a similar parameters to my paginated API. Did you find a way to bridge what RK provides, and how your API expects parameters?

@rahulgautam

@obuseme I don't find a good way to do that with RKPaginator, but actually I found implementing pagination without it also very easy.

@besi

+1 for an example as well as an examle based on startOffset rather than currentPage

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Something went wrong with that request. Please try again.