IOS Local Cache Implementation Scenario reference

Source: Internet
Author: User

In mobile application development, in order to reduce the number of interactions with the server, speed up the user's response speed, generally in the iOS device to add a caching mechanism, the previous article describes the iOS device memory cache, this article will design a local cache mechanism.

Functional Requirements

This caching mechanism satisfies the following features.

1. You can cache the data to a local disk.

2, you can determine whether a resource has been cached. If it has been cached, the same resource is requested, first to local disk search.

3, you can determine when the file cache expires. Here for the sake of simplicity here, we set an expiration time for each requested file when requesting a URL resource.

4, can be implemented: if the file has been cached, and has not expired, this will return the local data, or re-request the URL.

5, can be implemented: If the file download is unsuccessful or the download is not completed, the next time you open the program, remove the files that were unsuccessful or did not download.

6, can be achieved: simultaneously request or download multiple resources.

Design implementation:

1. Design a CacheItem class that is used to request a Web connection, an instance of which represents a cache entry. This CacheItem class requires a URL to create a nsurlconnection to request a Web resource. Using the CacheItem class is primarily used to request Web resources.

/*---------Cache entry--------------*/

@interface Cacheitem:nsobject {
@public
Id<cacheitemdelegate> delegate;
Web address
NSString *remoteurl;
@private
Are you downloading
BOOL isdownloading;
Nsmutabledata Object
Nsmutabledata *connectiondata;
Nsurlconnection Object
Nsurlconnection *connection;
}

/* -------------------------- */

@property (nonatomic, retain) id<cacheitemdelegate> delegate;
@property (nonatomic, retain) nsstring *remoteurl;
@property (nonatomic, assign) BOOL isdownloading;
@property (nonatomic, retain) Nsmutabledata *connectiondata;
@property (nonatomic, retain) nsurlconnection *connection;

/*----------Start the Download method-----------*/

-(BOOL) Startdownloadingurl: (NSString *) Paramremoteurl;

@end

2. Before nsurlconnection starts the request, call the Cacheddownloadmanager class to search for and manage the local cache file. Save the cache file to a dictionary class. This dictionary is designed as follows:

{
"Http://www.cnn.com" = {
Downloadenddate = "2011-08-02 07:51:57 +0100";
Downloadstartdate = "2011-08-02 07:51:55 +0100";
Expiresinseconds = 20;
Expirydate = "2011-08-02 07:52:17 +0100";
Localurl = "/var/mobile/applications/applicationid/documents/
Httpwww.cnn.com.cache ";
};
"Http://www.baidu.com" = {
Downloadenddate = "2011-08-02 07:51:49 +0100";
Downloadstartdate = "2011-08-02 07:51:44 +0100";
Expiresinseconds = 20;
Expirydate = "2011-08-02 07:52:09 +0100";
Localurl = "/var/mobile/applications/applicationid/documents/
Httpwww.oreilly.com.cache ";
};
}

A dictionary is nested in the dictionary above. The inside dictionary represents the cached information for a cache entry: Download end time, download start time, cache expiration time, cache expiry time, cache to local path.

Let's look at the Cacheddownloadmanager class below. Use it to implement and encapsulate our caching strategy.

/*-----------Cacheddownloadmanager--------------*/

@interface Cacheddownloadmanager:nsobject
<CacheItemDelegate> {
@public
Id<cacheddownloadmanagerdelegate> delegate;
@private
A dictionary of record cache data
Nsmutabledictionary *cachedictionary;
The path of the cache
NSString *cachedictionarypath;
}


@property (nonatomic, assign)
Id<cacheddownloadmanagerdelegate> delegate;

@property (nonatomic, copy)
Nsmutabledictionary *cachedictionary;

@property (nonatomic, retain)
NSString *cachedictionarypath;


/* Keep the cache dictionary */

-(BOOL) savecachedictionary;

/* Public method: Download */

-(BOOL) Download: (NSString *) paramurlasstring
Urlmustexpireinseconds: (nstimeinterval) paramurlmustexpireinseconds
Updateexpirydateifincache: (BOOL) Paramupdateexpirydateifincache;

/* -------------------------- */

@end

As can be seen from the code above, there is a cache dictionary in the class that manages the cache:cachedictionary, which is used to represent the cache of all resources;Cachedictionarypath is used to represent the cache path The savecachedictionary is used to archive the cache dictionary to a local file. Download:urlMustExpireInSeconds:updateExpiryDateIfInCache is a public interface that implements our caching strategy by passing URLs, cache expiration time, and updating cache expiration time by three parameters for ease of use.

3. If the file has been downloaded and has not expired, obtain the data from the local file. If the file has expired, download it again. We do this through the Download:urlMustExpireInSeconds:updateExpiryDateIfInCache method, which mainly looks at the code of this method:

-(BOOL) Download: (NSString *) paramurlasstring
Urlmustexpireinseconds: (nstimeinterval) paramurlmustexpireinseconds
Updateexpirydateifincache: (BOOL) paramupdateexpirydateifincache{

BOOL result = NO;

if (self.cachedictionary = = Nil | |
[paramurlasstring length] = = 0) {
return (NO);
}

paramurlasstring = [paramurlasstring lowercasestring];
Gets the data about the cache entry from the dictionary based on the URL
Nsmutabledictionary *itemdictionary =
[Self.cachedictionary objectforkey:paramurlasstring];

/* Use these variables to help us understand the cache logic */
Whether the file has been cached
BOOL filehasbeencached = NO;
Whether the cache expires
BOOL cachedfilehasexpired = NO;
Whether the cache file exists
BOOL cachedfileexists = NO;
Can the cache file be loaded
BOOL cachedfiledatacanbeloaded = NO;
Cache file Data
NSData *cachedfiledata = nil;
Whether the cache file is fully downloaded
BOOL cachedfileisfullydownloaded = NO;
Whether the cache file has been downloaded
BOOL cachedfileisbeingdownloaded = NO;
Expiry time
NSDate *expirydate = nil;
Download End time
NSDate *downloadenddate = nil;
Download Start time
NSDate *downloadstartdate = nil;
Local cache Path
NSString *localurl = nil;
Effective time
NSNumber *expiresinseconds = nil;
NSDate *now = [NSDate Date];

if (itemdictionary! = nil) {
filehasbeencached = YES;
}
If the file is already cached, get the relevant value from the cache entry-related data
if (filehasbeencached = = YES) {

Expirydate = [Itemdictionary
Objectforkey:cachedkeyexpirydate];

Downloadenddate = [Itemdictionary
Objectforkey:cachedkeydownloadenddate];

Downloadstartdate = [Itemdictionary
Objectforkey:cachedkeydownloadstartdate];

Localurl = [Itemdictionary
Objectforkey:cachedkeylocalurl];

Expiresinseconds = [Itemdictionary
Objectforkey:cachedkeyexpiresinseconds];
If the download start and end times are not empty, the file is all downloaded
if (downloadenddate! = Nil &&
Downloadstartdate! = nil) {
cachedfileisfullydownloaded = YES;
}

/* If Expiresinseconds is not empty, downloadenddate is empty, indicating that the file is already being downloaded */
if (expiresinseconds! = Nil &&
Downloadenddate = = nil) {
cachedfileisbeingdownloaded = YES;
}

/* Determine if the cache expires */
if (expirydate! = Nil &&
[Now Timeintervalsincedate:expirydate] > 0.0) {
cachedfilehasexpired = YES;
}

if (cachedfilehasexpired = = NO) {
/* If the cache file does not expire, load the cache file and update the expiration Time */
Nsfilemanager *filemanager = [[Nsfilemanager alloc] init];

if ([filemanager fileexistsatpath:localurl] = = YES) {
Cachedfileexists = YES;
Cachedfiledata = [NSData Datawithcontentsoffile:localurl];
if (cachedfiledata! = nil) {
cachedfiledatacanbeloaded = YES;
}/* if (cachedfiledata! = nil) {*/
}/* if ([filemanager fileexistsatpath:localurl] = = YES) {*/

[FileManager release];

/* Update Cache time */

if (Paramupdateexpirydateifincache = = YES) {

NSDate *newexpirydate =
[NSDate Datewithtimeintervalsincenow:
Paramurlmustexpireinseconds];

NSLog (@ "Updating the expiry date from%@ to%@.",
Expirydate,
Newexpirydate);

[Itemdictionary setobject:newexpirydate
Forkey:cachedkeyexpirydate];

NSNumber *expires =
[NSNumber Numberwithfloat:paramurlmustexpireinseconds];

[Itemdictionary Setobject:expires
Forkey:cachedkeyexpiresinseconds];
}

}/* if (cachedfilehasexpired = = NO) {*/

}

if (cachedfileisbeingdownloaded = = YES) {
NSLog (@ "This file is already being downloaded ...");
return (YES);
}

if (filehasbeencached = = YES) {

if (cachedfilehasexpired = = NO &&
Cachedfileexists = = YES &&
cachedfiledatacanbeloaded = = YES &&
[cachedfiledata length] > 0 &&
cachedfileisfullydownloaded = = YES) {

/* If the file has a cache and is not expired */

NSLog (@ "file has a cache and is not expired.");

[Self.delegate
Cacheddownloadmanagersucceeded:self
Remoteurl:[nsurl Urlwithstring:paramurlasstring]
Localurl:[nsurl Urlwithstring:localurl]
Abouttobereleaseddata:cachedfiledata
Iscacheddata:yes];

return (YES);

} else {
/* If the file is not cached, get cache failed */
NSLog (@ "file is not cached.");
[Self.cachedictionary removeobjectforkey:paramurlasstring];
[Self savecachedictionary];
}/* if (cachedfilehasexpired = = NO && */

}/* if (filehasbeencached = = YES) {*/

/* To download the file */

4. Below we design two delegate methods for cache entry download success and failure:

@protocol cacheitemdelegate <NSObject>
The download successfully executes the method
-(void) cacheitemdelegatesucceeded
:(CacheItem *) paramsender
Withremoteurl: (Nsurl *) Paramremoteurl
Withabouttobereleaseddata: (NSData *) Paramabouttobereleaseddata;

Download failed to execute the method
-(void) cacheitemdelegatefailed
:(CacheItem *) paramsender
Remoteurl: (Nsurl *) Paramremoteurl
Witherror: (Nserror *) Paramerror;

@end

When the download succeeds, the download time in the cache dictionary is modified to indicate that the download is complete and that the requested resource data needs to be cached locally:

Delegate method for cached items
-(void) cacheitemdelegatesucceeded: (CacheItem *) Paramsender
Withremoteurl: (Nsurl *) Paramremoteurl
Withabouttobereleaseddata: (NSData *) paramabouttobereleaseddata{

Get data about the cache entry from the cache dictionary
Nsmutabledictionary *dictionary =
[Self.cachedictionary Objectforkey:[paramremoteurl absolutestring];
Take the current time
NSDate *now = [NSDate Date];
Get valid time
NSNumber *expiresinseconds = [Dictionary
Objectforkey:cachedkeyexpiresinseconds];
Convert into Nstimeinterval
Nstimeinterval expiryseconds = [Expiresinseconds floatvalue];
Modify the download end time for cached items in the dictionary
[Dictionary setobject:[nsdate Date]
Forkey:cachedkeydownloadenddate];
To modify the cache expiration time for cache entries in a dictionary
[Dictionary Setobject:[now Datebyaddingtimeinterval:expiryseconds]
Forkey:cachedkeyexpirydate];
Save Cache Dictionary
[Self savecachedictionary];

NSString *localurl = [dictionary objectforkey:cachedkeylocalurl];

/* Keep the downloaded data to disk */
if ([Paramabouttobereleaseddata Writetofile:localurl
Atomically:yes] = = YES) {
NSLog (@ "cache file to disk succeeded.");
} else{
NSLog (@ "cache file to disk failed.");
}
Delegate methods for performing cache management
[Self.delegate
Cacheddownloadmanagersucceeded:self
Remoteurl:paramremoteurl
Localurl:[nsurl Urlwithstring:localurl]
Abouttobereleaseddata:paramabouttobereleaseddata
Iscacheddata:no];


}

If the download fails we need to remove the cache entry from the cache dictionary:

Delegate method for failed cache entry failure
-(void) cacheitemdelegatefailed: (CacheItem *) Paramsender
Remoteurl: (Nsurl *) Paramremoteurl
Witherror: (Nserror *) paramerror{

/* Remove the cache entry from the cache dictionary and send a delegate */

if (self.delegate! = nil) {



Objectforkey:[paramremoteurl Absolutestring]];


Objectforkey:cachedkeylocalurl];

[Self.delegate
Cacheddownloadmanagerfailed:self
Remoteurl:paramremoteurl
Localurl:[nsurl Urlwithstring:localurl]
Witherror:paramerror];
}


Removeobjectforkey:[paramremoteurl Absolutestring]];

}

5. When loading the cache dictionary, we can remove files that have not been downloaded:

NSString *documentsdirectory =
[Self documentsdirectorywithtrailingslash:yes];
Path to the production cache dictionary
Cachedictionarypath =
[[Documentsdirectory
stringbyappendingstring:@ "Cacheddownloads.dic"] retain];
Create a Nsfilemanager instance
Nsfilemanager *filemanager = [[Nsfilemanager alloc] init];
Determine if there is a cached dictionary of data
if ([FileManager
FileExistsAtPath:self.cacheDictionaryPath] = = YES) {
NSLog (Self.cachedictionarypath);
Loading data from a cache dictionary
Nsmutabledictionary *dictionary =
[[Nsmutabledictionary Alloc]
InitWithContentsOfFile:self.cacheDictionaryPath];

Cachedictionary = [Dictionary mutablecopy];

[Dictionary release];

Remove cached data that is not completed for download
[Self removecorruptedcacheditems];

} else {
Create a new Cache dictionary
Nsmutabledictionary *dictionary =
[[Nsmutabledictionary alloc] init];

Cachedictionary = [Dictionary mutablecopy];

[Dictionary release];

}

[FileManager release];

This basically completes the functionality we need, and let's look at how we can use the caching features we've designed.

Example scenario:

We use a UIWebView to show StackOverflow this site, we cache the content of this site to local 20 seconds, if the user to request the site within 20 seconds, then get the content from the local file, or after 20 seconds, then retrieve the data, and cache to local.

Drag and drop a button and a WebView control on the interface, such as.

This allows us to easily use the classes defined earlier. We instantiate a cacheddownloadmanager in Viewdidload and set its delegate to self. When the download is complete, execute the Cacheddownloadmanager download successful delegate method.

-(void) Viewdidload {
[Super Viewdidload];
[Self settitle:@ "local cache test"];
Cacheddownloadmanager *newmanager = [[Cacheddownloadmanager alloc] init];
Self.downloadmanager = Newmanager;
[Newmanager release];
[Self.downloadmanager setdelegate:self];


}

Add the following code to the button's Click event to request StackOverflow:

  static NSString *url = @ "http://stackoverflow.com";

[Self.downloadmanager Download:url
urlmustexpireinseconds:20.0f
Updateexpirydateifincache:yes];

The above code indicates that the StackOverflow cache event is set to 20s, and if there is the same request within 20s, the StackOverflow content data is obtained locally. Updateexpirydateifincache is set to Yes: At this request, the cache time is updated to 20s, similar to our session. If set to No, the cache expires after the first request of 20s.

The Cacheddownloadmanager delegate method is executed after the request is completed. We present the data in UIWebView with the following code:

-(void) cacheddownloadmanagersucceeded: (Cacheddownloadmanager *) Paramsender
Remoteurl: (Nsurl *) Paramremoteurl
Localurl: (Nsurl *) Paramlocalurl
Abouttobereleaseddata: (NSData *) paramabouttobereleaseddata
Iscacheddata: (BOOL) paramiscacheddata{

[WebView loaddata:paramabouttobereleaseddata mimetype:@ "text/html" textencodingname:@ "UTF-8" Baseurl:[nsurl urlwithstring:@ "http://stackoverflow.com"];
}

This allows us to implement a 20s cache.

Effect:

Click the Test button for the first time:

20s Click on the button, the program to get data from the local, relatively fast to display the page.

Summarize:

This article designs a local caching scheme for iphone applications through code and examples.

Ext.: http://blog.csdn.net/fhbystudy/article/details/25902841

IOS Local Cache Implementation Scenario reference

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.