mirror of
https://github.com/zhigang1992/RestKit.git
synced 2026-04-29 05:05:34 +08:00
Implement Timeout Based Caches
This commit is contained in:
committed by
Blake Watters
parent
16f6f004b5
commit
f98566b837
@@ -45,8 +45,11 @@ typedef enum {
|
|||||||
|
|
||||||
// Load from the cache if we have data stored
|
// Load from the cache if we have data stored
|
||||||
RKRequestCachePolicyEnabled = 1 << 3,
|
RKRequestCachePolicyEnabled = 1 << 3,
|
||||||
|
|
||||||
|
// Load from the cache if we are within the timeout window
|
||||||
|
RKRequestCachePolicyTimeout = 1 << 4,
|
||||||
|
|
||||||
RKRequestCachePolicyDefault = RKRequestCachePolicyEtag
|
RKRequestCachePolicyDefault = RKRequestCachePolicyEtag | RKRequestCachePolicyTimeout
|
||||||
} RKRequestCachePolicy;
|
} RKRequestCachePolicy;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -86,6 +89,7 @@ typedef enum RKRequestBackgroundPolicy {
|
|||||||
BOOL _sentSynchronously;
|
BOOL _sentSynchronously;
|
||||||
BOOL _forceBasicAuthentication;
|
BOOL _forceBasicAuthentication;
|
||||||
RKRequestCache* _cache;
|
RKRequestCache* _cache;
|
||||||
|
NSTimeInterval _cacheTimeoutInterval;
|
||||||
|
|
||||||
#if TARGET_OS_IPHONE
|
#if TARGET_OS_IPHONE
|
||||||
RKRequestBackgroundPolicy _backgroundPolicy;
|
RKRequestBackgroundPolicy _backgroundPolicy;
|
||||||
@@ -181,6 +185,13 @@ typedef enum RKRequestBackgroundPolicy {
|
|||||||
*/
|
*/
|
||||||
@property (nonatomic, retain) NSString* HTTPBodyString;
|
@property (nonatomic, retain) NSString* HTTPBodyString;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The timeout interval within which the request should not be sent
|
||||||
|
* and the cached response should be used. Used if the cache policy
|
||||||
|
* includes RKRequestCachePolicyTimeout
|
||||||
|
*/
|
||||||
|
@property (nonatomic, assign) NSTimeInterval cacheTimeoutInterval;
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
|||||||
@@ -27,7 +27,8 @@
|
|||||||
|
|
||||||
@synthesize URL = _URL, URLRequest = _URLRequest, delegate = _delegate, additionalHTTPHeaders = _additionalHTTPHeaders,
|
@synthesize URL = _URL, URLRequest = _URLRequest, delegate = _delegate, additionalHTTPHeaders = _additionalHTTPHeaders,
|
||||||
params = _params, userData = _userData, username = _username, password = _password, method = _method,
|
params = _params, userData = _userData, username = _username, password = _password, method = _method,
|
||||||
forceBasicAuthentication = _forceBasicAuthentication, cachePolicy = _cachePolicy, cache = _cache;
|
forceBasicAuthentication = _forceBasicAuthentication, cachePolicy = _cachePolicy, cache = _cache,
|
||||||
|
cacheTimeoutInterval = _cacheTimeoutInterval;
|
||||||
|
|
||||||
#if TARGET_OS_IPHONE
|
#if TARGET_OS_IPHONE
|
||||||
@synthesize backgroundPolicy = _backgroundPolicy, backgroundTaskIdentifier = _backgroundTaskIdentifier;
|
@synthesize backgroundPolicy = _backgroundPolicy, backgroundTaskIdentifier = _backgroundTaskIdentifier;
|
||||||
@@ -44,6 +45,7 @@
|
|||||||
[self reset];
|
[self reset];
|
||||||
_forceBasicAuthentication = NO;
|
_forceBasicAuthentication = NO;
|
||||||
_cachePolicy = RKRequestCachePolicyDefault;
|
_cachePolicy = RKRequestCachePolicyDefault;
|
||||||
|
_cacheTimeoutInterval = 0;
|
||||||
}
|
}
|
||||||
return self;
|
return self;
|
||||||
}
|
}
|
||||||
@@ -268,23 +270,37 @@
|
|||||||
[[NSNotificationCenter defaultCenter] postNotificationName:RKRequestSentNotification object:self userInfo:nil];
|
[[NSNotificationCenter defaultCenter] postNotificationName:RKRequestSentNotification object:self userInfo:nil];
|
||||||
}
|
}
|
||||||
|
|
||||||
- (BOOL)shouldDispatchRequest {
|
- (BOOL)shouldLoadFromCache {
|
||||||
|
// if RKRequestCachePolicyEnabled or if RKRequestCachePolicyTimeout and we are in the timeout
|
||||||
|
if ([self.cache hasResponseForRequest:self]) {
|
||||||
|
if (self.cachePolicy & RKRequestCachePolicyEnabled) {
|
||||||
|
return YES;
|
||||||
|
} else if (self.cachePolicy & RKRequestCachePolicyTimeout) {
|
||||||
|
NSDate* date = [self.cache cacheDateForRequest:self];
|
||||||
|
NSTimeInterval interval = [[NSDate date] timeIntervalSinceDate:date];
|
||||||
|
return interval <= self.cacheTimeoutInterval;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return NO;
|
||||||
|
}
|
||||||
|
|
||||||
|
- (RKResponse*)loadResponseFromCache {
|
||||||
|
RKLogDebug(@"Found cached content, loading...");
|
||||||
|
return [self.cache responseForRequest:self];
|
||||||
|
}
|
||||||
|
|
||||||
|
- (BOOL)shouldDispatchRequest {
|
||||||
return [RKClient sharedClient] == nil || [[RKClient sharedClient] isNetworkAvailable];
|
return [RKClient sharedClient] == nil || [[RKClient sharedClient] isNetworkAvailable];
|
||||||
}
|
}
|
||||||
|
|
||||||
- (void)sendAsynchronously {
|
- (void)sendAsynchronously {
|
||||||
NSAssert(NO == _isLoading || NO == _isLoaded, @"Cannot send a request that is loading or loaded without resetting it first.");
|
NSAssert(NO == _isLoading || NO == _isLoaded, @"Cannot send a request that is loading or loaded without resetting it first.");
|
||||||
_sentSynchronously = NO;
|
_sentSynchronously = NO;
|
||||||
if (self.cachePolicy & RKRequestCachePolicyEnabled) {
|
if ([self shouldLoadFromCache]) {
|
||||||
if ([self.cache hasResponseForRequest:self]) {
|
RKResponse* response = [self loadResponseFromCache];
|
||||||
RKLogDebug(@"Found cached content, loading...");
|
_isLoading = YES;
|
||||||
_isLoading = YES;
|
[self didFinishLoad:response];
|
||||||
[self didFinishLoad:[self.cache responseForRequest:self]];
|
} else if ([self shouldDispatchRequest]) {
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if ([self shouldDispatchRequest]) {
|
|
||||||
#if TARGET_OS_IPHONE
|
#if TARGET_OS_IPHONE
|
||||||
// Background Request Policy support
|
// Background Request Policy support
|
||||||
UIApplication* app = [UIApplication sharedApplication];
|
UIApplication* app = [UIApplication sharedApplication];
|
||||||
@@ -327,7 +343,7 @@
|
|||||||
[self.cache hasResponseForRequest:self]) {
|
[self.cache hasResponseForRequest:self]) {
|
||||||
|
|
||||||
_isLoading = YES;
|
_isLoading = YES;
|
||||||
[self didFinishLoad:[self.cache responseForRequest:self]];
|
[self didFinishLoad:[self loadResponseFromCache]];
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
RKLogCritical(@"SharedClient = %@ and network availability = %d", [RKClient sharedClient], [[RKClient sharedClient] isNetworkAvailable]);
|
RKLogCritical(@"SharedClient = %@ and network availability = %d", [RKClient sharedClient], [[RKClient sharedClient] isNetworkAvailable]);
|
||||||
@@ -349,12 +365,16 @@
|
|||||||
RKResponse* response = nil;
|
RKResponse* response = nil;
|
||||||
_sentSynchronously = YES;
|
_sentSynchronously = YES;
|
||||||
|
|
||||||
if ([self shouldDispatchRequest]) {
|
if ([self shouldLoadFromCache]) {
|
||||||
RKLogDebug(@"Sending synchronous %@ request to URL %@.", [self HTTPMethod], [[self URL] absoluteString]);
|
response = [self loadResponseFromCache];
|
||||||
if (![self prepareURLRequest]) {
|
_isLoading = YES;
|
||||||
// TODO: Logging
|
[self didFinishLoad:response];
|
||||||
return nil;
|
} else if ([self shouldDispatchRequest]) {
|
||||||
}
|
RKLogDebug(@"Sending synchronous %@ request to URL %@.", [self HTTPMethod], [[self URL] absoluteString]);
|
||||||
|
if (![self prepareURLRequest]) {
|
||||||
|
// TODO: Logging
|
||||||
|
return nil;
|
||||||
|
}
|
||||||
|
|
||||||
[[NSNotificationCenter defaultCenter] postNotificationName:RKRequestSentNotification object:self userInfo:nil];
|
[[NSNotificationCenter defaultCenter] postNotificationName:RKRequestSentNotification object:self userInfo:nil];
|
||||||
|
|
||||||
@@ -378,7 +398,7 @@
|
|||||||
if (_cachePolicy & RKRequestCachePolicyLoadIfOffline &&
|
if (_cachePolicy & RKRequestCachePolicyLoadIfOffline &&
|
||||||
[self.cache hasResponseForRequest:self]) {
|
[self.cache hasResponseForRequest:self]) {
|
||||||
|
|
||||||
response = [self.cache responseForRequest:self];
|
response = [self loadResponseFromCache];
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
NSString* errorMessage = [NSString stringWithFormat:@"The client is unable to contact the resource at %@", [[self URL] absoluteString]];
|
NSString* errorMessage = [NSString stringWithFormat:@"The client is unable to contact the resource at %@", [[self URL] absoluteString]];
|
||||||
@@ -404,7 +424,7 @@
|
|||||||
if (_cachePolicy & RKRequestCachePolicyLoadOnError &&
|
if (_cachePolicy & RKRequestCachePolicyLoadOnError &&
|
||||||
[self.cache hasResponseForRequest:self]) {
|
[self.cache hasResponseForRequest:self]) {
|
||||||
|
|
||||||
[self didFinishLoad:[self.cache responseForRequest:self]];
|
[self didFinishLoad:[self loadResponseFromCache]];
|
||||||
} else {
|
} else {
|
||||||
_isLoading = NO;
|
_isLoading = NO;
|
||||||
|
|
||||||
@@ -429,7 +449,7 @@
|
|||||||
RKResponse* finalResponse = response;
|
RKResponse* finalResponse = response;
|
||||||
|
|
||||||
if ((_cachePolicy & RKRequestCachePolicyEtag) && [response isNotModified]) {
|
if ((_cachePolicy & RKRequestCachePolicyEtag) && [response isNotModified]) {
|
||||||
finalResponse = [self.cache responseForRequest:self];
|
finalResponse = [self loadResponseFromCache];
|
||||||
}
|
}
|
||||||
|
|
||||||
if (![response wasLoadedFromCache] && [response isSuccessful] && (_cachePolicy != RKRequestCachePolicyNone)) {
|
if (![response wasLoadedFromCache] && [response isSuccessful] && (_cachePolicy != RKRequestCachePolicyNone)) {
|
||||||
|
|||||||
@@ -48,6 +48,8 @@ typedef enum {
|
|||||||
|
|
||||||
- (NSString*)etagForRequest:(RKRequest*)request;
|
- (NSString*)etagForRequest:(RKRequest*)request;
|
||||||
|
|
||||||
|
- (NSDate*)cacheDateForRequest:(RKRequest*)request;
|
||||||
|
|
||||||
- (void)invalidateRequest:(RKRequest*)request;
|
- (void)invalidateRequest:(RKRequest*)request;
|
||||||
|
|
||||||
- (void)invalidateWithStoragePolicy:(RKRequestCacheStoragePolicy)storagePolicy;
|
- (void)invalidateWithStoragePolicy:(RKRequestCacheStoragePolicy)storagePolicy;
|
||||||
|
|||||||
@@ -245,6 +245,27 @@ static NSDateFormatter* __rfc1123DateFormatter;
|
|||||||
return etag;
|
return etag;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
- (NSDate*)cacheDateForRequest:(RKRequest*)request {
|
||||||
|
NSDate* date;
|
||||||
|
NSString* dateString;
|
||||||
|
|
||||||
|
NSDictionary* responseHeaders = [self headersForRequest:request];
|
||||||
|
|
||||||
|
[_cacheLock lock];
|
||||||
|
if (responseHeaders) {
|
||||||
|
for (NSString* responseHeader in responseHeaders) {
|
||||||
|
if ([[responseHeader uppercaseString] isEqualToString:[cacheDateHeaderKey uppercaseString]]) {
|
||||||
|
dateString = [responseHeaders objectForKey:responseHeader];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
[_cacheLock unlock];
|
||||||
|
date = [[RKRequestCache rfc1123DateFormatter] dateFromString:dateString];
|
||||||
|
|
||||||
|
RKLogDebug(@"Found cached date '%@' for '%@'", date, request);
|
||||||
|
return date;
|
||||||
|
}
|
||||||
|
|
||||||
- (void)invalidateRequest:(RKRequest*)request {
|
- (void)invalidateRequest:(RKRequest*)request {
|
||||||
[_cacheLock lock];
|
[_cacheLock lock];
|
||||||
RKLogDebug(@"Invalidating cache entry for '%@'", request);
|
RKLogDebug(@"Invalidating cache entry for '%@'", request);
|
||||||
|
|||||||
@@ -324,6 +324,72 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
- (void)itShouldLoadFromTheCacheIfWeAreWithinTheTimeout {
|
||||||
|
RKLogConfigureByName("RestKit/Network", RKLogLevelTrace);
|
||||||
|
|
||||||
|
NSString* baseURL = RKSpecGetBaseURL();
|
||||||
|
NSString* cacheDirForClient = [NSString stringWithFormat:@"RKClientRequestCache-%@",
|
||||||
|
[[NSURL URLWithString:baseURL] host]];
|
||||||
|
NSString* cachePath = [[NSSearchPathForDirectoriesInDomains(NSCachesDirectory, NSUserDomainMask, YES) objectAtIndex:0]
|
||||||
|
stringByAppendingPathComponent:cacheDirForClient];
|
||||||
|
RKRequestCache* cache = [[RKRequestCache alloc] initWithCachePath:cachePath
|
||||||
|
storagePolicy:RKRequestCacheStoragePolicyPermanently];
|
||||||
|
[cache invalidateWithStoragePolicy:RKRequestCacheStoragePolicyPermanently];
|
||||||
|
|
||||||
|
NSString* url = [NSString stringWithFormat:@"%@/disk/cached", RKSpecGetBaseURL()];
|
||||||
|
NSURL* URL = [NSURL URLWithString:url];
|
||||||
|
{
|
||||||
|
RKSpecResponseLoader* loader = [RKSpecResponseLoader responseLoader];
|
||||||
|
RKRequest* request = [[RKRequest alloc] initWithURL:URL];
|
||||||
|
request.cachePolicy = RKRequestCachePolicyTimeout;
|
||||||
|
request.cacheTimeoutInterval = 5;
|
||||||
|
request.cache = cache;
|
||||||
|
request.delegate = loader;
|
||||||
|
[request sendAsynchronously];
|
||||||
|
[loader waitForResponse];
|
||||||
|
[expectThat([loader success]) should:be(YES)];
|
||||||
|
[expectThat([loader.response bodyAsString]) should:be(@"This Should Get Cached For 5 Seconds")];
|
||||||
|
[expectThat([loader.response wasLoadedFromCache]) should:be(NO)];
|
||||||
|
}
|
||||||
|
{
|
||||||
|
RKSpecResponseLoader* loader = [RKSpecResponseLoader responseLoader];
|
||||||
|
RKRequest* request = [[RKRequest alloc] initWithURL:URL];
|
||||||
|
request.cachePolicy = RKRequestCachePolicyTimeout;
|
||||||
|
request.cacheTimeoutInterval = 5;
|
||||||
|
request.cache = cache;
|
||||||
|
request.delegate = loader;
|
||||||
|
[request sendAsynchronously];
|
||||||
|
// Don't wait for a response as this actually returns synchronously.
|
||||||
|
[expectThat([loader.response bodyAsString]) should:be(@"This Should Get Cached For 5 Seconds")];
|
||||||
|
[expectThat([loader.response wasLoadedFromCache]) should:be(YES)];
|
||||||
|
}
|
||||||
|
{
|
||||||
|
RKSpecResponseLoader* loader = [RKSpecResponseLoader responseLoader];
|
||||||
|
RKRequest* request = [[RKRequest alloc] initWithURL:URL];
|
||||||
|
request.cachePolicy = RKRequestCachePolicyTimeout;
|
||||||
|
request.cacheTimeoutInterval = 5;
|
||||||
|
request.cache = cache;
|
||||||
|
request.delegate = loader;
|
||||||
|
[request sendSynchronously];
|
||||||
|
// Don't wait for a response as this actually returns synchronously.
|
||||||
|
[expectThat([loader.response bodyAsString]) should:be(@"This Should Get Cached For 5 Seconds")];
|
||||||
|
[expectThat([loader.response wasLoadedFromCache]) should:be(YES)];
|
||||||
|
}
|
||||||
|
{
|
||||||
|
RKSpecResponseLoader* loader = [RKSpecResponseLoader responseLoader];
|
||||||
|
RKRequest* request = [[RKRequest alloc] initWithURL:URL];
|
||||||
|
request.cachePolicy = RKRequestCachePolicyTimeout;
|
||||||
|
request.cacheTimeoutInterval = 0;
|
||||||
|
request.cache = cache;
|
||||||
|
request.delegate = loader;
|
||||||
|
[request sendAsynchronously];
|
||||||
|
[loader waitForResponse];
|
||||||
|
[expectThat([loader success]) should:be(YES)];
|
||||||
|
[expectThat([loader.response bodyAsString]) should:be(@"This Should Get Cached For 5 Seconds")];
|
||||||
|
[expectThat([loader.response wasLoadedFromCache]) should:be(NO)];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
- (void)itShouldLoadFromTheCacheIfWeAreOffline {
|
- (void)itShouldLoadFromTheCacheIfWeAreOffline {
|
||||||
NSString* baseURL = RKSpecGetBaseURL();
|
NSString* baseURL = RKSpecGetBaseURL();
|
||||||
NSString* cacheDirForClient = [NSString stringWithFormat:@"RKClientRequestCache-%@",
|
NSString* cacheDirForClient = [NSString stringWithFormat:@"RKClientRequestCache-%@",
|
||||||
|
|||||||
@@ -11,11 +11,13 @@ Debugger.start
|
|||||||
$: << File.join(File.expand_path(File.dirname(__FILE__)), 'lib')
|
$: << File.join(File.expand_path(File.dirname(__FILE__)), 'lib')
|
||||||
require 'restkit/network/authentication'
|
require 'restkit/network/authentication'
|
||||||
require 'restkit/network/etags'
|
require 'restkit/network/etags'
|
||||||
|
require 'restkit/network/timeout'
|
||||||
|
|
||||||
class RestKit::SpecServer < Sinatra::Base
|
class RestKit::SpecServer < Sinatra::Base
|
||||||
self.app_file = __FILE__
|
self.app_file = __FILE__
|
||||||
use RestKit::Network::Authentication
|
use RestKit::Network::Authentication
|
||||||
use RestKit::Network::ETags
|
use RestKit::Network::ETags
|
||||||
|
use RestKit::Network::Timeout
|
||||||
|
|
||||||
configure do
|
configure do
|
||||||
set :logging, true
|
set :logging, true
|
||||||
|
|||||||
Reference in New Issue
Block a user