📜 ⬆️ ⬇️

Network caching in iOS. Introduction

Virtually every mobile application gets any data from the network.
Unfortunately, access to the network is not always possible and therefore it is important for the developer to correctly implement the network cache in the application.

In this regard, I decided to write a series of articles on what methods of cache implementation exist and when to use them .

So, the introduction.

')

Caching strategies


There are two approaches to caching: on-demand caching and pre-caching.

On-demand caching allows you to view content that was previously viewed offline. The data received from the server is stored on the device and for each request, their relevance is checked. If the data is relevant, then they are taken from the disk, if not then a request is sent to the server.

Pre-caching means that all data that the user may need will be retrieved and saved to disk immediately.

To determine which caching strategy to use, you need to understand whether post processing may be required after it is loaded. Post processing implies any modification of the loaded data. For example, changing the links in the HTML page so that they point to cached images locally, etc.

Where to store the cache


Applications can store information only in their sandbox. Since cached data is not generated by the user, they should be stored in NSCachesDirectory, not in NSDocumentsDirectory. It is a good practice to create a separate directory for all cached data.

In this example, the directory MyAppCache is created in the Library / Caches folder:
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSCachesDirectory, NSUserDomainMask, YES); NSString *cachesDirectory = [paths objectAtIndex:0]; cachesDirectory = [cachesDirectory stringByAppendingPathComponent:@”MyAppCache”]; 

The reason for storing the cache in the Library / Caches folder is that iCloud (and iTunes) excludes this directory from the backup. And, therefore, the space limited in iCloud (at present for a free account, this is about 5 GB) is not spent on storing unnecessary data.

If an application intensively caches, it is recommended to use memory instead of a disk and upload data to disk when the application is closed. This is due to the fact that the iPhone's flash memory has a limited number of write / read cycles and it is undesirable to load it once again.

How to store cache


On iOS, there are many different ways to store user data. Best suited for caching: NSKeyedArchiver, Core Data, SQLite, NSURLCache.

NSKeyedArchiver


Data model caching is implemented using the NSKeyedArchiver class. In order for model objects to be archived, model classes must implement the NSCoding protocol. Namely methods
 - (void)encodeWithCoder:(NSCoder *)aCoder; - (id)initWithCoder:(NSCoder *)aDecoder; 

If the class implements NSCoding, for archiving it is enough to call one of the following methods:
 [NSKeyedArchiver archiveRootObject:objectForArchiving toFile:archiveFilePath]; 

 [NSKeyedArchiver archivedDataWithRootObject:objectForArchiving]; 

The first method will create a file with the archive in the path archiveFilePath. The second method will return an NSData object. NSData is usually faster, since there are no additional costs for accessing the file, but the data will be stored in the application's memory.

To unzip a model from a file (or a pointer to NSData), use the NSKeyedUnarchiver class. You can unarchive data using one of the following methods:
 [NSKeyedUnarchiver unarchiveObjectWithData:data]; 

 [NSKeyedUnarchiver unarchiveObjectWithFile:archiveFilePath]; 

Using NSKeyedArchiver / NSKeyedUnarchiver requires that models comply with the NSCoding protocol. The implementation of NSCoding is very simple, but if there are many files, it can take a long time. Therefore, to automate this process is better to use any tool. For example, the development environment AppCode .

Core data


To store data in Core Data, you must create a model file that contains a description of the entities (Entities), as well as relationships between them (Relationships), and write methods for storing and retrieving data. Using Core Data, you can get a real offline mode of the application, as is done in standard Mail and Calendar applications.

When implementing pre-caching, you need to periodically delete data that is not needed. Otherwise, the cache size will start to grow significantly, which will cause a loss of performance. Local changes are synchronized by tracking the change set and sending it back to the server. There are many algorithms for tracking change sets, but it's better to use one of those that works in Git.

Although Core Data can be used for on-demand caching, it’s best not to. The main advantage of Core Data is to provide access to model properties without having to unzip all the data. However, the complexity of implementing Core Data in an application outweighs this advantage.

Raw SQLite


To work with SQLite, you need to link the application with the libsqlite3 library, but this approach has significant drawbacks.
All sqlite3 libraries and the Object Relational Mapping (ORM) mechanism are slower than Core Data. In addition, the implementation of sqlite3 in iOS is not thread safe. So if you are not using a separately compiled sqlite3 library (compiled with the thread-safe flag), then you are responsible for ensuring that the thread-safe read / write access to the sqlite3 database is guaranteed.

Since Core Data can offer much more features (data migration, embedded thread-security, ...), it is recommended to avoid using native SQLite on iOS.

NSURLCache


Ideal for on-demand caching. Allows you to cache the data returned by NSURLRequest almost automatically and requires a minimum of code.

Just a couple of lines and your application will receive a disk cache for requests.
 - (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions { NSURLCache *URLCache = [[NSURLCache alloc] initWithMemoryCapacity:4 * 1024 * 1024 diskCapacity:20 * 1024 * 1024 diskPath:nil]; [NSURLCache setSharedURLCache:URLCache]; } 


Unfortunately, it is only suitable for REST services and there are problems when working with some HTTP headers.

Conclusion


To implement on-demand caching, it is better to use NSURLCache or NSKeyedArchiver. The implementation of a fully functional offline mode requires work with CoreData.

In the next part, I plan to examine in detail the work with NSURLCache / NSKeyedArchiver and describe the cases for which they are suitable.

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


All Articles