IOS use NSURLCache interface to the most convenient to do the most simple cache

In the recent version, do some optimization interface pull data, since we are a content oriented app, for long and rich text articles, and there is no direct access to the WebView client side realization, but through the interface and pull the HTML parsing code, realize the rich text by native the method will write some articles about this aspect. Because after the post finished, do not often change, then the client if every time to pull the HTML code and analysis, will waste a lot of cyber source, so in this version, I like with Etag to achieve the backend interface, due to network not many articles about this aspect, this article this article will talk about the network interface cache implementation method

Implementation ideas

First talk about the implementation of the idea is very simple, the interface in the response header into the Etag field, the client grabbed the value of Etag and access to the local, and then access the interface to local content. After the client in the call interface, in the request header in If-None-Match, the corresponding value is prior to access the value of Etag, the back-end status code returns 304 tell the client interface content has not changed, the client uses the interface in local content cache


What is Etag? Etag can tell the client entity that it is a way to uniquely identify resources as a string. The server will assign the corresponding Etag value for each resource. In addition, when the resource is updated, Etag values need to be updated


The realization method, one thing the most annoying is how to cache interface content, one way is to write a set of code to achieve cache function, SDWebImage is realized for cache mechanism, interface request, iOS system has been done for you. The cache, and very perfect simple, this way is called NSURLCache. In this way, only two steps can be used to cache the contents of the network interface:

  • The first step: the client set cache size AppDelegate.m = [[NSURLCache NSURLCache *urlCache alloc] initWithMemoryCapacity:4*1024*1024 diskCapacity:100*1024*1024 diskPath:nil]; NSURLCache.sharedURLCache = urlCache;
  • The second step: the client sends a GET request
  • The third step: Done, through NSCachedURLResponse *cachedResponse = sharedURLCache] cachedResponseForRequest:request]; access to the interface cache

After these two steps, the GET content of the request will be automatically cache, no need to go to achieve the contents of the cache, for this method, the Mattt God said “many developers trying to do a simple and fragile system to realize the network cache function, but NSURLCache can be as long as two lines of code and fix. 100 times.”

Demo (NSURLSession)

- (void) viewDidLoad {[super viewDidLoad]; Do any additional setup after loading / the view, typically from a nib. NSURLSessionConfiguration *config = [NSURLSessionConfiguration defaultSessionConfiguration]; NSURLSession *session = [NSURLSession sessionWithConfiguration:config delegate:self delegateQueue:nil]; NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:[NSURL URLWithString:@ cachePolicy:NSURLRequestReloadIgnoringLocalCacheData timeoutInterval:30.f] "URL"]; if (self.etag) {[request setValue:self.etag forHTTPHeaderField:@ "If-None-Match"]; *task = [session dataTaskWithRequest:request NSURLSessionDataTask} completionHandler:^ (NSData * _Nullable data NSURLResponse * _Nullable Response, NSError * _Nullable error) {NSHTTPURLResponse *urlResponse = (NSHTTPURLResponse *) response; if (urlResponse.statusCode = = 304) {NSCachedURLResponse *cachedResponse = [[NSURLCache sharedURLCache] cachedResponseForRequest:request]; if (cachedResponse) {data =;}} else {if (urlResponse.allHeaderFields[@ "Etag"]) {NSString *etag = urlResponse.allHeaderFields[@ if ("Etag"]; Etag & & etag.length; > 0; saveEtag:etag) {[self}}}];}]; [task resume];}

Demo (AFNetworking)

AFHTTPSessionManager *sessionManager = [[AFHTTPSessionManager alloc] initWithBaseURL:[NSURL URLWithString:baseURL] sessionConfiguration:config]; sessionManager.requestSerializer [CustomJSONRequestSerializer = serializer]; sessionManager.responseSerializer = [CustomJSONResponseSerializer serializer];
@interface CustomJSONRequestSerializer: AFJSONRequestSerializer @end @implementation CustomJSONRequestSerializer (NSMutableURLRequest) requestWithMethod: (NSString * method) URLString: (NSString *) URLString parameters: (ID) parameters error: (NSError *__autoreleasing _Nullable * error) {NSMutableURLRequest *request = [super requestWithMethod:method URLString:URLString parameters:parameters error:error] add request If-None-Match header NSString; / / *absoluteUrl = request.URL.absoluteString; NSString = [NSSearchPathForDirectoriesInDomains (NSCachesDirectory, *directory NSUserDomainMask, YES).FirstObject stringByAppendingPathComponent:@ "etags"]; NSString *fileName = [directory stringByAppendingPathComponent:[self cachedFi LeNameForKey:absoluteUrl]]; if ([[NSFileManager defaultManager] fileExistsAtPath:fileName]) {NSString *etag = [NSKeyedUnarchiver unarchiveObjectWithFile:fileName]; if (Etag & & etag.length > 0) {[request addValue:etag forHTTPHeaderField:@ "If-None-Match"]}}}; return request; @end
@interface CustomJSONResponseSerializer: AFJSONResponseSerializer @end @implementation CustomJSONResponseSerializer (nullable ID) - responseObjectForResponse: (NSURLResponse * response) data: (NSData *) data error: (NSError *__autoreleasing _Nullable * error NSUInteger) {responseStatusCode = 200; if ([response isKindOfClass:[NSHTTPURLResponse class]]) {responseStatusCode = (NSUInteger) / (NSHTTPURLResponse *) response statusCode] (if responseObject ID;}; responseStatusCode = = 304) {/ / fetch cached contents NSCachedURLResponse *cachedResponse = [[NSURLCache sharedURLCache] cachedResponseForRequest:task.currentRequest]; if (cachedResponse) {responseObject = [super responseObje CtForResponse:cachedResponse.response error:error];} else {/ / cached response was cleared, need to clear cached Etag NSString *directory = [NSSearchPathForDirectoriesInDomains (NSCachesDirectory, NSUserDomainMask, YES).FirstObject stringByAppendingPathComponent:@ "etags"]; NSString *fileName = [self cachedFileNameForKey:response.URL.absoluteString]; NSString *cachedFileName = [directory stringByAppendingPathComponent:fileName]; [[NSFileManager defaultManager] removeItemAtPath:cachedFileName error:nil] return responseObject;};} else (responseStatusCode > if & = 200; & responseStatusCode < {if ([respon = 299) Se isKindOfClass:[NSHTTPURLResponse class]]) {NSHTTPURLResponse *httpResponse = (NSHTTPURLResponse *) response; if (httpResponse.allHeaderFields[@ "Etag"]) {NSString *etag httpResponse.allHeaderFields[@ = "Etag"]; if (Etag & & amp; etag.length; > 0) {NSString *directory = [NSSearchPathForDirectoriesInDomains (NSCachesDirectory, NSUserDomainMask, YES).FirstObject stringByAppendingPathComponent:@ "etags"]; if ([[NSFileManager defaultManager] fileExistsAtPath:directory]! [[NSFileManager defaultManager] createDirectoryAtPath:directory withIntermediateDirectories:NO attributes:nil) {error:nil]}; NSString *fileName = [self cachedFileNameForKey:response.URL.absoluteString]; NSString *cachedFileName = [directory stringByAppendingPathComponent:fileName]; BOOL success = [NSKeyedArchiver archiveRootObject:etag toFile:cachedFileName];}}} = responseObject [super responseObjectForResponse:response data:data error:error]; return responseObject;} else {ID responseObject = [super responseObjectForResponse:response data:data error:error]; if ([responseObject isKindOfClass:[NSDictionary class]] [NSError errorWithDomain:NSURLErrorDomain code:responseStatusCode) {*error = userInfo:responseObject]; } else {*error = [NSError code:responseStatusCode userInfo:nil];} return nil;}} @end

Reprint please indicate the source, the original address: use NSURLCache interface to the most convenient to do the most simple cache