Pagination Helpers

This tutorial is about the new Pagination Helpers available in Cortex 1.8.6+.

When working with lists, it is often important to page through results. The recommended approaches to working with lists through the API are outlined here.

However, the Cortex iOS SDK makes this quite simple with pagination helpers.

The following examples illustrate how to paginate through a list of c_prescription instances.

For information on how to create custom cortex objects such as the example c_prescription object, see Data Model Setup.

For more information on working with your Cortex Objects in iOS, see Cortex Objects.

1. Using the Pagination Helper

This is how an instance of MDPaginationHelper is created and initialized:

MDPaginationHelper *prescriptions = [MDPaginationHelper
                                     paginatorWithContext:@"c_prescriptions"
                                     pageSize:10
                                     cacheResults:NO
                                     inverseOrder:NO];

// Optionally, custom API parameters (query parameters) can be specified; and the paginator will include those in the queries as well.
prescriptions.customParameters = [MDAPIParameterFactory parametersWithWhere:@{ @"c_refills": { @"$gt": 5 } } prefixPath:nil];

// set your class as the paginator's delegate if you use the delegate approach (see explanation below):
prescriptions.delegate = self;

// set the paginator's results callback block, if you use the callback block approach (see explanation below):
prescriptions.resultsCallback = ^(NSArray<MDObjectInstance *> * _Nullable objects, NSNumber * _Nullable hasMore, MDFault * _Nullable fault)
    {
        if (fault)
        {
            // fault handling
        }
        else
        {
            // "objects" will be instances of the Prescription class.
            
            // Use hasMore.boolValue to know if there are more pages to load
        }
    };

// And then you can call either `loadNextPage` or `loadAllPages` on the paginator, depending on what you need:
[prescriptions loadNextPage];

// or
[prescriptions loadAllPages];

// ----
// Note: make sure to store the instance somewhere, otherwise it will be destroyed by ARC.
let prescriptions: MDPaginationHelper! = MDPaginationHelper.paginator(withContext: "c_prescriptions",
                                                                      pageSize: 10,
                                                                      cacheResults: false,
                                                                      inverseOrder: false)

// Optionally, custom API parameters (query parameters) can be specified; and the paginator will include those in the queries as well.
prescriptions.customParameters = MDAPIParameterFactory.parameters(withWhere: [ "c_refills": [ "$gt": 5 ] ], prefixPath: nil)

// set your class as the paginator's delegate if you use the delegate approach (see explanation below):
prescriptions.delegate = self

// set the paginator's results callback block, if you use the callback block approach (see explanation below):
prescriptions.resultsCallback = {
    (objects: [MDObjectInstance]?, hasMore: NSNumber?, fault: MDFault?) in
    
    if let fault = fault {
        // fault handling
    } else {
        // "objects" will be instances of the Prescription class.
        
        // Use hasMore.boolValue to know if there are more pages to load
    }
}

// And then you can call either `loadNextPage` or `loadAllPages` on the paginator, depending on what you need:
prescriptions.loadNextPage()

// or
prescriptions.loadAllPages()

// ----
// Note: make sure to store the instance somewhere, otherwise it will be destroyed by ARC.

If you use the delegate approach, don't forget to conform to the MDPaginationHelperDelegate protocol,

// YourClassHandlingPaginationResults.h

@interface YourClassHandlingPaginationResults <MDPaginationHelperDelegate>
  ...
@end
extension YourClassHandlingPaginationResults: MDPaginationHelperDelegate {

}

and implement the delegate methods to get the results:

// YourClassHandlingPaginationResults.m

@implementation YourClassHandlingPaginationResults
 
...

- (void)paginator:(MDPaginationHelper *)paginator didLoadResults:(nullable NSArray<MDObjectInstance*> *)objects hasMore:(nullable NSNumber *)hasMore fault:(nullable MDFault *)fault
{
    // handle your page results here
    if (fault)
    {
        // fault handling
    }
    else
    {
        // "objects" will be instances of the Prescription class.
        
        // Use hasMore.boolValue to know if there are more pages to load
    }
}

- (void)paginator:(MDPaginationHelper *)paginator didLoadAllResults:(nullable NSArray<MDObjectInstance*> *)objects fault:(nullable MDFault *)fault
{
    // handle "all the pages" results here
    if (fault)
    {
        // fault handling
    }
    else
    {
        // "objects" will be instances of the Prescription class.
    }
}

...
  
@end
extension YourClassHandlingPaginationResults: MDPaginationHelperDelegate {
    func paginator(_ paginator: MDPaginationHelper, didLoadResults objects: [MDObjectInstance]?, hasMore: NSNumber?, fault: MDFault?) {
        // handle your page results here
        if let fault = fault {
            // fault handling
        } else {
            // "objects" will be instances of the Prescription class.
            
            // Use hasMore.boolValue to know if there are more pages to load
        }
    }
    
    func paginator(_ paginator: MDPaginationHelper, didLoadAllResults objects: [MDObjectInstance]?, fault: MDFault?) {
        // handle your page results here
        if let fault = fault {
            // fault handling
        } else {
            // "objects" will be instances of the Prescription class.
        }
    }
}

Both delegate methods are marked as optional. If you don't implement the didLoadAllResults, and loadAllPages is called, you'll get all the results in the first method, together with the results from calling loadNextPage. So, if you need to get the results of both calls separately, implement both.

📘

Note

The delegate approach and the results callback approach can be used simultaneously.

📘

Note

You'll find documentation about cacheResults and inverseOrder, as well as for some other pagination options (e.g. list property pagination, or paging using a field other than _id), in the MDPaginationHelper.h header file.

2. Using the Pagination Manager

If you don't want to manage the instances of MDPaginationHelper, you can leave that to the MDPaginationManager. Just create the instances using the MDPaginationManager class. Let's achieve the same as before; the only difference relies in how you create the instance:

// With this identifier, you can retrieve the instance from the MDPaginationManager later...
NSString *identifier = @"someIdentifier";

MDPaginationHelper *prescriptions = [MDPaginationManager
                                     paginatorWithIdentifier:identifier
                                     context:@"c_prescriptions"
                                     pageSize:10
                                     cacheResults:NO
                                     inverseOrder:NO];

// the rest is the same, and you don't have to take care of storing the paginator
// With this identifier, you can retrieve the instance from the MDPaginationManager later...
let identifier: String = "someIdentifier"

let prescriptions: MDPaginationHelper = MDPaginationManager.paginator(withIdentifier: identifier,
                                                                      context: "c_prescriptions",
                                                                      pageSize: 10,
                                                                      cacheResults: false,
                                                                      inverseOrder: false)
// the rest is the same, and you don't have to take care of storing the paginator

Later on, that paginator's instance can be retrieved by doing this:

MDPaginationHelper *prescriptions = [[MDPaginationManager sharedInstance] paginatorWithIdentifier:@"someIdentifier"];
let prescriptions: MDPaginationHelper = MDPaginationManager.sharedInstance().paginator(withIdentifier: "someIdentifier")

If you don't need to retrieve the pagination helpers by identifier, but you still want the manager to take care of storing them; there is a function to generate random identifiers:

NSString *randomIdentifier = [MDPaginationManager randomId];
let randomIdentifier: String = MDPaginationManager.randomId()