iOS - How to make the tableview use paginated API

2019-01-13 04:04发布

问题:

An API I am writing has about 2000 records, returned in JSON via a simple RESTful API I have written.

To reduce issues with lots of data, I want to use pagination so that I only return say the first 10 or first 20 per request via like an offset or limit or page, etc.

But my question is how does the iOS UITableView know when to get the next page of results?

I really am unsure of how to do this. The user could be scrolling superfast and so the API might not have enough time to retrieve 20 or 50 records at a time.

Another issue related to this is, lets say the user scrolls down on the UITableView, then up and then back down again -- how do you prevent the API from firing multiple times for the same rows?

Thanks

回答1:

Seems to be you aren't thinking in terms of MVC . Your UITableView has very little do with paging and webrequest. It's just concerned about its datasource not pages.

Restuful API Design : Assume your web Request is designed as follow :

/getRecorods?pageSize=20&pageNo=2

This will return you an Array of JSON. In addition to that its helpful to have a count parameter and a link to next page. This helps in parsing and sync with web server.

how do you prevent the API from firing multiple times for the same rows?

A simple flag is sufficient to avoid loading multiple pages. Just make sure that flag is accessed in main thread. The actual webrequest needs to go in background thread.

Below is the code you need to put into your UITableViewController which loads the data


- (void)viewDidLoad
{
    [super viewDidLoad];
    // Do any additional setup after loading the view, typically from a nib.

    //call http Util here to load the data
    httpUtil.delegate = self;

    //This retrieves post for first page always
    currentPageNumber = 1;
    [httpUtil getRecords:currentPageNumber];

}

- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
    // Return the number of rows in the section.
    int retValue = 0;
    if(recordsArray != nil){
        retValue = [recordsArray count];
    }
    return retValue;
}

- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
    static NSString *CellIdentifier = @"Cell";

    CustomCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
    if (cell == nil) {

    }

    // Configure the cell using recordsArray objectAtIndex

    return cell;
}


- (void)scrollViewDidScroll:(UIScrollView *)scrollView{

      if(self.tableView.contentOffset.y >= (self.tableView.contentSize.height - self.tableView.bounds.size.height)) {

      //NSLog(@" scroll to bottom!");
      if(isPageRefresing == NO){ // no need to worry about threads because this is always on main thread.

        isPageRefresing = YES;
        [self showMBProfressHUDOnView:self.view withText:@"Please wait..."];
        currentpagenumber = currentpagenumber +1;
        [httpUtil getRecords:currentpagenumber];
       }
    }

}

// you can get pageNo from tag
// make sure this is called in main thread
-(void)didFinishRecordsRequest:(NSArray *)results forPage:(NSInteger)pageNo{
    if(pageNo == 1){
        recordsArray = [results mutableCopy];
    }
    else{
        [recordsArray addObjectsFromArray:results];
    }
    isPageRefresing = NO;
    [self.tableView reloadData];
}


-(void)didFailedChalkBoardRequestWithError:(NSError *)error{

    //If Since subsequent refresh calls(for page 2 or page 3 fails)
    //then undo the current page number
    currentpagenumber--;
    isPageRefresing = NO;
}

// HTTP Utility class
-(void)getRecords:(NSInteger)pageNumber{

    NSString *serverUrl = [NSString stringWithFormat:@"http://yourwebsite.com/page/%d /?json",pageNumber];

    NSLog(@"fetching Stories data from server WITH URL %@",serverUrl);
    NSURL *url = [NSURL URLWithString:serverUrl];
    storiesRequest = [ASIHTTPRequest requestWithURL:url];
    storiesRequest.tag = pageNumber;
    [storiesRequest setDelegate:self];
    [storiesRequest startAsynchronous];
}



回答2:

For Swift

func scrollViewDidScroll(scrollView: UIScrollView) {
        if collectionViewGif.contentOffset.y >= self.collectionViewGif.contentSize.height - self.collectionViewGif.frame.size.height
        {
            offset = offset + 1
            self.fetchGifWithPaination(defaultText)
        }
    }