mirror of
https://github.com/zhigang1992/RestKit.git
synced 2026-04-23 12:27:52 +08:00
Improvements to reachability, the request queue, logging throughout the network layer, decoupling of components via notifications, reliability improvements for unit tests in the cache layer. Improved thread-local cleanup routines inside the managed object store. Changing base URL's is now more reliable. fixes #171, #158, #113, #104, #102
This commit is contained in:
@@ -231,6 +231,8 @@ NSString* RKPathAppendQueryParams(NSString* resourcePath, NSDictionary* queryPar
|
||||
|
||||
@property (nonatomic, assign) RKRequestCachePolicy cachePolicy;
|
||||
|
||||
@property (nonatomic, readonly) NSString* cachePath;
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////
|
||||
/// @name Shared Client Instance
|
||||
/////////////////////////////////////////////////////////////////////////
|
||||
|
||||
@@ -14,6 +14,10 @@
|
||||
#import "RKAlert.h"
|
||||
#import "RKLog.h"
|
||||
|
||||
// Set Logging Component
|
||||
#undef RKLogComponent
|
||||
#define RKLogComponent lcl_cRestKitNetwork
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
// Global
|
||||
|
||||
@@ -127,13 +131,7 @@ NSString* RKPathAppendQueryParams(NSString* resourcePath, NSDictionary* queryPar
|
||||
|
||||
- (id)initWithBaseURL:(NSString*)baseURL {
|
||||
self = [self init];
|
||||
if (self) {
|
||||
NSString* cacheDirForClient = [NSString stringWithFormat:@"RKClientRequestCache-%@",
|
||||
[[NSURL URLWithString:baseURL] host]];
|
||||
NSString* cachePath = [[NSSearchPathForDirectoriesInDomains(NSCachesDirectory, NSUserDomainMask, YES) objectAtIndex:0]
|
||||
stringByAppendingPathComponent:cacheDirForClient];
|
||||
_cache = [[RKRequestCache alloc] initWithCachePath:cachePath
|
||||
storagePolicy:RKRequestCacheStoragePolicyPermanently];
|
||||
if (self) {
|
||||
self.cachePolicy = RKRequestCachePolicyDefault;
|
||||
self.baseURL = baseURL;
|
||||
|
||||
@@ -156,18 +154,25 @@ NSString* RKPathAppendQueryParams(NSString* resourcePath, NSDictionary* queryPar
|
||||
self.serviceUnavailableAlertMessage = nil;
|
||||
self.cache = nil;
|
||||
[_HTTPHeaders release];
|
||||
[_baseURLReachabilityObserver release];
|
||||
|
||||
[super dealloc];
|
||||
}
|
||||
|
||||
- (NSString*)cachePath {
|
||||
NSString* cacheDirForClient = [NSString stringWithFormat:@"RKClientRequestCache-%@",
|
||||
[[NSURL URLWithString:self.baseURL] host]];
|
||||
NSString* cachePath = [[NSSearchPathForDirectoriesInDomains(NSCachesDirectory, NSUserDomainMask, YES) objectAtIndex:0]
|
||||
stringByAppendingPathComponent:cacheDirForClient];
|
||||
return cachePath;
|
||||
}
|
||||
|
||||
- (BOOL)isNetworkAvailable {
|
||||
BOOL isNetworkAvailable = NO;
|
||||
if (self.baseURLReachabilityObserver) {
|
||||
isNetworkAvailable = [self.baseURLReachabilityObserver isNetworkReachable];
|
||||
} else {
|
||||
RKReachabilityObserver* googleObserver = [RKReachabilityObserver reachabilityObserverWithHostName:@"google.com"];
|
||||
isNetworkAvailable = [googleObserver isNetworkReachable];
|
||||
}
|
||||
|
||||
return isNetworkAvailable;
|
||||
}
|
||||
|
||||
@@ -204,14 +209,29 @@ NSString* RKPathAppendQueryParams(NSString* resourcePath, NSDictionary* queryPar
|
||||
[_baseURL release];
|
||||
_baseURL = nil;
|
||||
_baseURL = [baseURL retain];
|
||||
|
||||
|
||||
[_baseURLReachabilityObserver release];
|
||||
_baseURLReachabilityObserver = nil;
|
||||
|
||||
// Don't crash if baseURL is nil'd out (i.e. dealloc)
|
||||
if (baseURL) {
|
||||
// Configure a cache for the new base URL
|
||||
[_cache release];
|
||||
_cache = [[RKRequestCache alloc] initWithCachePath:[self cachePath]
|
||||
storagePolicy:RKRequestCacheStoragePolicyPermanently];
|
||||
|
||||
// Configure a new reachability observer
|
||||
NSURL* URL = [NSURL URLWithString:baseURL];
|
||||
_baseURLReachabilityObserver = [[RKReachabilityObserver reachabilityObserverWithHostName:[URL host]] retain];
|
||||
_baseURLReachabilityObserver = [[RKReachabilityObserver alloc] initWithHostname:[URL host]];
|
||||
|
||||
// Suspend the queue until reachability to our new hostname is established
|
||||
[RKRequestQueue sharedQueue].suspended = YES;
|
||||
[[NSNotificationCenter defaultCenter] addObserver:self
|
||||
selector:@selector(reachabilityWasDetermined:)
|
||||
name:RKReachabilityStateWasDeterminedNotification
|
||||
object:_baseURLReachabilityObserver];
|
||||
RKLogDebug(@"Base URL changed for client %@, suspending main queue until reachability to host '%@' can be determined",
|
||||
self, [URL host]);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -265,4 +285,13 @@ NSString* RKPathAppendQueryParams(NSString* resourcePath, NSDictionary* queryPar
|
||||
}
|
||||
}
|
||||
|
||||
- (void)reachabilityWasDetermined:(NSNotification*)notification {
|
||||
RKReachabilityObserver* observer = (RKReachabilityObserver*) [notification object];
|
||||
NSAssert(observer == _baseURLReachabilityObserver, @"Received unexpected reachability notification from inappropriate reachability observer");
|
||||
|
||||
RKLogDebug(@"Reachability to host '%@' determined for client %@, unsuspending main queue", observer.hostName, self);
|
||||
[RKRequestQueue sharedQueue].suspended = NO;
|
||||
[[NSNotificationCenter defaultCenter] removeObserver:self name:RKReachabilityStateWasDeterminedNotification object:observer];
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
@@ -13,6 +13,7 @@
|
||||
* Posted when the network state has changed
|
||||
*/
|
||||
extern NSString* const RKReachabilityStateChangedNotification;
|
||||
extern NSString* const RKReachabilityStateWasDeterminedNotification;
|
||||
|
||||
typedef enum {
|
||||
RKReachabilityIndeterminate,
|
||||
@@ -29,9 +30,16 @@ typedef enum {
|
||||
* code sample: http://developer.apple.com/library/ios/#samplecode/Reachability/Listings/Classes_Reachability_m.html
|
||||
*/
|
||||
@interface RKReachabilityObserver : NSObject {
|
||||
SCNetworkReachabilityRef _reachabilityRef;
|
||||
NSString* _hostName;
|
||||
SCNetworkReachabilityRef _reachabilityRef;
|
||||
BOOL _reachabilityEstablished;
|
||||
}
|
||||
|
||||
/**
|
||||
The hostname we are observing reachability to
|
||||
*/
|
||||
@property (nonatomic, readonly) NSString* hostName;
|
||||
|
||||
/**
|
||||
* Create a new reachability observer against a given hostname. The observer
|
||||
* will monitor the ability to reach the specified hostname and emit notifications
|
||||
@@ -39,7 +47,7 @@ typedef enum {
|
||||
*
|
||||
* Note that the observer will be scheduled in the current run loop.
|
||||
*/
|
||||
+ (RKReachabilityObserver*)reachabilityObserverWithHostName:(NSString*)hostName;
|
||||
- (id)initWithHostname:(NSString*)hostName;
|
||||
|
||||
/**
|
||||
* Returns the current network status
|
||||
|
||||
@@ -13,15 +13,26 @@
|
||||
#import "RKReachabilityObserver.h"
|
||||
#include <netdb.h>
|
||||
#include <arpa/inet.h>
|
||||
#import "RKLog.h"
|
||||
#import "../Support/RKLog.h"
|
||||
|
||||
// Set Logging Component
|
||||
#undef RKLogComponent
|
||||
#define RKLogComponent lcl_cRestKitNetworkReachability
|
||||
|
||||
@interface RKReachabilityObserver (Private)
|
||||
|
||||
@property (nonatomic, assign) BOOL reachabilityEstablished;
|
||||
|
||||
// Internal initializer
|
||||
- (id)initWithReachabilityRef:(SCNetworkReachabilityRef)reachabilityRef;
|
||||
- (void)scheduleObserver;
|
||||
- (void)unscheduleObserver;
|
||||
|
||||
@end
|
||||
|
||||
// Constants
|
||||
NSString* const RKReachabilityStateChangedNotification = @"RKReachabilityStateChangedNotification";
|
||||
static bool hasNetworkAvailabilityBeenDetermined = NO;
|
||||
NSString* const RKReachabilityStateWasDeterminedNotification = @"RKReachabilityStateWasDeterminedNotification";
|
||||
|
||||
static void ReachabilityCallback(SCNetworkReachabilityRef target, SCNetworkReachabilityFlags flags, void* info) {
|
||||
#pragma unused (target, flags)
|
||||
@@ -31,7 +42,11 @@ static void ReachabilityCallback(SCNetworkReachabilityRef target, SCNetworkReach
|
||||
|
||||
RKReachabilityObserver* observer = (RKReachabilityObserver*) info;
|
||||
|
||||
hasNetworkAvailabilityBeenDetermined = YES;
|
||||
if (!observer.reachabilityEstablished) {
|
||||
RKLogInfo(@"Network availability has been determined for reachability observer %@", observer);
|
||||
observer.reachabilityEstablished = YES;
|
||||
[[NSNotificationCenter defaultCenter] postNotificationName:RKReachabilityStateWasDeterminedNotification object:observer];
|
||||
}
|
||||
|
||||
// Post a notification to notify the client that the network reachability changed.
|
||||
[[NSNotificationCenter defaultCenter] postNotificationName:RKReachabilityStateChangedNotification object:observer];
|
||||
@@ -41,66 +56,62 @@ static void ReachabilityCallback(SCNetworkReachabilityRef target, SCNetworkReach
|
||||
|
||||
#pragma mark -
|
||||
|
||||
@interface RKReachabilityObserver (Private)
|
||||
|
||||
// Internal initializer
|
||||
- (id)initWithReachabilityRef:(SCNetworkReachabilityRef)reachabilityRef;
|
||||
- (void)scheduleObserver;
|
||||
- (void)unscheduleObserver;
|
||||
|
||||
@end
|
||||
|
||||
@implementation RKReachabilityObserver
|
||||
|
||||
+ (RKReachabilityObserver*)reachabilityObserverWithHostName:(NSString*)hostName {
|
||||
RKReachabilityObserver* observer = nil;
|
||||
SCNetworkReachabilityRef reachabilityRef;
|
||||
|
||||
// Try to determine if we have an IP address or a hostname
|
||||
struct sockaddr_in sa;
|
||||
char* hostNameOrIPAddress = (char*) [hostName UTF8String];
|
||||
int result = inet_pton(AF_INET, hostNameOrIPAddress, &(sa.sin_addr));
|
||||
|
||||
if (result != 0) {
|
||||
// IP Address
|
||||
struct sockaddr_in remote_saddr;
|
||||
|
||||
bzero(&remote_saddr, sizeof(struct sockaddr_in));
|
||||
remote_saddr.sin_len = sizeof(struct sockaddr_in);
|
||||
remote_saddr.sin_family = AF_INET;
|
||||
inet_aton(hostNameOrIPAddress, &(remote_saddr.sin_addr));
|
||||
|
||||
reachabilityRef = SCNetworkReachabilityCreateWithAddress(CFAllocatorGetDefault(), (struct sockaddr*)&remote_saddr);
|
||||
|
||||
// We can immediately determine reachability to an IP address
|
||||
hasNetworkAvailabilityBeenDetermined = YES;
|
||||
} else {
|
||||
// Hostname
|
||||
reachabilityRef = SCNetworkReachabilityCreateWithName(CFAllocatorGetDefault(), hostNameOrIPAddress);
|
||||
}
|
||||
|
||||
if (nil != reachabilityRef) {
|
||||
observer = [[[self alloc] initWithReachabilityRef:reachabilityRef] autorelease];
|
||||
}
|
||||
return observer;
|
||||
}
|
||||
@synthesize hostName = _hostName;
|
||||
|
||||
- (id)initWithReachabilityRef:(SCNetworkReachabilityRef)reachabilityRef {
|
||||
self = [self init];
|
||||
if (self) {
|
||||
_reachabilityRef = reachabilityRef;
|
||||
[self scheduleObserver];
|
||||
}
|
||||
return self;
|
||||
- (id)initWithHostname:(NSString*)hostName {
|
||||
self = [self init];
|
||||
if (self) {
|
||||
_hostName = [hostName retain];
|
||||
|
||||
// Try to determine if we have an IP address or a hostname
|
||||
struct sockaddr_in sa;
|
||||
char* hostNameOrIPAddress = (char*) [hostName UTF8String];
|
||||
int result = inet_pton(AF_INET, hostNameOrIPAddress, &(sa.sin_addr));
|
||||
|
||||
if (result != 0) {
|
||||
// IP Address
|
||||
struct sockaddr_in remote_saddr;
|
||||
|
||||
bzero(&remote_saddr, sizeof(struct sockaddr_in));
|
||||
remote_saddr.sin_len = sizeof(struct sockaddr_in);
|
||||
remote_saddr.sin_family = AF_INET;
|
||||
inet_aton(hostNameOrIPAddress, &(remote_saddr.sin_addr));
|
||||
|
||||
_reachabilityRef = SCNetworkReachabilityCreateWithAddress(CFAllocatorGetDefault(), (struct sockaddr*)&remote_saddr);
|
||||
|
||||
// We can immediately determine reachability to an IP address
|
||||
_reachabilityEstablished = YES;
|
||||
|
||||
RKLogInfo(@"Reachability observer initialized with IP address %@.", hostName);
|
||||
RKLogDebug(@"Reachability observer initialized with IP address, automatically marking reachability as determined.");
|
||||
} else {
|
||||
// Hostname
|
||||
_reachabilityRef = SCNetworkReachabilityCreateWithName(CFAllocatorGetDefault(), hostNameOrIPAddress);
|
||||
RKLogInfo(@"Reachability observer initialized with hostname %@", hostName);
|
||||
}
|
||||
|
||||
if (_reachabilityRef) {
|
||||
[self scheduleObserver];
|
||||
} else {
|
||||
RKLogWarning(@"Unable to initialize reachability reference");
|
||||
}
|
||||
}
|
||||
|
||||
return self;
|
||||
}
|
||||
|
||||
- (void)dealloc {
|
||||
[[NSNotificationCenter defaultCenter] removeObserver:self];
|
||||
[self unscheduleObserver];
|
||||
if (_reachabilityRef) {
|
||||
CFRelease(_reachabilityRef);
|
||||
}
|
||||
[super dealloc];
|
||||
RKLogTrace(@"Deallocating reachability observer %@", self);
|
||||
|
||||
[[NSNotificationCenter defaultCenter] removeObserver:self];
|
||||
[self unscheduleObserver];
|
||||
if (_reachabilityRef) {
|
||||
CFRelease(_reachabilityRef);
|
||||
}
|
||||
|
||||
[super dealloc];
|
||||
}
|
||||
|
||||
- (RKReachabilityNetworkStatus)networkStatus {
|
||||
@@ -108,21 +119,36 @@ static void ReachabilityCallback(SCNetworkReachabilityRef target, SCNetworkReach
|
||||
RKReachabilityNetworkStatus status = RKReachabilityNotReachable;
|
||||
SCNetworkReachabilityFlags flags;
|
||||
|
||||
if (!hasNetworkAvailabilityBeenDetermined) {
|
||||
if (!self.reachabilityEstablished) {
|
||||
RKLogTrace(@"Reachability observer %@ has not yet established reachability. networkStatus = %@", self, @"RKReachabilityIndeterminate");
|
||||
return RKReachabilityIndeterminate;
|
||||
}
|
||||
|
||||
|
||||
if (SCNetworkReachabilityGetFlags(_reachabilityRef, &flags)) {
|
||||
if (SCNetworkReachabilityGetFlags(_reachabilityRef, &flags)) {
|
||||
RKLogTrace(@"Reachability Flag Status: %c%c %c%c%c%c%c%c%c \n",
|
||||
(flags & kSCNetworkReachabilityFlagsIsWWAN) ? 'W' : '-',
|
||||
(flags & kSCNetworkReachabilityFlagsReachable) ? 'R' : '-',
|
||||
(flags & kSCNetworkReachabilityFlagsTransientConnection) ? 't' : '-',
|
||||
(flags & kSCNetworkReachabilityFlagsConnectionRequired) ? 'c' : '-',
|
||||
(flags & kSCNetworkReachabilityFlagsConnectionOnTraffic) ? 'C' : '-',
|
||||
(flags & kSCNetworkReachabilityFlagsInterventionRequired) ? 'i' : '-',
|
||||
(flags & kSCNetworkReachabilityFlagsConnectionOnDemand) ? 'D' : '-',
|
||||
(flags & kSCNetworkReachabilityFlagsIsLocalAddress) ? 'l' : '-',
|
||||
(flags & kSCNetworkReachabilityFlagsIsDirect) ? 'd' : '-'
|
||||
);
|
||||
|
||||
if ((flags & kSCNetworkReachabilityFlagsReachable) == 0) {
|
||||
// if target host is not reachable
|
||||
RKLogTrace(@"Reachability observer %@ determined networkStatus = %@", self, @"RKReachabilityNotReachable");
|
||||
return RKReachabilityNotReachable;
|
||||
}
|
||||
|
||||
if ((flags & kSCNetworkReachabilityFlagsConnectionRequired) == 0) {
|
||||
// if target host is reachable and no connection is required
|
||||
// then we'll assume (for now) that your on Wi-Fi
|
||||
status = RKReachabilityReachableViaWiFi;
|
||||
RKLogTrace(@"Reachability observer %@ determined networkStatus = %@", self, @"RKReachabilityReachableViaWiFi");
|
||||
status = RKReachabilityReachableViaWiFi;
|
||||
}
|
||||
|
||||
|
||||
@@ -134,6 +160,7 @@ static void ReachabilityCallback(SCNetworkReachabilityRef target, SCNetworkReach
|
||||
if ((flags & kSCNetworkReachabilityFlagsInterventionRequired) == 0) {
|
||||
// ... and no [user] intervention is needed
|
||||
status = RKReachabilityReachableViaWiFi;
|
||||
RKLogTrace(@"Reachability observer %@ determined networkStatus = %@", self, @"RKReachabilityReachableViaWiFi");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -142,6 +169,7 @@ static void ReachabilityCallback(SCNetworkReachabilityRef target, SCNetworkReach
|
||||
// ... but WWAN connections are OK if the calling application
|
||||
// is using the CFNetwork (CFSocketStream?) APIs.
|
||||
status = RKReachabilityReachableViaWWAN;
|
||||
RKLogTrace(@"Reachability observer %@ determined networkStatus = %@", self, @"RKReachabilityReachableViaWWAN");
|
||||
}
|
||||
#endif
|
||||
}
|
||||
@@ -150,16 +178,21 @@ static void ReachabilityCallback(SCNetworkReachabilityRef target, SCNetworkReach
|
||||
}
|
||||
|
||||
- (BOOL)isNetworkReachable {
|
||||
return (RKReachabilityNotReachable != [self networkStatus]);
|
||||
BOOL reachable = (RKReachabilityNotReachable != [self networkStatus]);
|
||||
RKLogDebug(@"Reachability observer %@ determined isNetworkReachable = %d", self, reachable);
|
||||
return reachable;
|
||||
}
|
||||
|
||||
- (BOOL)isConnectionRequired {
|
||||
NSAssert(_reachabilityRef != NULL, @"connectionRequired called with NULL reachabilityRef");
|
||||
SCNetworkReachabilityFlags flags;
|
||||
BOOL required = NO;
|
||||
if (SCNetworkReachabilityGetFlags(_reachabilityRef, &flags)) {
|
||||
return (flags & kSCNetworkReachabilityFlagsConnectionRequired);
|
||||
required = (flags & kSCNetworkReachabilityFlagsConnectionRequired);
|
||||
}
|
||||
return NO;
|
||||
|
||||
RKLogDebug(@"Reachability observer %@ determined isConnectionRequired = %d", self, required);
|
||||
return required;
|
||||
}
|
||||
|
||||
#pragma mark Observer scheduling
|
||||
@@ -167,16 +200,28 @@ static void ReachabilityCallback(SCNetworkReachabilityRef target, SCNetworkReach
|
||||
- (void)scheduleObserver {
|
||||
SCNetworkReachabilityContext context = {0, self, NULL, NULL, NULL};
|
||||
if (SCNetworkReachabilitySetCallback(_reachabilityRef, ReachabilityCallback, &context)) {
|
||||
RKLogDebug(@"Scheduling reachability observer %@ in current run loop", self);
|
||||
if (NO == SCNetworkReachabilityScheduleWithRunLoop(_reachabilityRef, CFRunLoopGetCurrent(), kCFRunLoopDefaultMode)) {
|
||||
RKLogWarning(@"Warning -- Unable to schedule reachability observer in current run loop.");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
- (void)unscheduleObserver {
|
||||
if (nil != _reachabilityRef) {
|
||||
- (void)unscheduleObserver {
|
||||
if (_reachabilityRef) {
|
||||
RKLogDebug(@"Unscheduling reachability observer %@ from current run loop", self);
|
||||
SCNetworkReachabilityUnscheduleFromRunLoop(_reachabilityRef, CFRunLoopGetCurrent(), kCFRunLoopDefaultMode);
|
||||
}
|
||||
} else {
|
||||
RKLogDebug(@"Failed to unschedule reachability observer %@: reachability reference is nil.", _reachabilityRef);
|
||||
}
|
||||
}
|
||||
|
||||
- (BOOL)reachabilityEstablished {
|
||||
return _reachabilityEstablished;
|
||||
}
|
||||
|
||||
- (void)setReachabilityEstablished:(BOOL)reachabilityEstablished {
|
||||
_reachabilityEstablished = reachabilityEstablished;
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
@@ -281,6 +281,11 @@ typedef enum RKRequestBackgroundPolicy {
|
||||
*/
|
||||
- (BOOL)isLoaded;
|
||||
|
||||
/**
|
||||
* Returnes YES when this request has not yet been sent
|
||||
*/
|
||||
- (BOOL)isUnsent;
|
||||
|
||||
/**
|
||||
* Returns YES when the request was sent to the specified resource path
|
||||
*/
|
||||
|
||||
@@ -470,6 +470,10 @@
|
||||
return _isLoaded;
|
||||
}
|
||||
|
||||
- (BOOL)isUnsent {
|
||||
return _isLoading == NO && _isLoaded == NO;
|
||||
}
|
||||
|
||||
- (NSString*)resourcePath {
|
||||
NSString* resourcePath = nil;
|
||||
if ([self.URL isKindOfClass:[RKURL class]]) {
|
||||
|
||||
@@ -37,11 +37,12 @@ static NSDateFormatter* __rfc1123DateFormatter;
|
||||
}
|
||||
|
||||
- (id)initWithCachePath:(NSString*)cachePath storagePolicy:(RKRequestCacheStoragePolicy)storagePolicy {
|
||||
if ((self = [super init])) {
|
||||
self = [super init];
|
||||
if (self) {
|
||||
_cachePath = [cachePath copy];
|
||||
_cacheLock = [[NSRecursiveLock alloc] init];
|
||||
|
||||
NSFileManager* fileManager = [[NSFileManager alloc] init];
|
||||
NSFileManager* fileManager = [NSFileManager defaultManager];
|
||||
NSArray* pathArray = [NSArray arrayWithObjects:
|
||||
_cachePath,
|
||||
[_cachePath stringByAppendingPathComponent:sessionCacheFolder],
|
||||
@@ -62,8 +63,10 @@ static NSDateFormatter* __rfc1123DateFormatter;
|
||||
} else {
|
||||
RKLogDebug(@"Created cache storage at path '%@'", path);
|
||||
}
|
||||
} else if (!isDirectory) {
|
||||
RKLogWarning(@"Failed to create cache directory: Directory already exists: %@", path);
|
||||
} else {
|
||||
if (!isDirectory) {
|
||||
RKLogWarning(@"Skipped creation of cache directory as non-directory file exists at path: %@", path);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -71,6 +74,7 @@ static NSDateFormatter* __rfc1123DateFormatter;
|
||||
|
||||
self.storagePolicy = storagePolicy;
|
||||
}
|
||||
|
||||
return self;
|
||||
}
|
||||
|
||||
@@ -110,7 +114,7 @@ static NSDateFormatter* __rfc1123DateFormatter;
|
||||
[_cacheLock lock];
|
||||
|
||||
BOOL hasEntryForRequest = NO;
|
||||
NSFileManager* fileManager = [[NSFileManager alloc] init];
|
||||
NSFileManager* fileManager = [NSFileManager defaultManager];
|
||||
|
||||
NSString* cachePath = [self pathForRequest:request];
|
||||
hasEntryForRequest = ([fileManager fileExistsAtPath:cachePath] &&
|
||||
@@ -136,12 +140,12 @@ static NSDateFormatter* __rfc1123DateFormatter;
|
||||
if (cachePath) {
|
||||
NSData* body = response.body;
|
||||
if (body) {
|
||||
BOOL success = [body writeToFile:cachePath atomically:NO];
|
||||
NSError* error = nil;
|
||||
BOOL success = [body writeToFile:cachePath options:NSDataWritingAtomic error:&error];
|
||||
if (success) {
|
||||
RKLogTrace(@"Wrote cached response body to path '%@'", cachePath);
|
||||
|
||||
RKLogTrace(@"Wrote cached response body to path '%@'", cachePath);
|
||||
} else {
|
||||
RKLogError(@"Failed to write cached response body to path '%@'", cachePath);
|
||||
RKLogError(@"Failed to write cached response body to path '%@': %@", cachePath, [error localizedDescription]);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -247,7 +251,7 @@ static NSDateFormatter* __rfc1123DateFormatter;
|
||||
|
||||
NSString* cachePath = [self pathForRequest:request];
|
||||
if (cachePath) {
|
||||
NSFileManager* fileManager = [[NSFileManager alloc] init];
|
||||
NSFileManager* fileManager = [NSFileManager defaultManager];
|
||||
[fileManager removeItemAtPath:cachePath error:NULL];
|
||||
[fileManager removeItemAtPath:[cachePath stringByAppendingPathExtension:headersExtension]
|
||||
error:NULL];
|
||||
@@ -270,7 +274,7 @@ static NSDateFormatter* __rfc1123DateFormatter;
|
||||
}
|
||||
|
||||
RKLogInfo(@"Invalidating cache at path: %@", cachePath);
|
||||
NSFileManager* fileManager = [[NSFileManager alloc] init];
|
||||
NSFileManager* fileManager = [NSFileManager defaultManager];
|
||||
|
||||
BOOL isDirectory = NO;
|
||||
BOOL fileExists = [fileManager fileExistsAtPath:cachePath isDirectory:&isDirectory];
|
||||
|
||||
@@ -13,7 +13,6 @@
|
||||
#import "RKRequestQueue.h"
|
||||
#import "RKResponse.h"
|
||||
#import "RKNotifications.h"
|
||||
#import "RKClient.h"
|
||||
#import "../Support/RKLog.h"
|
||||
|
||||
static RKRequestQueue* gSharedQueue = nil;
|
||||
@@ -67,15 +66,7 @@ static const NSTimeInterval kFlushDelay = 0.3;
|
||||
_concurrentRequestsLimit = 5;
|
||||
_requestTimeout = 300;
|
||||
_showsNetworkActivityIndicatorWhenBusy = NO;
|
||||
|
||||
[[NSNotificationCenter defaultCenter] addObserver:self
|
||||
selector:@selector(responseDidLoad:)
|
||||
name:RKResponseReceivedNotification
|
||||
object:nil];
|
||||
[[NSNotificationCenter defaultCenter] addObserver:self
|
||||
selector:@selector(responseDidLoad:)
|
||||
name:RKRequestFailedWithErrorNotification
|
||||
object:nil];
|
||||
|
||||
#if TARGET_OS_IPHONE
|
||||
BOOL backgroundOK = &UIApplicationDidEnterBackgroundNotification != NULL;
|
||||
if (backgroundOK) {
|
||||
@@ -152,14 +143,24 @@ static const NSTimeInterval kFlushDelay = 0.3;
|
||||
}
|
||||
}
|
||||
|
||||
- (RKRequest*)nextRequest {
|
||||
for (NSUInteger i = 0; i < [_requests count]; i++) {
|
||||
RKRequest* request = [_requests objectAtIndex:i];
|
||||
if ([request isUnsent]) {
|
||||
return request;
|
||||
}
|
||||
}
|
||||
|
||||
return nil;
|
||||
}
|
||||
|
||||
- (void)loadNextInQueue {
|
||||
// This makes sure that the Request Queue does not fire off any requests until the Reachability state has been determined.
|
||||
if ([[[RKClient sharedClient] baseURLReachabilityObserver] networkStatus] == RKReachabilityIndeterminate ||
|
||||
self.suspended) {
|
||||
if (self.suspended) {
|
||||
_queueTimer = nil;
|
||||
[self loadNextInQueueDelayed];
|
||||
|
||||
RKLogTrace(@"Deferring queue loading because of %@", self.suspended ? @"queue suspension" : @"indeterminate network condition");
|
||||
RKLogTrace(@"Deferring request loading for queue %@ due to suspension", self);
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -167,32 +168,22 @@ static const NSTimeInterval kFlushDelay = 0.3;
|
||||
|
||||
_queueTimer = nil;
|
||||
|
||||
NSUInteger initialCount = [_requests count];
|
||||
NSUInteger requestsDequeued = 0;
|
||||
while ([_requests count] > 0 && requestsDequeued < initialCount) {
|
||||
RKRequest* request = [_requests objectAtIndex:0];
|
||||
requestsDequeued++;
|
||||
RKRequest* request = [self nextRequest];
|
||||
while (request && self.loadingCount < _concurrentRequestsLimit) {
|
||||
RKLogTrace(@"Processing request %@ in queue %@", request, self);
|
||||
if ([_delegate respondsToSelector:@selector(requestQueue:willSendRequest:)]) {
|
||||
[_delegate requestQueue:self willSendRequest:request];
|
||||
}
|
||||
|
||||
if ([request isLoading]) {
|
||||
RKLogTrace(@"Skipping request %@: currently loading.", request);
|
||||
} else if ([request isLoaded]) {
|
||||
RKLogTrace(@"Skipping request %@: already loaded.", request);
|
||||
} else if (self.loadingCount > _concurrentRequestsLimit) {
|
||||
RKLogTrace(@"Skipping request %@: Maximum concurrent request limit of %d is reached", request, self.loadingCount);
|
||||
} else {
|
||||
if ([_delegate respondsToSelector:@selector(requestQueue:willSendRequest:)]) {
|
||||
[_delegate requestQueue:self willSendRequest:request];
|
||||
}
|
||||
|
||||
self.loadingCount = self.loadingCount + 1;
|
||||
[request sendAsynchronously];
|
||||
RKLogDebug(@"Sent request %@ from top of queue %@. Loading count = %d", request, self, self.loadingCount);
|
||||
self.loadingCount = self.loadingCount + 1;
|
||||
[request sendAsynchronously];
|
||||
RKLogDebug(@"Sent request %@ from queue %@. Loading count = %d of %d", request, self, self.loadingCount, _concurrentRequestsLimit);
|
||||
|
||||
if ([_delegate respondsToSelector:@selector(requestQueue:didSendRequest:)]) {
|
||||
[_delegate requestQueue:self didSendRequest:request];
|
||||
}
|
||||
}
|
||||
if ([_delegate respondsToSelector:@selector(requestQueue:didSendRequest:)]) {
|
||||
[_delegate requestQueue:self didSendRequest:request];
|
||||
}
|
||||
|
||||
request = [self nextRequest];
|
||||
}
|
||||
|
||||
if (_requests.count && !_suspended) {
|
||||
@@ -235,9 +226,38 @@ static const NSTimeInterval kFlushDelay = 0.3;
|
||||
RKLogTrace(@"Request %@ added to queue %@", request, self);
|
||||
|
||||
[_requests addObject:request];
|
||||
|
||||
[[NSNotificationCenter defaultCenter] addObserver:self
|
||||
selector:@selector(responseDidLoad:)
|
||||
name:RKResponseReceivedNotification
|
||||
object:request];
|
||||
[[NSNotificationCenter defaultCenter] addObserver:self
|
||||
selector:@selector(responseDidLoad:)
|
||||
name:RKRequestFailedWithErrorNotification
|
||||
object:request];
|
||||
|
||||
[self loadNextInQueue];
|
||||
}
|
||||
|
||||
- (BOOL)removeRequest:(RKRequest*)request decrementCounter:(BOOL)decrementCounter {
|
||||
if ([self containsRequest:request]) {
|
||||
RKLogTrace(@"Removing request %@ from queue %@", request, self);
|
||||
[_requests removeObject:request];
|
||||
|
||||
[[NSNotificationCenter defaultCenter] removeObserver:self name:RKResponseReceivedNotification object:request];
|
||||
[[NSNotificationCenter defaultCenter] removeObserver:self name:RKRequestFailedWithErrorNotification object:request];
|
||||
|
||||
if (decrementCounter) {
|
||||
self.loadingCount = self.loadingCount - 1;
|
||||
RKLogTrace(@"Decremented the loading count to %d", self.loadingCount);
|
||||
}
|
||||
return YES;
|
||||
}
|
||||
|
||||
RKLogWarning(@"Failed to remove request %@ from queue %@: it is not in the queue.", request, self);
|
||||
return NO;
|
||||
}
|
||||
|
||||
- (BOOL)containsRequest:(RKRequest*)request {
|
||||
return [_requests containsObject:request];
|
||||
}
|
||||
@@ -246,7 +266,8 @@ static const NSTimeInterval kFlushDelay = 0.3;
|
||||
if (![request isLoading]) {
|
||||
RKLogDebug(@"Canceled undispatched request %@ and removed from queue %@", request, self);
|
||||
|
||||
[_requests removeObject:request];
|
||||
// Do not decrement counter
|
||||
[self removeRequest:request decrementCounter:NO];
|
||||
request.delegate = nil;
|
||||
|
||||
if ([_delegate respondsToSelector:@selector(requestQueue:didCancelRequest:)]) {
|
||||
@@ -261,9 +282,9 @@ static const NSTimeInterval kFlushDelay = 0.3;
|
||||
if ([_delegate respondsToSelector:@selector(requestQueue:didCancelRequest:)]) {
|
||||
[_delegate requestQueue:self didCancelRequest:request];
|
||||
}
|
||||
|
||||
[_requests removeObject:request];
|
||||
self.loadingCount = self.loadingCount - 1;
|
||||
|
||||
// Decrement the counter
|
||||
[self removeRequest:request decrementCounter:YES];
|
||||
|
||||
if (loadNext) {
|
||||
[self loadNextInQueue];
|
||||
@@ -324,8 +345,8 @@ static const NSTimeInterval kFlushDelay = 0.3;
|
||||
if ([notification.object isKindOfClass:[RKResponse class]]) {
|
||||
RKLogTrace(@"Received response for request %@, removing from queue.", request);
|
||||
|
||||
[_requests removeObject:request];
|
||||
self.loadingCount = self.loadingCount - 1;
|
||||
// Decrement the counter
|
||||
[self removeRequest:request decrementCounter:YES];
|
||||
|
||||
if ([_delegate respondsToSelector:@selector(requestQueue:didLoadResponse:)]) {
|
||||
[_delegate requestQueue:self didLoadResponse:(RKResponse*)notification.object];
|
||||
@@ -335,8 +356,8 @@ static const NSTimeInterval kFlushDelay = 0.3;
|
||||
} else if ([notification.object isKindOfClass:[RKRequest class]]) {
|
||||
RKLogTrace(@"Received failure notification for request %@, removing from queue.", request);
|
||||
|
||||
[_requests removeObject:request];
|
||||
self.loadingCount = self.loadingCount - 1;
|
||||
// Decrement the counter
|
||||
[self removeRequest:request decrementCounter:YES];
|
||||
|
||||
NSDictionary* userInfo = [notification userInfo];
|
||||
NSError* error = nil;
|
||||
|
||||
Reference in New Issue
Block a user