Caching the Data

(Optional, offline mode only) Caching is an important part of getting an application to work in offline mode. The Cache method is used to cache and persist data, when the mobile device is out of the network range, and process the data, when it is within the range of the network.

Note: The delete tombstones for delta query support is not available on OData JSON format.

Prerequisites

The caching functionality comprises of two types of stored entries, a copy of the entries you receive from the server called as "server entry", and a copy of locally modified entries called as "local entry".

Use the Caching interface, which is implemented by the Cache class, to create an object to work with.

Initialize the Cache

To initialize all the elements required for cache to work, use the initializeCacheWithError method. This method should be executed once during application start.

 
 id<Caching> cache = [[Cache alloc] init];
 NSError* error = nil;
 if (![cache initializeCacheWithError:&error])
 {  
      NSLog(@"Initialize Error : %@", error); 
      return;
 }   

Cache can be used in persistable mode (database) and non-persistable mode (memory). By default, cache is persistable.

If you do not want to persist cache to the database, use the following API:
[cacheLocal setIsPersistable:NO];

Merge to Cache

To incrementally update the cache for server entries with the latest state of server objects, use the mergeEntries method. Every online HTTP GET operation on a URL should be followed by a mergeEntries method to enable the server cache to be in-sync with the backend service. It is important to instate a server cache using the mergeEntries method for all operations to work after a successful online GET request for a URL at the initial stage. It is recommended to optimize GET operation with Delta support to avoid redundancies.

ODataDataParser* dataParser = [[ODataDataParser alloc] initWithEntitySchema:actualcollection.entitySchema andServiceDocument: serviceDocument];
        [dataParser parse:[collection responseData]];
        ODataFeed *feed = [dataParser getFeed];
NSError *errormerge=nil;
if(![cache mergeEntries:feed forUrlKey:URL withError:&errormerge withCompletionBlock:^(NSNotification *notif){
        NSLog(@"Cache updated");
    }] )
    {
        NSLog(@"Merge error:%@",errormerge);
        return;
        
    }
Note: There is no overhead observed in the application response time with the additional caching of data, provided merge to cache is called in separate thread after delivering parsed data for presentation.

Read Entry from Cache

You can read server entries or local entries from cache.

To read only server entries, use readEntriesForURLKey. To display local entries, use readEntriesLocalForEntryId. You can also combine the server and local entries to display the latest version of application data.

The ODataEntry class of the parser has two member properties. The isLocalEntry property checks if the particular entry is local, and the cacheState checks if the local entry is created, updated, or deleted on the client. The cache states are represented by the enums - CreatedState, UpdatedState, and DeletedState.

/*Read entry from server.*/
/* Note: To maintain brevity in iOS, the method name does not have the key word
server in it and it is always server entries by default that the read returns */ 
id<Caching> cacheLocal = [[Cache alloc] init];
 NSError* error = nil;
 NSArray* cachedEntries = [cacheLocal readEntriesForUrlKey:urlKey withError:&error];
 if (error)
 {
     NSLog(@"Read Error : %@", error);
     return;
 }
/*Read entry from local.*/
id<Caching> cacheLocal = [[Cache alloc] init];
 NSError* error = nil;
 NSArray* localEntries = [cacheLocal readEntriesLocalForEntryId:id forEntityType:type withError:&error];
 if (error) 
 {
    NSLog(@"Read Local Entry Error: %@", error);
     return;
 }

Managing Locally Modified Entries in Cache

Store Document in Cache

To cache the service and metadata document (schema) for a particular service URL, use the storeDocument method . You can also define your own enum type and store the data for that enum type. The service document must be stored only after the metadata document is parsed.
typedef enum {
ServiceDocumentType = 0,
MetaDocumentType = 1
} DocType;
//Service document
 id<Caching> cacheLocal = [[Cache alloc] init];
 NSError* error = nil;
 if ([cacheLocal storeDocument:servDoc forDocType:ServiceDocumentType forUrlKey:urlKey withError:&error])
 { 
      NSLog(@"Store Document Error : %@", error); 
      return;
 }
//Metadata document
 id<Caching> cacheLocal = [[Cache alloc] init];
 NSError* error = nil;
 if ([cacheLocal storeDocument:metaDoc forDocType:MetaDocumentType forUrlKey:urlKey withError:&error])
 { 
      NSLog(@"Store Document Error : %@", error); 
      return;
 } 

Read Document from Cache

To read the service and metadata documents from cache, use the readDocumentForUrlKey method. This method returns the stored document in the cache. The application should pass the document type and the URL for which the document is relevant.

 id<Caching> cacheLocal = [[Cache alloc] init];
 NSError* error = nil;
 id document = [cacheLocal readDocumentForUrlKey:urlKey forDocType:ServiceDocumentType
 withError:&error];
 if (error) { 
      NSLog(@"Read Document Error : %@", error); 
      return;
 } 

Clearing the Cache

To clear the cache and persistence of all entries based on the URL key, use the clearCacheForUrlKey method. This method also deletes the delta token of any document that is stored against this URL. SAP recommends that you use this method only when the application does not support delta queries.

id<Caching> cacheLocal = [[Cache alloc] init];
 NSError* error = nil;
 if ([cacheLocal clearCacheForUrlKey:urlKey withError:&error]) {
     NSLog(@"Clear Cache Error : %@", error);
     return;
 }

Controlling OData Cache Size and Age

The OData SDK does not provide any APIs for configuring cache behavior related to cache size or age. The underlying database used is SQLCipher, which implements the following limits: http://www.sqlite.org/limits.html.

The cache database utilizes private timestamps internally, but these may not reflect the time of the last valid GET request, and are not exposed as public APIs for the purpose of validating the freshness of data in the cache.

Related concepts
Offline OData Support