mirror of
https://github.com/zhigang1992/RestKit.git
synced 2026-04-23 04:20:21 +08:00
Merge branch 'reachability-queue-three20'
Conflicts: Code/Network/RKResponse.m
This commit is contained in:
@@ -88,7 +88,7 @@
|
||||
+ (id)object;
|
||||
|
||||
/**
|
||||
* The name of an object mapped property existing on this classs representing the unique primary key.
|
||||
* The name of an object mapped property existing on this class representing the unique primary key.
|
||||
* Must be implemented by the subclass for the mapper to be able to uniquely identify objects.
|
||||
*/
|
||||
+ (NSString*)primaryKeyProperty;
|
||||
|
||||
@@ -10,3 +10,5 @@
|
||||
#import "RKRequest.h"
|
||||
#import "RKResponse.h"
|
||||
#import "RKRequestSerializable.h"
|
||||
#import "RKReachabilityObserver.h"
|
||||
#import "RKRequestQueue.h"
|
||||
|
||||
@@ -10,6 +10,7 @@
|
||||
#import "RKParams.h"
|
||||
#import "RKResponse.h"
|
||||
#import "NSDictionary+RKRequestSerialization.h"
|
||||
#import "RKReachabilityObserver.h"
|
||||
|
||||
/**
|
||||
* RKClient exposes the low level client interface for working
|
||||
@@ -21,6 +22,7 @@
|
||||
NSString* _username;
|
||||
NSString* _password;
|
||||
NSMutableDictionary* _HTTPHeaders;
|
||||
RKReachabilityObserver* _baseURLReachabilityObserver;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -43,6 +45,12 @@
|
||||
*/
|
||||
@property(nonatomic, readonly) NSDictionary* HTTPHeaders;
|
||||
|
||||
/**
|
||||
* The RKReachabilityObserver used to monitor whether or not the client has a connection
|
||||
* path to the baseURL
|
||||
*/
|
||||
@property(nonatomic, readonly) RKReachabilityObserver* baseURLReachabilityObserver;
|
||||
|
||||
/**
|
||||
* Return the configured singleton instance of the Rest client
|
||||
*/
|
||||
@@ -95,11 +103,13 @@
|
||||
*/
|
||||
- (NSURL*)URLForResourcePath:(NSString *)resourcePath queryParams:(NSDictionary*)queryParams;
|
||||
|
||||
- (void)setupRequest:(RKRequest*)request;
|
||||
|
||||
/**
|
||||
* Return a request object targetted at a resource path relative to the base URL. By default the method is set to GET
|
||||
* All headers set on the client will automatically be applied to the request as well.
|
||||
*/
|
||||
- (RKRequest*)requestWithResourcePath:(NSString*)resourcePath delegate:(id)delegate callback:(SEL)callback;
|
||||
- (RKRequest*)requestWithResourcePath:(NSString*)resourcePath delegate:(id)delegate;
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
// Asynchronous Helper Methods
|
||||
@@ -112,31 +122,31 @@
|
||||
*/
|
||||
|
||||
/**
|
||||
* Fetch a resource via an HTTP GET and invoke a callback with the result
|
||||
* Fetch a resource via an HTTP GET
|
||||
*/
|
||||
- (RKRequest*)get:(NSString*)resourcePath delegate:(id)delegate callback:(SEL)callback;
|
||||
- (RKRequest*)get:(NSString*)resourcePath delegate:(id)delegate;
|
||||
|
||||
/**
|
||||
* Fetch a resource via an HTTP GET with a dictionary of params and invoke a callback with the resulting payload
|
||||
* Fetch a resource via an HTTP GET with a dictionary of params
|
||||
*
|
||||
* Note that this request _only_ allows NSDictionary objects as the params. The dictionary will be coerced into a URL encoded
|
||||
* string and then appended to the resourcePath as the query string of the request.
|
||||
*/
|
||||
- (RKRequest*)get:(NSString*)resourcePath queryParams:(NSDictionary*)queryParams delegate:(id)delegate callback:(SEL)callback;
|
||||
- (RKRequest*)get:(NSString*)resourcePath queryParams:(NSDictionary*)queryParams delegate:(id)delegate;
|
||||
|
||||
/**
|
||||
* Create a resource via an HTTP POST with a set of form parameters and invoke a callback with the resulting payload
|
||||
* Create a resource via an HTTP POST with a set of form parameters
|
||||
*/
|
||||
- (RKRequest*)post:(NSString*)resourcePath params:(NSObject<RKRequestSerializable>*)params delegate:(id)delegate callback:(SEL)callback;
|
||||
- (RKRequest*)post:(NSString*)resourcePath params:(NSObject<RKRequestSerializable>*)params delegate:(id)delegate;
|
||||
|
||||
/**
|
||||
* Update a resource via an HTTP PUT and invoke a callback with the resulting payload
|
||||
* Update a resource via an HTTP PUT
|
||||
*/
|
||||
- (RKRequest*)put:(NSString*)resourcePath params:(NSObject<RKRequestSerializable>*)params delegate:(id)delegate callback:(SEL)callback;
|
||||
- (RKRequest*)put:(NSString*)resourcePath params:(NSObject<RKRequestSerializable>*)params delegate:(id)delegate;
|
||||
|
||||
/**
|
||||
* Destroy a resource via an HTTP DELETE and invoke a callback with the resulting payload
|
||||
* Destroy a resource via an HTTP DELETE
|
||||
*/
|
||||
- (RKRequest*)delete:(NSString*)resourcePath delegate:(id)delegate callback:(SEL)callback;
|
||||
- (RKRequest*)delete:(NSString*)resourcePath delegate:(id)delegate;
|
||||
|
||||
@end
|
||||
|
||||
@@ -24,6 +24,7 @@ static RKClient* sharedClient = nil;
|
||||
@synthesize username = _username;
|
||||
@synthesize password = _password;
|
||||
@synthesize HTTPHeaders = _HTTPHeaders;
|
||||
@synthesize baseURLReachabilityObserver = _baseURLReachabilityObserver;
|
||||
|
||||
+ (RKClient*)sharedClient {
|
||||
return sharedClient;
|
||||
@@ -80,20 +81,13 @@ static RKClient* sharedClient = nil;
|
||||
}
|
||||
|
||||
- (BOOL)isNetworkAvailable {
|
||||
Boolean success;
|
||||
|
||||
const char *host_name = "google.com"; // your data source host name
|
||||
|
||||
SCNetworkReachabilityRef reachability = SCNetworkReachabilityCreateWithName(NULL, host_name);
|
||||
#ifdef TARGET_OS_IPHONE || TARGET_IPHONE_SIMULATOR
|
||||
SCNetworkReachabilityFlags flags;
|
||||
#else
|
||||
SCNetworkConnectionFlags flags;
|
||||
#endif
|
||||
success = SCNetworkReachabilityGetFlags(reachability, &flags);
|
||||
BOOL isNetworkAvailable = success && (flags & kSCNetworkFlagsReachable) && !(flags & kSCNetworkFlagsConnectionRequired);
|
||||
CFRelease(reachability);
|
||||
|
||||
BOOL isNetworkAvailable = NO;
|
||||
if (self.baseURLReachabilityObserver) {
|
||||
isNetworkAvailable = [self.baseURLReachabilityObserver isNetworkReachable];
|
||||
} else {
|
||||
RKReachabilityObserver* googleObserver = [RKReachabilityObserver reachabilityObserverWithHostName:@"google.com"];
|
||||
isNetworkAvailable = [googleObserver isNetworkReachable];
|
||||
}
|
||||
return isNetworkAvailable;
|
||||
}
|
||||
|
||||
@@ -119,8 +113,18 @@ static RKClient* sharedClient = nil;
|
||||
[_HTTPHeaders setValue:value forKey:header];
|
||||
}
|
||||
|
||||
- (RKRequest*)requestWithResourcePath:(NSString*)resourcePath delegate:(id)delegate callback:(SEL)callback {
|
||||
RKRequest* request = [[RKRequest alloc] initWithURL:[self URLForResourcePath:resourcePath] delegate:delegate callback:callback];
|
||||
- (void)setBaseURL:(NSString*)baseURL {
|
||||
[_baseURL release];
|
||||
_baseURL = nil;
|
||||
_baseURL = [baseURL retain];
|
||||
|
||||
[_baseURLReachabilityObserver release];
|
||||
_baseURLReachabilityObserver = nil;
|
||||
_baseURLReachabilityObserver = [[RKReachabilityObserver reachabilityObserverWithHostName:baseURL] retain];
|
||||
}
|
||||
|
||||
- (RKRequest*)requestWithResourcePath:(NSString*)resourcePath delegate:(id)delegate {
|
||||
RKRequest* request = [[RKRequest alloc] initWithURL:[self URLForResourcePath:resourcePath] delegate:delegate];
|
||||
[self setupRequest:request];
|
||||
[request autorelease];
|
||||
|
||||
@@ -131,8 +135,8 @@ static RKClient* sharedClient = nil;
|
||||
// Asynchronous Requests
|
||||
///////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
- (RKRequest*)load:(NSString*)resourcePath method:(RKRequestMethod)method params:(NSObject<RKRequestSerializable>*)params delegate:(id)delegate callback:(SEL)callback {
|
||||
RKRequest* request = [[RKRequest alloc] initWithURL:[self URLForResourcePath:resourcePath] delegate:delegate callback:callback];
|
||||
- (RKRequest*)load:(NSString*)resourcePath method:(RKRequestMethod)method params:(NSObject<RKRequestSerializable>*)params delegate:(id)delegate {
|
||||
RKRequest* request = [[RKRequest alloc] initWithURL:[self URLForResourcePath:resourcePath] delegate:delegate];
|
||||
[self setupRequest:request];
|
||||
[request autorelease];
|
||||
request.params = params;
|
||||
@@ -142,25 +146,25 @@ static RKClient* sharedClient = nil;
|
||||
return request;
|
||||
}
|
||||
|
||||
- (RKRequest*)get:(NSString*)resourcePath delegate:(id)delegate callback:(SEL)callback {
|
||||
return [self load:resourcePath method:RKRequestMethodGET params:nil delegate:delegate callback:callback];
|
||||
- (RKRequest*)get:(NSString*)resourcePath delegate:(id)delegate {
|
||||
return [self load:resourcePath method:RKRequestMethodGET params:nil delegate:delegate];
|
||||
}
|
||||
|
||||
- (RKRequest*)get:(NSString*)resourcePath queryParams:(NSDictionary*)queryParams delegate:(id)delegate callback:(SEL)callback {
|
||||
- (RKRequest*)get:(NSString*)resourcePath queryParams:(NSDictionary*)queryParams delegate:(id)delegate {
|
||||
NSString* resourcePathWithQueryString = [NSString stringWithFormat:@"%@?%@", resourcePath, [queryParams URLEncodedString]];
|
||||
return [self load:resourcePathWithQueryString method:RKRequestMethodGET params:nil delegate:delegate callback:callback];
|
||||
return [self load:resourcePathWithQueryString method:RKRequestMethodGET params:nil delegate:delegate];
|
||||
}
|
||||
|
||||
- (RKRequest*)post:(NSString*)resourcePath params:(NSObject<RKRequestSerializable>*)params delegate:(id)delegate callback:(SEL)callback {
|
||||
return [self load:resourcePath method:RKRequestMethodPOST params:params delegate:delegate callback:callback];
|
||||
- (RKRequest*)post:(NSString*)resourcePath params:(NSObject<RKRequestSerializable>*)params delegate:(id)delegate {
|
||||
return [self load:resourcePath method:RKRequestMethodPOST params:params delegate:delegate];
|
||||
}
|
||||
|
||||
- (RKRequest*)put:(NSString*)resourcePath params:(NSObject<RKRequestSerializable>*)params delegate:(id)delegate callback:(SEL)callback {
|
||||
return [self load:resourcePath method:RKRequestMethodPUT params:params delegate:delegate callback:callback];
|
||||
- (RKRequest*)put:(NSString*)resourcePath params:(NSObject<RKRequestSerializable>*)params delegate:(id)delegate {
|
||||
return [self load:resourcePath method:RKRequestMethodPUT params:params delegate:delegate];
|
||||
}
|
||||
|
||||
- (RKRequest*)delete:(NSString*)resourcePath delegate:(id)delegate callback:(SEL)callback {
|
||||
return [self load:resourcePath method:RKRequestMethodDELETE params:nil delegate:delegate callback:callback];
|
||||
- (RKRequest*)delete:(NSString*)resourcePath delegate:(id)delegate {
|
||||
return [self load:resourcePath method:RKRequestMethodDELETE params:nil delegate:delegate];
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
@@ -18,3 +18,4 @@
|
||||
*/
|
||||
extern NSString* const kRKRequestSentNotification;
|
||||
extern NSString* const kRKResponseReceivedNotification;
|
||||
extern NSString* const kRKRequestFailedWithErrorNotification;
|
||||
@@ -10,3 +10,4 @@
|
||||
|
||||
NSString* const kRKRequestSentNotification = @"kRKRequestSentNotification";
|
||||
NSString* const kRKResponseReceivedNotification = @"kRKRespongReceivedNotification";
|
||||
NSString* const kRKRequestFailedWithErrorNotification = @"kRKRequestFailedWithErrorNotification";
|
||||
|
||||
55
Code/Network/RKReachabilityObserver.h
Executable file
55
Code/Network/RKReachabilityObserver.h
Executable file
@@ -0,0 +1,55 @@
|
||||
//
|
||||
// RKReachabilityObserver.h
|
||||
// RestKit
|
||||
//
|
||||
// Created by Blake Watters on 9/14/10.
|
||||
// Copyright 2010 RestKit. All rights reserved.
|
||||
//
|
||||
|
||||
#import <Foundation/Foundation.h>
|
||||
#import <SystemConfiguration/SystemConfiguration.h>
|
||||
|
||||
/**
|
||||
* Posted when the network state has changed
|
||||
*/
|
||||
extern NSString* const RKReachabilityStateChangedNotification;
|
||||
|
||||
typedef enum {
|
||||
RKReachabilityNotReachable,
|
||||
RKReachabilityReachableViaWiFi,
|
||||
RKReachabilityReachableViaWWAN
|
||||
} RKReachabilityNetworkStatus;
|
||||
|
||||
/**
|
||||
* Provides a notification based interface for monitoring changes
|
||||
* to network status
|
||||
*/
|
||||
@interface RKReachabilityObserver : NSObject {
|
||||
SCNetworkReachabilityRef _reachabilityRef;
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a new reachability observer against a given hostname. The observer
|
||||
* will monitor the ability to reach the specified hostname and emit notifications
|
||||
* when its reachability status changes.
|
||||
*
|
||||
* Note that the observer will be scheduled in the current run loop.
|
||||
*/
|
||||
+ (RKReachabilityObserver*)reachabilityObserverWithHostName:(NSString*)hostName;
|
||||
|
||||
/**
|
||||
* Returns the current network status
|
||||
*/
|
||||
- (RKReachabilityNetworkStatus)networkStatus;
|
||||
|
||||
/**
|
||||
* Returns YES when the Internet is reachable (via WiFi or WWAN)
|
||||
*/
|
||||
- (BOOL)isNetworkReachable;
|
||||
|
||||
/**
|
||||
* Returns YES when WWAN may be available, but not active until a connection has been established.
|
||||
*/
|
||||
- (BOOL)isConnectionRequired;
|
||||
|
||||
@end
|
||||
145
Code/Network/RKReachabilityObserver.m
Executable file
145
Code/Network/RKReachabilityObserver.m
Executable file
@@ -0,0 +1,145 @@
|
||||
//
|
||||
// RKReachabilityObserver.m
|
||||
// RestKit
|
||||
//
|
||||
// Created by Blake Watters on 9/14/10.
|
||||
// Copyright 2010 RestKit. All rights reserved.
|
||||
//
|
||||
|
||||
#import "RKReachabilityObserver.h"
|
||||
#import <UIKit/UIKit.h>
|
||||
|
||||
// Constants
|
||||
NSString* const RKReachabilityStateChangedNotification = @"RKReachabilityStateChangedNotification";
|
||||
|
||||
static void ReachabilityCallback(SCNetworkReachabilityRef target, SCNetworkReachabilityFlags flags, void* info) {
|
||||
#pragma unused (target, flags)
|
||||
// We're on the main RunLoop, so an NSAutoreleasePool is not necessary, but is added defensively
|
||||
// in case someone uses the Reachablity object in a different thread.
|
||||
NSAutoreleasePool* pool = [[NSAutoreleasePool alloc] init];
|
||||
|
||||
RKReachabilityObserver* observer = (RKReachabilityObserver*) info;
|
||||
// Post a notification to notify the client that the network reachability changed.
|
||||
[[NSNotificationCenter defaultCenter] postNotificationName:RKReachabilityStateChangedNotification object:observer];
|
||||
|
||||
[pool release];
|
||||
}
|
||||
|
||||
#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 = SCNetworkReachabilityCreateWithName(NULL, [hostName UTF8String]);
|
||||
|
||||
if (nil != reachabilityRef) {
|
||||
observer = [[[self alloc] initWithReachabilityRef:reachabilityRef] autorelease];
|
||||
}
|
||||
return observer;
|
||||
}
|
||||
|
||||
- (id)initWithReachabilityRef:(SCNetworkReachabilityRef)reachabilityRef {
|
||||
if (self = [self init]) {
|
||||
_reachabilityRef = reachabilityRef;
|
||||
[self scheduleObserver];
|
||||
|
||||
[[NSNotificationCenter defaultCenter] addObserver:self
|
||||
selector:@selector(scheduleObserver)
|
||||
name:UIApplicationDidBecomeActiveNotification
|
||||
object:nil];
|
||||
[[NSNotificationCenter defaultCenter] addObserver:self
|
||||
selector:@selector(unscheduleObserver)
|
||||
name:UIApplicationWillResignActiveNotification
|
||||
object:nil];
|
||||
}
|
||||
return self;
|
||||
}
|
||||
|
||||
- (void)dealloc {
|
||||
[[NSNotificationCenter defaultCenter] removeObserver:self];
|
||||
[self unscheduleObserver];
|
||||
if (_reachabilityRef) {
|
||||
CFRelease(_reachabilityRef);
|
||||
}
|
||||
[super dealloc];
|
||||
}
|
||||
|
||||
- (RKReachabilityNetworkStatus)networkStatus {
|
||||
NSAssert(_reachabilityRef != NULL, @"currentNetworkStatus called with NULL reachabilityRef");
|
||||
RKReachabilityNetworkStatus status = RKReachabilityNotReachable;
|
||||
SCNetworkReachabilityFlags flags;
|
||||
|
||||
if (SCNetworkReachabilityGetFlags(_reachabilityRef, &flags)) {
|
||||
if ((flags & kSCNetworkReachabilityFlagsReachable) == 0) {
|
||||
// if target host is not reachable
|
||||
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;
|
||||
}
|
||||
|
||||
|
||||
if ((((flags & kSCNetworkReachabilityFlagsConnectionOnDemand ) != 0) ||
|
||||
(flags & kSCNetworkReachabilityFlagsConnectionOnTraffic) != 0)) {
|
||||
// ... and the connection is on-demand (or on-traffic) if the
|
||||
// calling application is using the CFSocketStream or higher APIs
|
||||
|
||||
if ((flags & kSCNetworkReachabilityFlagsInterventionRequired) == 0) {
|
||||
// ... and no [user] intervention is needed
|
||||
status = RKReachabilityReachableViaWiFi;
|
||||
}
|
||||
}
|
||||
|
||||
if ((flags & kSCNetworkReachabilityFlagsIsWWAN) == kSCNetworkReachabilityFlagsIsWWAN) {
|
||||
// ... but WWAN connections are OK if the calling application
|
||||
// is using the CFNetwork (CFSocketStream?) APIs.
|
||||
status = RKReachabilityReachableViaWWAN;
|
||||
}
|
||||
}
|
||||
return status;
|
||||
}
|
||||
|
||||
- (BOOL)isNetworkReachable {
|
||||
return (RKReachabilityNotReachable != [self networkStatus]);
|
||||
}
|
||||
|
||||
- (BOOL)isConnectionRequired {
|
||||
NSAssert(_reachabilityRef != NULL, @"connectionRequired called with NULL reachabilityRef");
|
||||
SCNetworkReachabilityFlags flags;
|
||||
if (SCNetworkReachabilityGetFlags(_reachabilityRef, &flags)) {
|
||||
return (flags & kSCNetworkReachabilityFlagsConnectionRequired);
|
||||
}
|
||||
return NO;
|
||||
}
|
||||
|
||||
#pragma mark Observer scheduling
|
||||
|
||||
- (void)scheduleObserver {
|
||||
SCNetworkReachabilityContext context = {0, self, NULL, NULL, NULL};
|
||||
if (SCNetworkReachabilitySetCallback(_reachabilityRef, ReachabilityCallback, &context)) {
|
||||
if (NO == SCNetworkReachabilityScheduleWithRunLoop(_reachabilityRef, CFRunLoopGetCurrent(), kCFRunLoopDefaultMode)) {
|
||||
NSLog(@"Warning -- Unable to schedule reachability observer in current run loop.");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
- (void)unscheduleObserver {
|
||||
if (nil != _reachabilityRef) {
|
||||
SCNetworkReachabilityUnscheduleFromRunLoop(_reachabilityRef, CFRunLoopGetCurrent(), kCFRunLoopDefaultMode);
|
||||
}
|
||||
}
|
||||
|
||||
@end
|
||||
@@ -22,6 +22,7 @@ typedef enum RKRequestMethod {
|
||||
} RKRequestMethod;
|
||||
|
||||
@class RKResponse;
|
||||
@protocol RKRequestDelegate;
|
||||
|
||||
@interface RKRequest : NSObject {
|
||||
NSURL* _URL;
|
||||
@@ -29,12 +30,13 @@ typedef enum RKRequestMethod {
|
||||
NSURLConnection* _connection;
|
||||
NSDictionary* _additionalHTTPHeaders;
|
||||
NSObject<RKRequestSerializable>* _params;
|
||||
id _delegate;
|
||||
SEL _callback;
|
||||
NSObject<RKRequestDelegate>* _delegate;
|
||||
id _userData;
|
||||
NSString* _username;
|
||||
NSString* _password;
|
||||
RKRequestMethod _method;
|
||||
BOOL _isLoading;
|
||||
BOOL _isLoaded;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -42,6 +44,11 @@ typedef enum RKRequestMethod {
|
||||
*/
|
||||
@property(nonatomic, readonly) NSURL* URL;
|
||||
|
||||
/**
|
||||
* The resourcePath portion of this loader's URL
|
||||
*/
|
||||
@property (nonatomic, readonly) NSString* resourcePath;
|
||||
|
||||
/**
|
||||
* The HTTP verb the request is sent via
|
||||
*
|
||||
@@ -61,12 +68,7 @@ typedef enum RKRequestMethod {
|
||||
* If the object implements the RKRequestDelegate protocol,
|
||||
* it will receive request lifecycle event messages.
|
||||
*/
|
||||
@property(nonatomic, assign) id delegate;
|
||||
|
||||
/**
|
||||
* The selector to invoke when the request is completed
|
||||
*/
|
||||
@property(nonatomic, assign) SEL callback;
|
||||
@property(nonatomic, assign) NSObject<RKRequestDelegate>* delegate;
|
||||
|
||||
/**
|
||||
* A Dictionary of additional HTTP Headers to send with the request
|
||||
@@ -100,7 +102,7 @@ typedef enum RKRequestMethod {
|
||||
/**
|
||||
* Return a REST request that is ready for dispatching
|
||||
*/
|
||||
+ (RKRequest*)requestWithURL:(NSURL*)URL delegate:(id)delegate callback:(SEL)callback;
|
||||
+ (RKRequest*)requestWithURL:(NSURL*)URL delegate:(id)delegate;
|
||||
|
||||
/**
|
||||
* Initialize a synchronous request
|
||||
@@ -110,10 +112,11 @@ typedef enum RKRequestMethod {
|
||||
/**
|
||||
* Initialize a REST request and prepare it for dispatching
|
||||
*/
|
||||
- (id)initWithURL:(NSURL*)URL delegate:(id)delegate callback:(SEL)callback;
|
||||
- (id)initWithURL:(NSURL*)URL delegate:(id)delegate;
|
||||
|
||||
/**
|
||||
* Send the request asynchronously
|
||||
* Send the request asynchronously. It will be added to the queue and
|
||||
* dispatched as soon as possible.
|
||||
*/
|
||||
- (void)send;
|
||||
|
||||
@@ -122,6 +125,18 @@ typedef enum RKRequestMethod {
|
||||
*/
|
||||
- (RKResponse*)sendSynchronously;
|
||||
|
||||
/**
|
||||
* Callback performed to notify the request that the underlying NSURLConnection
|
||||
* has failed with an error.
|
||||
*/
|
||||
- (void)didFailLoadWithError:(NSError*)error;
|
||||
|
||||
/**
|
||||
* Callback performed to notify the request that the underlying NSURLConnection
|
||||
* has completed with a response.
|
||||
*/
|
||||
- (void)didFinishLoad:(RKResponse*)response;
|
||||
|
||||
/**
|
||||
* Cancels the underlying URL connection
|
||||
*/
|
||||
@@ -147,6 +162,16 @@ typedef enum RKRequestMethod {
|
||||
*/
|
||||
- (BOOL)isDELETE;
|
||||
|
||||
/**
|
||||
* Returns YES when this request is in-progress
|
||||
*/
|
||||
- (BOOL)isLoading;
|
||||
|
||||
/**
|
||||
* Returns YES when this request has been completed
|
||||
*/
|
||||
- (BOOL)isLoaded;
|
||||
|
||||
@end
|
||||
|
||||
/**
|
||||
@@ -154,18 +179,13 @@ typedef enum RKRequestMethod {
|
||||
*
|
||||
* Modeled off of TTURLRequest
|
||||
*/
|
||||
@protocol RKRequestDelegate
|
||||
@protocol RKRequestDelegate
|
||||
@optional
|
||||
|
||||
/**
|
||||
* Sent when a request has started loading
|
||||
*/
|
||||
- (void)requestDidStartLoad:(RKRequest*)request;
|
||||
|
||||
/**
|
||||
* Sent when a request has finished loading
|
||||
*/
|
||||
- (void)requestDidFinishLoad:(RKRequest*)request;
|
||||
- (void)request:(RKRequest*)request didLoadResponse:(RKResponse*)response;
|
||||
|
||||
/**
|
||||
* Sent when a request has failed due to an error
|
||||
@@ -173,9 +193,9 @@ typedef enum RKRequestMethod {
|
||||
- (void)request:(RKRequest*)request didFailLoadWithError:(NSError*)error;
|
||||
|
||||
/**
|
||||
* Sent when a request has been canceled
|
||||
* Sent when a request has started loading
|
||||
*/
|
||||
- (void)requestDidCancelLoad:(RKRequest*)request;
|
||||
- (void)requestDidStartLoad:(RKRequest*)request;
|
||||
|
||||
/**
|
||||
* Sent when a request has uploaded data to the remote site
|
||||
|
||||
@@ -7,20 +7,21 @@
|
||||
//
|
||||
|
||||
#import "RKRequest.h"
|
||||
#import "RKRequestQueue.h"
|
||||
#import "RKResponse.h"
|
||||
#import "NSDictionary+RKRequestSerialization.h"
|
||||
#import "RKNotifications.h"
|
||||
#import "RKClient.h"
|
||||
#import "../Support/Support.h"
|
||||
#import "RKURL.h"
|
||||
|
||||
@implementation RKRequest
|
||||
|
||||
@synthesize URL = _URL, URLRequest = _URLRequest, delegate = _delegate, callback = _callback, additionalHTTPHeaders = _additionalHTTPHeaders,
|
||||
@synthesize URL = _URL, URLRequest = _URLRequest, delegate = _delegate, additionalHTTPHeaders = _additionalHTTPHeaders,
|
||||
params = _params, userData = _userData, username = _username, password = _password, method = _method;
|
||||
|
||||
+ (RKRequest*)requestWithURL:(NSURL*)URL delegate:(id)delegate callback:(SEL)callback {
|
||||
RKRequest* request = [[RKRequest alloc] initWithURL:URL delegate:delegate callback:callback];
|
||||
[request autorelease];
|
||||
|
||||
return request;
|
||||
+ (RKRequest*)requestWithURL:(NSURL*)URL delegate:(id)delegate {
|
||||
return [[[RKRequest alloc] initWithURL:URL delegate:delegate] autorelease];
|
||||
}
|
||||
|
||||
- (id)initWithURL:(NSURL*)URL {
|
||||
@@ -28,30 +29,38 @@
|
||||
_URL = [URL retain];
|
||||
_URLRequest = [[NSMutableURLRequest alloc] initWithURL:_URL];
|
||||
_connection = nil;
|
||||
_isLoading = NO;
|
||||
_isLoaded = NO;
|
||||
}
|
||||
|
||||
return self;
|
||||
}
|
||||
|
||||
- (id)initWithURL:(NSURL*)URL delegate:(id)delegate callback:(SEL)callback {
|
||||
- (id)initWithURL:(NSURL*)URL delegate:(id)delegate {
|
||||
if (self = [self initWithURL:URL]) {
|
||||
_delegate = delegate;
|
||||
_callback = callback;
|
||||
}
|
||||
|
||||
return self;
|
||||
}
|
||||
|
||||
- (void)dealloc {
|
||||
self.delegate = nil;
|
||||
[_connection cancel];
|
||||
[_connection release];
|
||||
_connection = nil;
|
||||
[_userData release];
|
||||
_userData = nil;
|
||||
[_URL release];
|
||||
_URL = nil;
|
||||
[_URLRequest release];
|
||||
_URLRequest = nil;
|
||||
[_params release];
|
||||
_params = nil;
|
||||
[_additionalHTTPHeaders release];
|
||||
_additionalHTTPHeaders = nil;
|
||||
[_username release];
|
||||
_username = nil;
|
||||
[_password release];
|
||||
_password = nil;
|
||||
[super dealloc];
|
||||
}
|
||||
|
||||
@@ -126,38 +135,96 @@
|
||||
}
|
||||
|
||||
- (void)send {
|
||||
[self addHeadersToRequest];
|
||||
NSString* body = [[NSString alloc] initWithData:[_URLRequest HTTPBody] encoding:NSUTF8StringEncoding];
|
||||
NSLog(@"Sending %@ request to URL %@. HTTP Body: %@", [self HTTPMethod], [[self URL] absoluteString], body);
|
||||
[body release];
|
||||
NSDate* sentAt = [NSDate date];
|
||||
NSDictionary* userInfo = [NSDictionary dictionaryWithObjectsAndKeys:[self HTTPMethod], @"HTTPMethod", [self URL], @"URL", sentAt, @"sentAt", nil];
|
||||
[[NSNotificationCenter defaultCenter] postNotificationName:kRKRequestSentNotification object:self userInfo:userInfo];
|
||||
RKResponse* response = [[[RKResponse alloc] initWithRequest:self] autorelease];
|
||||
_connection = [[NSURLConnection connectionWithRequest:_URLRequest delegate:response] retain];
|
||||
[[RKRequestQueue sharedQueue] sendRequest:self];
|
||||
}
|
||||
|
||||
- (void)fireAsynchronousRequest {
|
||||
if ([[RKClient sharedClient] isNetworkAvailable]) {
|
||||
[self addHeadersToRequest];
|
||||
NSString* body = [[NSString alloc] initWithData:[_URLRequest HTTPBody] encoding:NSUTF8StringEncoding];
|
||||
NSLog(@"Sending %@ request to URL %@. HTTP Body: %@", [self HTTPMethod], [[self URL] absoluteString], body);
|
||||
[body release];
|
||||
NSDate* sentAt = [NSDate date];
|
||||
NSDictionary* userInfo = [NSDictionary dictionaryWithObjectsAndKeys:[self HTTPMethod], @"HTTPMethod", [self URL], @"URL", sentAt, @"sentAt", nil];
|
||||
[[NSNotificationCenter defaultCenter] postNotificationName:kRKRequestSentNotification object:self userInfo:userInfo];
|
||||
|
||||
_isLoading = YES;
|
||||
RKResponse* response = [[[RKResponse alloc] initWithRequest:self] autorelease];
|
||||
_connection = [[NSURLConnection connectionWithRequest:_URLRequest delegate:response] retain];
|
||||
} else {
|
||||
NSString* errorMessage = [NSString stringWithFormat:@"The client is unable to contact the resource at %@", [[self URL] absoluteString]];
|
||||
NSDictionary *userInfo = [NSDictionary dictionaryWithObjectsAndKeys:
|
||||
errorMessage, NSLocalizedDescriptionKey,
|
||||
nil];
|
||||
NSError* error = [NSError errorWithDomain:RKRestKitErrorDomain code:RKRequestBaseURLOfflineError userInfo:userInfo];
|
||||
[self didFailLoadWithError:error];
|
||||
}
|
||||
}
|
||||
|
||||
- (RKResponse*)sendSynchronously {
|
||||
[self addHeadersToRequest];
|
||||
NSString* body = [[NSString alloc] initWithData:[_URLRequest HTTPBody] encoding:NSUTF8StringEncoding];
|
||||
NSLog(@"Sending synchronous %@ request to URL %@. HTTP Body: %@", [self HTTPMethod], [[self URL] absoluteString], body);
|
||||
[body release];
|
||||
NSDate* sentAt = [NSDate date];
|
||||
NSDictionary* userInfo = [NSDictionary dictionaryWithObjectsAndKeys:[self HTTPMethod], @"HTTPMethod", [self URL], @"URL", sentAt, @"sentAt", nil];
|
||||
[[NSNotificationCenter defaultCenter] postNotificationName:kRKRequestSentNotification object:self userInfo:userInfo];
|
||||
NSURLResponse* URLResponse = nil;
|
||||
NSError* error = nil;
|
||||
NSData* payload = [NSURLConnection sendSynchronousRequest:_URLRequest returningResponse:&URLResponse error:&error];
|
||||
return [[[RKResponse alloc] initWithSynchronousRequest:self URLResponse:URLResponse body:payload error:error] autorelease];
|
||||
NSData* payload = nil;
|
||||
RKResponse* response = nil;
|
||||
|
||||
if ([[RKClient sharedClient] isNetworkAvailable]) {
|
||||
[self addHeadersToRequest];
|
||||
NSString* body = [[NSString alloc] initWithData:[_URLRequest HTTPBody] encoding:NSUTF8StringEncoding];
|
||||
NSLog(@"Sending synchronous %@ request to URL %@. HTTP Body: %@", [self HTTPMethod], [[self URL] absoluteString], body);
|
||||
[body release];
|
||||
NSDate* sentAt = [NSDate date];
|
||||
NSDictionary* userInfo = [NSDictionary dictionaryWithObjectsAndKeys:[self HTTPMethod], @"HTTPMethod", [self URL], @"URL", sentAt, @"sentAt", nil];
|
||||
[[NSNotificationCenter defaultCenter] postNotificationName:kRKRequestSentNotification object:self userInfo:userInfo];
|
||||
|
||||
_isLoading = YES;
|
||||
payload = [NSURLConnection sendSynchronousRequest:_URLRequest returningResponse:&URLResponse error:&error];
|
||||
response = [[[RKResponse alloc] initWithSynchronousRequest:self URLResponse:URLResponse body:payload error:error] autorelease];
|
||||
} else {
|
||||
NSString* errorMessage = [NSString stringWithFormat:@"The client is unable to contact the resource at %@", [[self URL] absoluteString]];
|
||||
NSDictionary *userInfo = [NSDictionary dictionaryWithObjectsAndKeys:
|
||||
errorMessage, NSLocalizedDescriptionKey,
|
||||
nil];
|
||||
error = [NSError errorWithDomain:RKRestKitErrorDomain code:RKRequestBaseURLOfflineError userInfo:userInfo];
|
||||
[self didFailLoadWithError:error];
|
||||
|
||||
// TODO: Is this needed here? Or can we just return a nil response and everyone will be happy??
|
||||
response = [[[RKResponse alloc] initWithSynchronousRequest:self URLResponse:URLResponse body:payload error:error] autorelease];
|
||||
}
|
||||
|
||||
return response;
|
||||
}
|
||||
|
||||
- (void)cancel {
|
||||
[_connection cancel];
|
||||
[_connection release];
|
||||
_connection = nil;
|
||||
if ([_delegate respondsToSelector:@selector(requestDidCancelLoad:)]) {
|
||||
[_delegate requestDidCancelLoad:self];
|
||||
_isLoading = NO;
|
||||
}
|
||||
|
||||
- (void)didFailLoadWithError:(NSError*)error {
|
||||
_isLoading = NO;
|
||||
|
||||
if ([_delegate respondsToSelector:@selector(request:didFailLoadWithError:)]) {
|
||||
[_delegate request:self didFailLoadWithError:error];
|
||||
}
|
||||
|
||||
NSDate* receivedAt = [NSDate date];
|
||||
NSDictionary* userInfo = [NSDictionary dictionaryWithObjectsAndKeys:[self HTTPMethod], @"HTTPMethod",
|
||||
[self URL], @"URL", receivedAt, @"receivedAt", error, @"error", nil];
|
||||
[[NSNotificationCenter defaultCenter] postNotificationName:kRKRequestFailedWithErrorNotification object:self userInfo:userInfo];
|
||||
}
|
||||
|
||||
- (void)didFinishLoad:(RKResponse*)response {
|
||||
_isLoading = NO;
|
||||
_isLoaded = YES;
|
||||
|
||||
if ([_delegate respondsToSelector:@selector(request:didLoadResponse:)]) {
|
||||
[_delegate request:self didLoadResponse:response];
|
||||
}
|
||||
|
||||
NSDate* receivedAt = [NSDate date];
|
||||
NSDictionary* userInfo = [NSDictionary dictionaryWithObjectsAndKeys:[self HTTPMethod], @"HTTPMethod", [self URL], @"URL", receivedAt, @"receivedAt", nil];
|
||||
[[NSNotificationCenter defaultCenter] postNotificationName:kRKResponseReceivedNotification object:response userInfo:userInfo];
|
||||
}
|
||||
|
||||
- (BOOL)isGET {
|
||||
@@ -176,4 +243,21 @@
|
||||
return _method == RKRequestMethodDELETE;
|
||||
}
|
||||
|
||||
- (BOOL)isLoading {
|
||||
return _isLoading;
|
||||
}
|
||||
|
||||
- (BOOL)isLoaded {
|
||||
return _isLoaded;
|
||||
}
|
||||
|
||||
- (NSString*)resourcePath {
|
||||
NSString* resourcePath = nil;
|
||||
if ([self.URL isKindOfClass:[RKURL class]]) {
|
||||
RKURL* url = (RKURL*)self.URL;
|
||||
resourcePath = url.resourcePath;
|
||||
}
|
||||
return resourcePath;
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
63
Code/Network/RKRequestQueue.h
Normal file
63
Code/Network/RKRequestQueue.h
Normal file
@@ -0,0 +1,63 @@
|
||||
//
|
||||
// RKRequestQueue.h
|
||||
// RestKit
|
||||
//
|
||||
// Created by Blake Watters on 12/1/10.
|
||||
// Copyright 2010 Two Toasters. All rights reserved.
|
||||
//
|
||||
|
||||
#import <Foundation/Foundation.h>
|
||||
#import "RKRequest.h"
|
||||
|
||||
/**
|
||||
* A lightweight queue implementation responsible
|
||||
* for dispatching and managing RKRequest objects
|
||||
*/
|
||||
@interface RKRequestQueue : NSObject {
|
||||
NSMutableArray* _requests;
|
||||
NSInteger _totalLoading;
|
||||
NSTimer* _queueTimer;
|
||||
BOOL _suspended;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the flag that determines if new load requests are allowed to reach the network.
|
||||
*
|
||||
* Because network requests tend to slow down performance, this property can be used to
|
||||
* temporarily delay them. All requests made while suspended are queued, and when
|
||||
* suspended becomes false again they are executed.
|
||||
*/
|
||||
@property (nonatomic) BOOL suspended;
|
||||
|
||||
/**
|
||||
* Return the global queue
|
||||
*/
|
||||
+ (RKRequestQueue*)sharedQueue;
|
||||
|
||||
/**
|
||||
* Set the global queue
|
||||
*/
|
||||
+ (void)setSharedQueue:(RKRequestQueue*)requestQueue;
|
||||
|
||||
/**
|
||||
* Add an asynchronous request to the queue and send it as
|
||||
* as soon as possible
|
||||
*/
|
||||
- (void)sendRequest:(RKRequest*)request;
|
||||
|
||||
/**
|
||||
* Cancel a request that is in progress
|
||||
*/
|
||||
- (void)cancelRequest:(RKRequest*)request;
|
||||
|
||||
/**
|
||||
* Cancel all requests with a given delegate
|
||||
*/
|
||||
- (void)cancelRequestsWithDelegate:(NSObject<RKRequestDelegate>*)delegate;
|
||||
|
||||
/**
|
||||
* Cancel all active or pending requests.
|
||||
*/
|
||||
- (void)cancelAllRequests;
|
||||
|
||||
@end
|
||||
163
Code/Network/RKRequestQueue.m
Normal file
163
Code/Network/RKRequestQueue.m
Normal file
@@ -0,0 +1,163 @@
|
||||
//
|
||||
// RKRequestQueue.m
|
||||
// RestKit
|
||||
//
|
||||
// Created by Blake Watters on 12/1/10.
|
||||
// Copyright 2010 Two Toasters. All rights reserved.
|
||||
//
|
||||
|
||||
#import "RKRequestQueue.h"
|
||||
#import "RKResponse.h"
|
||||
#import "RKNotifications.h"
|
||||
|
||||
static RKRequestQueue* gSharedQueue = nil;
|
||||
|
||||
static const NSTimeInterval kFlushDelay = 0.3;
|
||||
static const NSTimeInterval kTimeout = 300.0;
|
||||
static const NSInteger kMaxConcurrentLoads = 5;
|
||||
|
||||
@implementation RKRequestQueue
|
||||
|
||||
@synthesize suspended = _suspended;
|
||||
|
||||
+ (RKRequestQueue*)sharedQueue {
|
||||
if (!gSharedQueue) {
|
||||
gSharedQueue = [[RKRequestQueue alloc] init];
|
||||
}
|
||||
return gSharedQueue;
|
||||
}
|
||||
|
||||
+ (void)setSharedQueue:(RKRequestQueue*)requestQueue {
|
||||
if (gSharedQueue != requestQueue) {
|
||||
[gSharedQueue release];
|
||||
gSharedQueue = [requestQueue retain];
|
||||
}
|
||||
}
|
||||
|
||||
- (id)init {
|
||||
if (self = [super init]) {
|
||||
_requests = [[NSMutableArray alloc] init];
|
||||
_suspended = NO;
|
||||
_totalLoading = 0;
|
||||
[[NSNotificationCenter defaultCenter] addObserver:self
|
||||
selector:@selector(responseDidLoad:)
|
||||
name:kRKResponseReceivedNotification
|
||||
object:nil];
|
||||
[[NSNotificationCenter defaultCenter] addObserver:self
|
||||
selector:@selector(responseDidLoad:)
|
||||
name:kRKRequestFailedWithErrorNotification
|
||||
object:nil];
|
||||
}
|
||||
return self;
|
||||
}
|
||||
|
||||
- (void)dealloc {
|
||||
[_queueTimer invalidate];
|
||||
[_requests release];
|
||||
_requests = nil;
|
||||
[super dealloc];
|
||||
}
|
||||
|
||||
- (void)loadNextInQueueDelayed {
|
||||
if (!_queueTimer) {
|
||||
_queueTimer = [NSTimer scheduledTimerWithTimeInterval:kFlushDelay
|
||||
target:self
|
||||
selector:@selector(loadNextInQueue)
|
||||
userInfo:nil
|
||||
repeats:NO];
|
||||
}
|
||||
}
|
||||
|
||||
- (void)dispatchRequest:(RKRequest*)request {
|
||||
[request performSelector:@selector(fireAsynchronousRequest)];
|
||||
}
|
||||
|
||||
- (void)loadNextInQueue {
|
||||
_queueTimer = nil;
|
||||
|
||||
for (RKRequest* request in _requests) {
|
||||
if (![request isLoading] && ![request isLoaded] && _totalLoading < kMaxConcurrentLoads) {
|
||||
++_totalLoading;
|
||||
[self dispatchRequest:request];
|
||||
}
|
||||
}
|
||||
|
||||
if (_requests.count && !_suspended) {
|
||||
[self loadNextInQueueDelayed];
|
||||
}
|
||||
}
|
||||
|
||||
- (void)setSuspended:(BOOL)isSuspended {
|
||||
_suspended = isSuspended;
|
||||
|
||||
if (!_suspended) {
|
||||
[self loadNextInQueue];
|
||||
} else if (_queueTimer) {
|
||||
[_queueTimer invalidate];
|
||||
_queueTimer = nil;
|
||||
}
|
||||
}
|
||||
|
||||
- (void)sendRequest:(RKRequest*)request {
|
||||
[_requests addObject:request];
|
||||
[self loadNextInQueue];
|
||||
}
|
||||
|
||||
- (void)cancelRequest:(RKRequest*)request loadNext:(BOOL)loadNext {
|
||||
if ([_requests containsObject:request] && ![request isLoaded]) {
|
||||
[request cancel];
|
||||
request.delegate = nil;
|
||||
|
||||
[_requests removeObject:request];
|
||||
_totalLoading--;
|
||||
|
||||
if (loadNext) {
|
||||
[self loadNextInQueue];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
- (void)cancelRequest:(RKRequest*)request {
|
||||
[self cancelRequest:request loadNext:YES];
|
||||
}
|
||||
|
||||
- (void)cancelRequestsWithDelegate:(NSObject<RKRequestDelegate>*)delegate {
|
||||
NSArray* requestsCopy = [NSArray arrayWithArray:_requests];
|
||||
for (RKRequest* request in requestsCopy) {
|
||||
if (request.delegate && request.delegate == delegate) {
|
||||
[self cancelRequest:request];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
- (void)cancelAllRequests {
|
||||
NSArray* requestsCopy = [NSArray arrayWithArray:_requests];
|
||||
for (RKRequest* request in requestsCopy) {
|
||||
[self cancelRequest:request loadNext:NO];
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Invoked via observation when a request has loaded a response. Remove
|
||||
* the completed request from the queue and continue processing
|
||||
*/
|
||||
- (void)responseDidLoad:(NSNotification*)notification {
|
||||
if (notification.object) {
|
||||
// Our RKRequest completed and we're notified with an RKResponse object
|
||||
if ([notification.object isKindOfClass:[RKResponse class]]) {
|
||||
RKRequest* request = [(RKResponse*)notification.object request];
|
||||
[_requests removeObject:request];
|
||||
_totalLoading--;
|
||||
|
||||
// Our RKRequest failed and we're notified with the original RKRequest object
|
||||
} else if ([notification.object isKindOfClass:[RKRequest class]]) {
|
||||
RKRequest* request = (RKRequest*)notification.object;
|
||||
[_requests removeObject:request];
|
||||
_totalLoading--;
|
||||
}
|
||||
|
||||
[self loadNextInQueue];
|
||||
}
|
||||
}
|
||||
|
||||
@end
|
||||
@@ -26,7 +26,9 @@
|
||||
|
||||
- (id)initWithRequest:(RKRequest*)request {
|
||||
if (self = [self init]) {
|
||||
_request = [request retain];
|
||||
// We don't retain here as we're letting RKRequestQueue manage
|
||||
// request ownership
|
||||
_request = request;
|
||||
}
|
||||
|
||||
return self;
|
||||
@@ -34,7 +36,9 @@
|
||||
|
||||
- (id)initWithSynchronousRequest:(RKRequest*)request URLResponse:(NSURLResponse*)URLResponse body:(NSData*)body error:(NSError*)error {
|
||||
if (self = [super init]) {
|
||||
_request = [request retain];
|
||||
// TODO: Does the lack of retain here cause problems with synchronous requests, since they
|
||||
// are not being retained by the RKRequestQueue??
|
||||
_request = request;
|
||||
_httpURLResponse = [URLResponse retain];
|
||||
_failureError = [error retain];
|
||||
_body = [body retain];
|
||||
@@ -47,11 +51,24 @@
|
||||
- (void)dealloc {
|
||||
[_httpURLResponse release];
|
||||
[_body release];
|
||||
[_request release];
|
||||
[_failureError release];
|
||||
[super dealloc];
|
||||
}
|
||||
|
||||
// Handle basic auth
|
||||
- (void)connection:(NSURLConnection *)connection didReceiveAuthenticationChallenge:(NSURLAuthenticationChallenge *)challenge {
|
||||
if ([challenge previousFailureCount] == 0) {
|
||||
NSURLCredential *newCredential;
|
||||
newCredential=[NSURLCredential credentialWithUser:[NSString stringWithFormat:@"%@", _request.username]
|
||||
password:[NSString stringWithFormat:@"%@", _request.password]
|
||||
persistence:NSURLCredentialPersistenceNone];
|
||||
[[challenge sender] useCredential:newCredential
|
||||
forAuthenticationChallenge:challenge];
|
||||
} else {
|
||||
[[challenge sender] cancelAuthenticationChallenge:challenge];
|
||||
}
|
||||
}
|
||||
|
||||
- (void)connection:(NSURLConnection *)connection didReceiveData:(NSData *)data {
|
||||
if (NO == _loading) {
|
||||
_loading = YES;
|
||||
@@ -67,25 +84,13 @@
|
||||
_httpURLResponse = [response retain];
|
||||
}
|
||||
|
||||
- (void)connectionDidFinishLoading:(NSURLConnection *)connection {
|
||||
NSDate* receivedAt = [NSDate date]; // TODO - Carry around this timestamp on the response or request?
|
||||
NSDictionary* userInfo = [NSDictionary dictionaryWithObjectsAndKeys:[_request HTTPMethod], @"HTTPMethod", [_request URL], @"URL", receivedAt, @"receivedAt", nil];
|
||||
[[NSNotificationCenter defaultCenter] postNotificationName:kRKResponseReceivedNotification object:self userInfo:userInfo];
|
||||
|
||||
[[_request delegate] performSelector:[_request callback] withObject:self];
|
||||
|
||||
if ([[_request delegate] respondsToSelector:@selector(requestDidFinishLoad:)]) {
|
||||
[[_request delegate] requestDidFinishLoad:_request];
|
||||
}
|
||||
- (void)connectionDidFinishLoading:(NSURLConnection *)connection {
|
||||
[_request didFinishLoad:self];
|
||||
}
|
||||
|
||||
- (void)connection:(NSURLConnection *)connection didFailWithError:(NSError *)error {
|
||||
_failureError = [error retain];
|
||||
[[_request delegate] performSelector:[_request callback] withObject:self];
|
||||
|
||||
if ([[_request delegate] respondsToSelector:@selector(request:didFailLoadWithError:)]) {
|
||||
[[_request delegate] request:_request didFailLoadWithError:error];
|
||||
}
|
||||
[_request didFailLoadWithError:_failureError];
|
||||
}
|
||||
|
||||
- (void)connection:(NSURLConnection *)connection didSendBodyData:(NSInteger)bytesWritten totalBytesWritten:(NSInteger)totalBytesWritten totalBytesExpectedToWrite:(NSInteger)totalBytesExpectedToWrite {
|
||||
@@ -94,7 +99,6 @@
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
- (NSString*)localizedStatusCodeString {
|
||||
return [NSHTTPURLResponse localizedStringForStatusCode:[self statusCode]];
|
||||
}
|
||||
|
||||
@@ -40,15 +40,14 @@
|
||||
/**
|
||||
* Wraps a request/response cycle and loads a remote object representation into local domain objects
|
||||
*/
|
||||
@interface RKObjectLoader : NSObject <RKRequestDelegate> {
|
||||
@interface RKObjectLoader : RKRequest {
|
||||
RKObjectMapper* _mapper;
|
||||
NSObject<RKObjectLoaderDelegate>* _delegate;
|
||||
RKRequest* _request;
|
||||
RKResponse* _response;
|
||||
NSObject<RKObjectMappable>* _source;
|
||||
NSObject<RKObjectMappable>* _targetObject;
|
||||
Class<RKObjectMappable> _objectClass;
|
||||
NSString* _keyPath;
|
||||
RKManagedObjectStore* _managedObjectStore;
|
||||
NSManagedObjectID* _targetObjectID;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -56,19 +55,6 @@
|
||||
*/
|
||||
@property (nonatomic, readonly) RKObjectMapper* mapper;
|
||||
|
||||
/**
|
||||
* The object to be invoked with the loaded models
|
||||
*
|
||||
* If this object implements life-cycle methods from the RKRequestDelegate protocol,
|
||||
* events from the request will be forwarded back.
|
||||
*/
|
||||
@property (nonatomic, assign) NSObject<RKObjectLoaderDelegate>* delegate;
|
||||
|
||||
/**
|
||||
* The underlying request object for this loader
|
||||
*/
|
||||
@property (nonatomic, retain) RKRequest* request;
|
||||
|
||||
/**
|
||||
* The underlying response object for this loader
|
||||
*/
|
||||
@@ -82,25 +68,9 @@
|
||||
|
||||
/**
|
||||
* The mappable object that generated this loader. This is used to map object
|
||||
* updates back to the source object that sent the request
|
||||
* updates back to the object that sent the request
|
||||
*/
|
||||
// TODO: This should have a better name... targetObject?
|
||||
@property (nonatomic, retain) NSObject<RKObjectMappable>* source;
|
||||
|
||||
/**
|
||||
* The URL this loader sent the request to
|
||||
*/
|
||||
@property (nonatomic, readonly) NSURL* URL;
|
||||
|
||||
/**
|
||||
* The HTTP method used to send the request
|
||||
*/
|
||||
@property (nonatomic, assign) RKRequestMethod method;
|
||||
|
||||
/**
|
||||
* Parameters sent with the request
|
||||
*/
|
||||
@property (nonatomic, retain) NSObject<RKRequestSerializable>* params;
|
||||
@property (nonatomic, retain) NSObject<RKObjectMappable>* targetObject;
|
||||
|
||||
/*
|
||||
* The keyPath property is an optional property to tell the mapper to map a subset of the response
|
||||
@@ -118,21 +88,11 @@
|
||||
/**
|
||||
* Return an auto-released loader with with an object mapper, a request, and a delegate
|
||||
*/
|
||||
+ (id)loaderWithMapper:(RKObjectMapper*)mapper request:(RKRequest*)request delegate:(NSObject<RKObjectLoaderDelegate>*)delegate;
|
||||
+ (id)loaderWithResourcePath:(NSString*)resourcePath mapper:(RKObjectMapper*)mapper delegate:(NSObject<RKObjectLoaderDelegate>*)delegate;
|
||||
|
||||
/**
|
||||
* Initialize a new object loader with an object mapper, a request, and a delegate
|
||||
*/
|
||||
- (id)initWithMapper:(RKObjectMapper*)mapper request:(RKRequest*)request delegate:(NSObject<RKObjectLoaderDelegate>*)delegate;
|
||||
|
||||
/**
|
||||
* Asynchronously send the object loader request
|
||||
*/
|
||||
- (void)send;
|
||||
|
||||
/**
|
||||
* Synchronously send the object loader request and process the response
|
||||
*/
|
||||
- (void)sendSynchronously;
|
||||
- (id)initWithResourcePath:(NSString*)resourcePath mapper:(RKObjectMapper*)mapper delegate:(NSObject<RKObjectLoaderDelegate>*)delegate;
|
||||
|
||||
@end
|
||||
|
||||
@@ -13,102 +13,109 @@
|
||||
#import "Errors.h"
|
||||
#import "RKManagedObject.h"
|
||||
#import "RKURL.h"
|
||||
|
||||
@interface RKObjectLoader (Private)
|
||||
- (void)loadObjectsFromResponse:(RKResponse*)response;
|
||||
@end
|
||||
#import "RKNotifications.h"
|
||||
|
||||
@implementation RKObjectLoader
|
||||
|
||||
@synthesize mapper = _mapper, delegate = _delegate, request = _request, response = _response,
|
||||
objectClass = _objectClass, source = _source, keyPath = _keyPath, managedObjectStore = _managedObjectStore;
|
||||
@synthesize mapper = _mapper, response = _response, objectClass = _objectClass, targetObject = _targetObject,
|
||||
keyPath = _keyPath, managedObjectStore = _managedObjectStore;
|
||||
|
||||
+ (id)loaderWithMapper:(RKObjectMapper*)mapper request:(RKRequest*)request delegate:(NSObject<RKObjectLoaderDelegate>*)delegate {
|
||||
return [[[self alloc] initWithMapper:mapper request:request delegate:delegate] autorelease];
|
||||
+ (id)loaderWithResourcePath:(NSString*)resourcePath mapper:(RKObjectMapper*)mapper delegate:(NSObject<RKObjectLoaderDelegate>*)delegate {
|
||||
return [[[self alloc] initWithResourcePath:resourcePath mapper:mapper delegate:delegate] autorelease];
|
||||
}
|
||||
|
||||
- (id)initWithMapper:(RKObjectMapper*)mapper request:(RKRequest*)request delegate:(NSObject<RKObjectLoaderDelegate>*)delegate {
|
||||
if (self = [self init]) {
|
||||
- (id)initWithResourcePath:(NSString*)resourcePath mapper:(RKObjectMapper*)mapper delegate:(NSObject<RKObjectLoaderDelegate>*)delegate {
|
||||
if (self = [self initWithURL:[[RKClient sharedClient] URLForResourcePath:resourcePath] delegate:delegate]) {
|
||||
_mapper = [mapper retain];
|
||||
self.request = request;
|
||||
self.delegate = delegate;
|
||||
self.managedObjectStore = nil;
|
||||
_targetObjectID = nil;
|
||||
|
||||
[[RKClient sharedClient] setupRequest:self];
|
||||
}
|
||||
|
||||
return self;
|
||||
}
|
||||
|
||||
- (void)dealloc {
|
||||
_request.delegate = nil;
|
||||
[_mapper release];
|
||||
[_request release];
|
||||
_mapper = nil;
|
||||
[_response release];
|
||||
_response = nil;
|
||||
[_keyPath release];
|
||||
_keyPath = nil;
|
||||
[_targetObject release];
|
||||
_targetObject = nil;
|
||||
[_targetObjectID release];
|
||||
_targetObjectID = nil;
|
||||
self.managedObjectStore = nil;
|
||||
[super dealloc];
|
||||
}
|
||||
|
||||
- (void)setRequest:(RKRequest *)request {
|
||||
[request retain];
|
||||
[_request release];
|
||||
_request = request;
|
||||
- (void)setTargetObject:(NSObject<RKObjectMappable>*)targetObject {
|
||||
[_targetObject release];
|
||||
_targetObject = nil;
|
||||
_targetObject = [targetObject retain];
|
||||
|
||||
_request.delegate = self;
|
||||
_request.callback = @selector(loadObjectsFromResponse:);
|
||||
[_targetObjectID release];
|
||||
_targetObjectID = nil;
|
||||
|
||||
if ([targetObject isKindOfClass:[NSManagedObject class]]) {
|
||||
_targetObjectID = [[(NSManagedObject*)targetObject objectID] retain];
|
||||
}
|
||||
}
|
||||
|
||||
#pragma mark RKRequest Proxy Methods
|
||||
|
||||
- (NSURL*)URL {
|
||||
return self.request.URL;
|
||||
}
|
||||
|
||||
- (RKRequestMethod)method {
|
||||
return self.request.method;
|
||||
}
|
||||
|
||||
- (void)setMethod:(RKRequestMethod)method {
|
||||
self.request.method = method;
|
||||
}
|
||||
|
||||
- (NSObject<RKRequestSerializable>*)params {
|
||||
return self.request.params;
|
||||
}
|
||||
|
||||
- (void)setParams:(NSObject<RKRequestSerializable>*)params {
|
||||
self.request.params = params;
|
||||
}
|
||||
|
||||
- (void)send {
|
||||
[self retain];
|
||||
[self.request send];
|
||||
}
|
||||
|
||||
- (void)sendSynchronously {
|
||||
[self retain];
|
||||
RKResponse* response = [self.request sendSynchronously];
|
||||
[self loadObjectsFromResponse:response];
|
||||
}
|
||||
|
||||
#pragma mark Response Processing
|
||||
|
||||
- (void)responseProcessingSuccessful:(BOOL)successful withError:(NSError*)error {
|
||||
_isLoading = NO;
|
||||
|
||||
NSDate* receivedAt = [NSDate date];
|
||||
if (successful) {
|
||||
_isLoaded = YES;
|
||||
NSDictionary* userInfo = [NSDictionary dictionaryWithObjectsAndKeys:[self HTTPMethod], @"HTTPMethod",
|
||||
[self URL], @"URL",
|
||||
receivedAt, @"receivedAt",
|
||||
nil];
|
||||
[[NSNotificationCenter defaultCenter] postNotificationName:kRKResponseReceivedNotification
|
||||
object:_response
|
||||
userInfo:userInfo];
|
||||
} else {
|
||||
NSDictionary* userInfo = [NSDictionary dictionaryWithObjectsAndKeys:[self HTTPMethod], @"HTTPMethod",
|
||||
[self URL], @"URL",
|
||||
receivedAt, @"receivedAt",
|
||||
error, @"error",
|
||||
nil];
|
||||
[[NSNotificationCenter defaultCenter] postNotificationName:kRKRequestFailedWithErrorNotification
|
||||
object:self
|
||||
userInfo:userInfo];
|
||||
}
|
||||
}
|
||||
|
||||
- (BOOL)encounteredErrorWhileProcessingRequest:(RKResponse*)response {
|
||||
if ([response isFailure]) {
|
||||
[_delegate objectLoader:self didFailWithError:response.failureError];
|
||||
[self release];
|
||||
[(NSObject<RKObjectLoaderDelegate>*)_delegate objectLoader:self didFailWithError:response.failureError];
|
||||
|
||||
[self responseProcessingSuccessful:NO withError:response.failureError];
|
||||
|
||||
return YES;
|
||||
} else if ([response isError]) {
|
||||
NSError* error = nil;
|
||||
|
||||
if ([response isJSON]) {
|
||||
[_delegate objectLoader:self didFailWithError:[_mapper parseErrorFromString:[response bodyAsString]]];
|
||||
error = [_mapper parseErrorFromString:[response bodyAsString]];
|
||||
[(NSObject<RKObjectLoaderDelegate>*)_delegate objectLoader:self didFailWithError:error];
|
||||
} else {
|
||||
// TODO: We've likely run into a maintenance page here. Consider adding the ability
|
||||
// to put the stack into offline mode in response...
|
||||
if ([_delegate respondsToSelector:@selector(objectLoaderDidLoadUnexpectedResponse:)]) {
|
||||
[_delegate objectLoaderDidLoadUnexpectedResponse:self];
|
||||
[(NSObject<RKObjectLoaderDelegate>*)_delegate objectLoaderDidLoadUnexpectedResponse:self];
|
||||
}
|
||||
}
|
||||
[self release];
|
||||
}
|
||||
|
||||
[self responseProcessingSuccessful:NO withError:error];
|
||||
|
||||
return YES;
|
||||
}
|
||||
|
||||
return NO;
|
||||
}
|
||||
|
||||
@@ -128,8 +135,9 @@
|
||||
}
|
||||
}
|
||||
|
||||
[_delegate objectLoader:self didLoadObjects:[NSArray arrayWithArray:objects]];
|
||||
[self release];
|
||||
[(NSObject<RKObjectLoaderDelegate>*)_delegate objectLoader:self didLoadObjects:[NSArray arrayWithArray:objects]];
|
||||
|
||||
[self responseProcessingSuccessful:YES withError:nil];
|
||||
}
|
||||
|
||||
- (void)informDelegateOfObjectLoadErrorWithInfoDictionary:(NSDictionary*)dictionary {
|
||||
@@ -143,11 +151,11 @@
|
||||
nil];
|
||||
NSError *rkError = [NSError errorWithDomain:RKRestKitErrorDomain code:RKObjectLoaderRemoteSystemError userInfo:userInfo];
|
||||
|
||||
[_delegate objectLoader:self didFailWithError:rkError];
|
||||
[self release];
|
||||
[(NSObject<RKObjectLoaderDelegate>*)_delegate objectLoader:self didFailWithError:rkError];
|
||||
|
||||
[self responseProcessingSuccessful:NO withError:rkError];
|
||||
}
|
||||
|
||||
|
||||
- (void)processLoadModelsInBackground:(RKResponse *)response {
|
||||
NSAutoreleasePool* pool = [[NSAutoreleasePool alloc] init];
|
||||
RKManagedObjectStore* objectStore = self.managedObjectStore;
|
||||
@@ -158,15 +166,14 @@
|
||||
* individual object instances via getObject & friends.
|
||||
*/
|
||||
NSArray* results = nil;
|
||||
if (self.source) {
|
||||
if ([self.source isKindOfClass:[NSManagedObject class]]) {
|
||||
NSManagedObjectID* modelID = [(NSManagedObject*)self.source objectID];
|
||||
NSManagedObject* backgroundThreadModel = [self.managedObjectStore objectWithID:modelID];
|
||||
if (self.targetObject) {
|
||||
if (_targetObjectID) {
|
||||
NSManagedObject* backgroundThreadModel = [self.managedObjectStore objectWithID:_targetObjectID];
|
||||
[_mapper mapObject:backgroundThreadModel fromString:[response bodyAsString]];
|
||||
results = [NSArray arrayWithObject:backgroundThreadModel];
|
||||
} else {
|
||||
[_mapper mapObject:self.source fromString:[response bodyAsString]];
|
||||
results = [NSArray arrayWithObject:self.source];
|
||||
[_mapper mapObject:self.targetObject fromString:[response bodyAsString]];
|
||||
results = [NSArray arrayWithObject:self.targetObject];
|
||||
}
|
||||
} else {
|
||||
id result = [_mapper mapFromString:[response bodyAsString] toClass:self.objectClass keyPath:_keyPath];
|
||||
@@ -199,7 +206,7 @@
|
||||
NSError* error = [objectStore save];
|
||||
if (nil != error) {
|
||||
NSDictionary* infoDictionary = [[NSDictionary dictionaryWithObjectsAndKeys:response, @"response", error, @"error", nil] retain];
|
||||
[self performSelectorOnMainThread:@selector(informDelegateOfObjectLoadErrorWithInfoDictionary:) withObject:infoDictionary waitUntilDone:NO];
|
||||
[self performSelectorOnMainThread:@selector(informDelegateOfObjectLoadErrorWithInfoDictionary:) withObject:infoDictionary waitUntilDone:YES];
|
||||
} else {
|
||||
// NOTE: Passing Core Data objects across threads is not safe.
|
||||
// Iterate over each model and coerce Core Data objects into ID's to pass across the threads.
|
||||
@@ -214,15 +221,29 @@
|
||||
}
|
||||
|
||||
NSDictionary* infoDictionary = [[NSDictionary dictionaryWithObjectsAndKeys:response, @"response", models, @"models", nil] retain];
|
||||
[self performSelectorOnMainThread:@selector(informDelegateOfObjectLoadWithInfoDictionary:) withObject:infoDictionary waitUntilDone:NO];
|
||||
[self performSelectorOnMainThread:@selector(informDelegateOfObjectLoadWithInfoDictionary:) withObject:infoDictionary waitUntilDone:YES];
|
||||
}
|
||||
|
||||
[pool release];
|
||||
[pool drain];
|
||||
}
|
||||
|
||||
- (void)loadObjectsFromResponse:(RKResponse*)response {
|
||||
- (void)didFailLoadWithError:(NSError*)error {
|
||||
if ([_delegate respondsToSelector:@selector(request:didFailLoadWithError:)]) {
|
||||
[_delegate request:self didFailLoadWithError:error];
|
||||
}
|
||||
|
||||
[(NSObject<RKObjectLoaderDelegate>*)_delegate objectLoader:self didFailWithError:error];
|
||||
|
||||
[self responseProcessingSuccessful:NO withError:error];
|
||||
}
|
||||
|
||||
- (void)didFinishLoad:(RKResponse*)response {
|
||||
_response = [response retain];
|
||||
|
||||
if ([_delegate respondsToSelector:@selector(request:didLoadResponse:)]) {
|
||||
[_delegate request:self didLoadResponse:response];
|
||||
}
|
||||
|
||||
if (NO == [self encounteredErrorWhileProcessingRequest:response]) {
|
||||
// TODO: When other mapping formats are supported, unwind this assumption...
|
||||
if ([response isSuccessful] && [response isJSON]) {
|
||||
@@ -230,47 +251,11 @@
|
||||
} else {
|
||||
NSLog(@"Encountered unexpected response code: %d (MIME Type: %@)", response.statusCode, response.MIMEType);
|
||||
if ([_delegate respondsToSelector:@selector(objectLoaderDidLoadUnexpectedResponse:)]) {
|
||||
[_delegate objectLoaderDidLoadUnexpectedResponse:self];
|
||||
[self release];
|
||||
[(NSObject<RKObjectLoaderDelegate>*)_delegate objectLoaderDidLoadUnexpectedResponse:self];
|
||||
}
|
||||
[self responseProcessingSuccessful:NO withError:nil];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
// RKRequestDelegate
|
||||
//
|
||||
// If our delegate responds to the messages, forward them back...
|
||||
|
||||
- (void)requestDidStartLoad:(RKRequest*)request {
|
||||
if ([_delegate respondsToSelector:@selector(requestDidStartLoad:)]) {
|
||||
[_delegate requestDidStartLoad:request];
|
||||
}
|
||||
}
|
||||
|
||||
- (void)requestDidFinishLoad:(RKRequest*)request {
|
||||
if ([_delegate respondsToSelector:@selector(requestDidFinishLoad:)]) {
|
||||
[(NSObject<RKRequestDelegate>*)_delegate requestDidFinishLoad:request];
|
||||
}
|
||||
}
|
||||
|
||||
- (void)request:(RKRequest*)request didFailLoadWithError:(NSError*)error {
|
||||
if ([_delegate respondsToSelector:@selector(request:didFailLoadWithError:)]) {
|
||||
[(NSObject<RKRequestDelegate>*)_delegate request:request didFailLoadWithError:error];
|
||||
}
|
||||
}
|
||||
|
||||
- (void)requestDidCancelLoad:(RKRequest*)request {
|
||||
[self release];
|
||||
if ([_delegate respondsToSelector:@selector(requestDidCancelLoad:)]) {
|
||||
[(NSObject<RKRequestDelegate>*)_delegate requestDidCancelLoad:request];
|
||||
}
|
||||
}
|
||||
|
||||
- (void)request:(RKRequest*)request didSendBodyData:(NSInteger)bytesWritten totalBytesWritten:(NSInteger)totalBytesWritten totalBytesExpectedToWrite:(NSInteger)totalBytesExpectedToWrite {
|
||||
if ([_delegate respondsToSelector:@selector(request:didSendBodyData:totalBytesWritten:totalBytesExpectedToWrite:)]) {
|
||||
[(NSObject<RKRequestDelegate>*)_delegate request:request didSendBodyData:bytesWritten totalBytesWritten:totalBytesWritten totalBytesExpectedToWrite:totalBytesExpectedToWrite];
|
||||
}
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
@@ -15,6 +15,12 @@
|
||||
extern NSString* const RKDidEnterOfflineModeNotification;
|
||||
extern NSString* const RKDidEnterOnlineModeNotification;
|
||||
|
||||
typedef enum {
|
||||
RKObjectManagerOnlineStateUndetermined,
|
||||
RKObjectManagerOnlineStateDisconnected,
|
||||
RKObjectManagerOnlineStateConnected
|
||||
} RKObjectManagerOnlineState;
|
||||
|
||||
// TODO: Factor out into a protocol...
|
||||
// insertObject:, deleteObject:, save, etc.
|
||||
@class RKManagedObjectStore;
|
||||
@@ -24,8 +30,9 @@ extern NSString* const RKDidEnterOnlineModeNotification;
|
||||
RKMappingFormat _format;
|
||||
RKObjectMapper* _mapper;
|
||||
NSObject<RKRouter>* _router;
|
||||
RKManagedObjectStore* _objectStore;
|
||||
BOOL _isOnline;
|
||||
RKManagedObjectStore* _objectStore;
|
||||
RKObjectManagerOnlineState _onlineState;
|
||||
BOOL _onlineStateForced;
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -32,7 +32,12 @@ static RKObjectManager* sharedManager = nil;
|
||||
_router = [[RKDynamicRouter alloc] init];
|
||||
_client = [[RKClient clientWithBaseURL:baseURL] retain];
|
||||
self.format = RKMappingFormatJSON;
|
||||
_isOnline = YES;
|
||||
_onlineState = RKObjectManagerOnlineStateUndetermined;
|
||||
_onlineStateForced = NO;
|
||||
[[NSNotificationCenter defaultCenter] addObserver:self
|
||||
selector:@selector(reachabilityChanged:)
|
||||
name:RKReachabilityStateChangedNotification
|
||||
object:nil];
|
||||
}
|
||||
return self;
|
||||
}
|
||||
@@ -68,6 +73,7 @@ static RKObjectManager* sharedManager = nil;
|
||||
}
|
||||
|
||||
- (void)dealloc {
|
||||
[[NSNotificationCenter defaultCenter] removeObserver:self];
|
||||
[_mapper release];
|
||||
_mapper = nil;
|
||||
[_router release];
|
||||
@@ -80,23 +86,39 @@ static RKObjectManager* sharedManager = nil;
|
||||
}
|
||||
|
||||
- (void)goOffline {
|
||||
_isOnline = NO;
|
||||
_onlineState = RKObjectManagerOnlineStateDisconnected;
|
||||
_onlineStateForced = YES;
|
||||
[[NSNotificationCenter defaultCenter] postNotificationName:RKDidEnterOfflineModeNotification object:self];
|
||||
}
|
||||
|
||||
- (void)goOnline {
|
||||
_isOnline = YES;
|
||||
_onlineState = RKObjectManagerOnlineStateConnected;
|
||||
_onlineStateForced = YES;
|
||||
[[NSNotificationCenter defaultCenter] postNotificationName:RKDidEnterOnlineModeNotification object:self];
|
||||
}
|
||||
|
||||
- (BOOL)isOnline {
|
||||
return _isOnline;
|
||||
return (_onlineState == RKObjectManagerOnlineStateConnected);
|
||||
}
|
||||
|
||||
- (BOOL)isOffline {
|
||||
return ![self isOnline];
|
||||
}
|
||||
|
||||
- (void)reachabilityChanged:(NSNotification*)notification {
|
||||
if (!_onlineStateForced) {
|
||||
BOOL isHostReachable = [self.client.baseURLReachabilityObserver isNetworkReachable];
|
||||
|
||||
_onlineState = isHostReachable ? RKObjectManagerOnlineStateConnected : RKObjectManagerOnlineStateDisconnected;
|
||||
|
||||
if (isHostReachable) {
|
||||
[[NSNotificationCenter defaultCenter] postNotificationName:RKDidEnterOnlineModeNotification object:self];
|
||||
} else {
|
||||
[[NSNotificationCenter defaultCenter] postNotificationName:RKDidEnterOfflineModeNotification object:self];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
- (void)setFormat:(RKMappingFormat)format {
|
||||
_format = format;
|
||||
_mapper.format = format;
|
||||
@@ -114,13 +136,7 @@ static RKObjectManager* sharedManager = nil;
|
||||
}
|
||||
|
||||
- (RKObjectLoader*)objectLoaderWithResourcePath:(NSString*)resourcePath delegate:(NSObject<RKObjectLoaderDelegate>*)delegate {
|
||||
if ([self isOffline]) {
|
||||
return nil;
|
||||
}
|
||||
|
||||
// Grab request through client to get HTTP AUTH & Headers
|
||||
RKRequest* request = [self.client requestWithResourcePath:resourcePath delegate:nil callback:nil];
|
||||
RKObjectLoader* loader = [RKObjectLoader loaderWithMapper:self.mapper request:request delegate:delegate];
|
||||
RKObjectLoader* loader = [RKObjectLoader loaderWithResourcePath:resourcePath mapper:self.mapper delegate:delegate];
|
||||
loader.managedObjectStore = self.objectStore;
|
||||
|
||||
return loader;
|
||||
@@ -185,7 +201,7 @@ static RKObjectManager* sharedManager = nil;
|
||||
|
||||
loader.method = method;
|
||||
loader.params = params;
|
||||
loader.source = object;
|
||||
loader.targetObject = object;
|
||||
loader.objectClass = [object class];
|
||||
loader.managedObjectStore = self.objectStore;
|
||||
|
||||
|
||||
@@ -104,7 +104,13 @@ static const NSString* kRKModelMapperMappingFormatParserKey = @"RKMappingFormatP
|
||||
}
|
||||
|
||||
NSLog(@"Began parse...");
|
||||
id result = [parser objectFromString:string];
|
||||
id result = nil;
|
||||
@try {
|
||||
result = [parser objectFromString:string];
|
||||
}
|
||||
@catch (NSException* e) {
|
||||
NSLog(@"[RestKit] RKObjectMapper:parseString: Exception (%@) parsing error from string: %@", [e reason], string);
|
||||
}
|
||||
NSLog(@"Finished parse...");
|
||||
return result;
|
||||
}
|
||||
@@ -165,23 +171,25 @@ static const NSString* kRKModelMapperMappingFormatParserKey = @"RKMappingFormatP
|
||||
// TODO: Should accept RKObjectMappable instead of id...
|
||||
- (void)mapObject:(id)model fromDictionary:(NSDictionary*)dictionary {
|
||||
Class class = [model class];
|
||||
NSString* elementName = [_elementToClassMappings keyForObject:class];
|
||||
if (elementName) {
|
||||
// Extract elements nested in dictionary
|
||||
if ([[dictionary allKeys] containsObject:elementName]) {
|
||||
NSDictionary* elements = [dictionary objectForKey:elementName];
|
||||
[self updateModel:model fromElements:elements];
|
||||
} else {
|
||||
// If the dictionary is not namespaced, attempt mapping its properties directly...
|
||||
[self updateModel:model fromElements:dictionary];
|
||||
}
|
||||
} else {
|
||||
|
||||
NSArray* elementNames = [_elementToClassMappings allKeysForObject:class];
|
||||
if ([elementNames count] == 0) {
|
||||
if ([model conformsToProtocol:@protocol(RKObjectMappable)]) {
|
||||
[self updateModel:model fromElements:dictionary];
|
||||
} else {
|
||||
[NSException raise:@"Unable to map from requested dictionary"
|
||||
format:@"There was no mappable element found for objects of type %@", class];
|
||||
}
|
||||
}
|
||||
} else {
|
||||
for (NSString* elementName in elementNames) {
|
||||
if ([[dictionary allKeys] containsObject:elementName]) {
|
||||
NSDictionary* elements = [dictionary objectForKey:elementName];
|
||||
[self updateModel:model fromElements:elements];
|
||||
return;
|
||||
}
|
||||
}
|
||||
// If the dictionary is not namespaced, attempt mapping its properties directly...
|
||||
[self updateModel:model fromElements:dictionary];
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -10,5 +10,6 @@
|
||||
extern NSString* const RKRestKitErrorDomain;
|
||||
|
||||
typedef enum {
|
||||
RKObjectLoaderRemoteSystemError = 1
|
||||
RKObjectLoaderRemoteSystemError = 1,
|
||||
RKRequestBaseURLOfflineError
|
||||
} RKRestKitError;
|
||||
|
||||
@@ -17,9 +17,4 @@
|
||||
*/
|
||||
+ (id)dictionaryWithKeysAndObjects:(id)firstKey, ... NS_REQUIRES_NIL_TERMINATION;
|
||||
|
||||
/**
|
||||
* Returns the key for an object within the dictionary
|
||||
*/
|
||||
- (id)keyForObject:(id)object;
|
||||
|
||||
@end
|
||||
|
||||
@@ -25,13 +25,4 @@
|
||||
return [self dictionaryWithObjects:values forKeys:keys];
|
||||
}
|
||||
|
||||
- (id)keyForObject:(id)object {
|
||||
for (id key in self) {
|
||||
if ([[self objectForKey:key] isEqual:object]) {
|
||||
return key;
|
||||
}
|
||||
}
|
||||
return nil;
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
@@ -19,6 +19,7 @@
|
||||
NSArray* _sortDescriptors;
|
||||
NSString* _searchText;
|
||||
SEL _sortSelector;
|
||||
NSArray* _filteredObjects;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -62,6 +63,6 @@
|
||||
/**
|
||||
* Search the model for matching text
|
||||
*/
|
||||
- (void)search:(NSString *)text;
|
||||
- (void)search:(NSString*)text;
|
||||
|
||||
@end
|
||||
|
||||
@@ -17,27 +17,29 @@
|
||||
|
||||
- (id)init {
|
||||
if (self = [super init]) {
|
||||
_predicate = nil;
|
||||
_sortDescriptors = nil;
|
||||
self.predicate = nil;
|
||||
self.sortDescriptors = nil;
|
||||
self.searchEngine = nil;
|
||||
_searchText = nil;
|
||||
_searchEngine = nil;
|
||||
_filteredObjects = nil;
|
||||
}
|
||||
|
||||
return self;
|
||||
}
|
||||
|
||||
- (void)dealloc {
|
||||
[_searchEngine release];_searchEngine=nil;
|
||||
[_predicate release];_predicate=nil;
|
||||
[_sortDescriptors release];_sortDescriptors=nil;
|
||||
[_searchText release];_searchText=nil;
|
||||
self.predicate = nil;
|
||||
self.sortDescriptors = nil;
|
||||
self.searchEngine = nil;
|
||||
[_searchText release];
|
||||
_searchText = nil;
|
||||
[super dealloc];
|
||||
}
|
||||
|
||||
- (void)reset {
|
||||
[_predicate release];_predicate=nil;
|
||||
[_sortDescriptors release];_sortDescriptors=nil;
|
||||
[_searchText release];_searchText=nil;
|
||||
self.predicate = nil;
|
||||
self.sortDescriptors = nil;
|
||||
[_searchText release];
|
||||
_searchText = nil;
|
||||
[self didChange];
|
||||
}
|
||||
|
||||
@@ -53,7 +55,7 @@
|
||||
return _searchEngine;
|
||||
}
|
||||
|
||||
- (NSArray*)search:(NSString *)text inCollection:(NSArray*)collection {
|
||||
- (NSArray*)search:(NSString*)text inCollection:(NSArray*)collection {
|
||||
if (text.length) {
|
||||
RKSearchEngine* searchEngine = [self createSearchEngine];
|
||||
return [searchEngine searchFor:text inCollection:collection];
|
||||
@@ -62,32 +64,85 @@
|
||||
}
|
||||
}
|
||||
|
||||
// public
|
||||
|
||||
- (void)search:(NSString *)text {
|
||||
- (void)search:(NSString*)text {
|
||||
[_searchText release];
|
||||
_searchText = nil;
|
||||
_searchText = [text retain];
|
||||
|
||||
[_filteredObjects release];
|
||||
_filteredObjects = nil;
|
||||
|
||||
[self didFinishLoad];
|
||||
}
|
||||
|
||||
// Overloaded to hide filtering/searching from the underlying data source
|
||||
- (void)filterRawObjects {
|
||||
NSArray* results = _objects;
|
||||
if (results && [results count] > 0) {
|
||||
if (self.predicate) {
|
||||
results = [results filteredArrayUsingPredicate:self.predicate];
|
||||
}
|
||||
|
||||
if (_searchText) {
|
||||
results = [self search:_searchText inCollection:results];
|
||||
}
|
||||
|
||||
if (self.sortSelector) {
|
||||
results = [results sortedArrayUsingSelector:self.sortSelector];
|
||||
} else if (self.sortDescriptors) {
|
||||
results = [results sortedArrayUsingDescriptors:self.sortDescriptors];
|
||||
}
|
||||
|
||||
_filteredObjects = [results retain];
|
||||
} else {
|
||||
_filteredObjects = [results copy];
|
||||
}
|
||||
}
|
||||
|
||||
- (NSArray*)objects {
|
||||
NSArray* results = _model.objects;
|
||||
if (self.predicate) {
|
||||
results = [results filteredArrayUsingPredicate:self.predicate];
|
||||
if (nil == _filteredObjects) {
|
||||
[self filterRawObjects];
|
||||
}
|
||||
return _filteredObjects;
|
||||
}
|
||||
|
||||
- (void)modelsDidLoad:(NSArray*)models {
|
||||
[models retain];
|
||||
[_objects release];
|
||||
_objects = nil;
|
||||
[_filteredObjects release];
|
||||
_filteredObjects = nil;
|
||||
|
||||
if (_searchText) {
|
||||
results = [self search:_searchText inCollection:results];
|
||||
}
|
||||
_objects = models;
|
||||
[self filterRawObjects];
|
||||
_isLoaded = YES;
|
||||
|
||||
if (self.sortSelector) {
|
||||
results = [results sortedArrayUsingSelector:self.sortSelector];
|
||||
} else if (self.sortDescriptors) {
|
||||
results = [results sortedArrayUsingDescriptors:self.sortDescriptors];
|
||||
}
|
||||
[self didFinishLoad];
|
||||
}
|
||||
|
||||
- (void)setPredicate:(NSPredicate*)predicate {
|
||||
[_predicate release];
|
||||
_predicate = nil;
|
||||
_predicate = [predicate retain];
|
||||
|
||||
return results;
|
||||
[_filteredObjects release];
|
||||
_filteredObjects = nil;
|
||||
}
|
||||
|
||||
- (void)setSortDescriptors:(NSArray*)sortDescriptors {
|
||||
[_sortDescriptors release];
|
||||
_sortDescriptors = nil;
|
||||
_sortDescriptors = [sortDescriptors retain];
|
||||
|
||||
[_filteredObjects release];
|
||||
_filteredObjects = nil;
|
||||
}
|
||||
|
||||
- (void)setSortSelector:(SEL)sortSelector {
|
||||
_sortSelector = nil;
|
||||
_sortSelector = sortSelector;
|
||||
|
||||
[_filteredObjects release];
|
||||
_filteredObjects = nil;
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
@@ -1,108 +0,0 @@
|
||||
//
|
||||
// RKRequestModel.h
|
||||
// RestKit
|
||||
//
|
||||
// Created by Jeff Arena on 4/26/10.
|
||||
// Copyright 2010 RestKit. All rights reserved.
|
||||
//
|
||||
|
||||
#import "../RestKit.h"
|
||||
#import "../CoreData/RKManagedObject.h"
|
||||
|
||||
/**
|
||||
* Lifecycle events for RKRequestModel
|
||||
*
|
||||
* Modeled off of RKRequestDelegate (and therefore TTURLRequest)
|
||||
*/
|
||||
@protocol RKRequestModelDelegate
|
||||
@optional
|
||||
- (void)rkModelDidStartLoad;
|
||||
- (void)rkModelDidFinishLoad;
|
||||
- (void)rkModelDidFailLoadWithError:(NSError*)error;
|
||||
- (void)rkModelDidCancelLoad;
|
||||
- (void)rkModelDidLoad;
|
||||
@end
|
||||
|
||||
/**
|
||||
* Generic class for loading a remote model using a RestKit request
|
||||
*/
|
||||
@interface RKRequestModel : NSObject <RKObjectLoaderDelegate, RKRequestDelegate> {
|
||||
NSArray *_objects;
|
||||
BOOL _loaded;
|
||||
|
||||
NSString* _resourcePath;
|
||||
NSDictionary* _params;
|
||||
RKRequestMethod _method;
|
||||
id _delegate;
|
||||
RKObjectLoader* _objectLoader;
|
||||
Class _objectClass;
|
||||
NSString* _keyPath;
|
||||
|
||||
NSTimeInterval _refreshRate;
|
||||
}
|
||||
|
||||
/**
|
||||
* Domain objects loaded via this model
|
||||
*/
|
||||
@property (nonatomic, readonly) NSArray *objects;
|
||||
|
||||
@property (readonly) BOOL loaded;
|
||||
|
||||
@property (nonatomic, readonly) NSString* resourcePath;
|
||||
|
||||
/**
|
||||
* Any parameters POSTed with the request
|
||||
*/
|
||||
@property (nonatomic, readonly) NSDictionary* params;
|
||||
|
||||
@property (nonatomic, readonly) RKObjectLoader* objectLoader;
|
||||
|
||||
/**
|
||||
* The HTTP method to load the models with. Defaults to RKRequestMethodGET
|
||||
*/
|
||||
@property (nonatomic, assign) RKRequestMethod method;
|
||||
|
||||
@property (assign) NSTimeInterval refreshRate;
|
||||
|
||||
|
||||
/**
|
||||
* Init methods for creating new models
|
||||
*/
|
||||
- (id)initWithResourcePath:(NSString*)resourcePath delegate:(id)delegate;
|
||||
- (id)initWithResourcePath:(NSString*)resourcePath params:(NSDictionary*)params delegate:(id)delegate;
|
||||
- (id)initWithResourcePath:(NSString*)resourcePath params:(NSDictionary*)params objectClass:(Class)klass delegate:(id)delegate;
|
||||
- (id)initWithResourcePath:(NSString*)resourcePath params:(NSDictionary*)params objectClass:(Class)klass keyPath:(NSString*)keyPath delegate:(id)delegate;
|
||||
|
||||
- (id)initWithResourcePath:(NSString*)resourcePath params:(NSDictionary*)params method:(RKRequestMethod)method delegate:(id)delegate;
|
||||
- (id)initWithResourcePath:(NSString*)resourcePath params:(NSDictionary*)params method:(RKRequestMethod)method objectClass:(Class)klass delegate:(id)delegate;
|
||||
- (id)initWithResourcePath:(NSString*)resourcePath params:(NSDictionary*)params method:(RKRequestMethod)method objectClass:(Class)klass keyPath:(NSString*)keyPath delegate:(id)delegate;
|
||||
|
||||
|
||||
/**
|
||||
* Clear the last loaded time for the model
|
||||
*/
|
||||
- (void)clearLoadedTime;
|
||||
|
||||
/*
|
||||
* Save the last loaded time for the model
|
||||
*/
|
||||
- (void)saveLoadedTime;
|
||||
|
||||
/**
|
||||
* Get the last loaded time for the model
|
||||
*/
|
||||
- (NSDate*)loadedTime;
|
||||
|
||||
/**
|
||||
* Invoked after a remote request has completed and model objects have been
|
||||
* built from the response. Subclasses must invoke super to complete the load operation
|
||||
*/
|
||||
- (void)modelsDidLoad:(NSArray*)models;
|
||||
|
||||
- (void)reset;
|
||||
|
||||
- (void)load;
|
||||
|
||||
- (void)loadFromObjectCache;
|
||||
|
||||
@end
|
||||
@@ -1,310 +0,0 @@
|
||||
//
|
||||
// RKRequestModel.m
|
||||
// RestKit
|
||||
//
|
||||
// Created by Jeff Arena on 4/26/10.
|
||||
// Copyright 2010 RestKit. All rights reserved.
|
||||
//
|
||||
|
||||
#import "RKRequestModel.h"
|
||||
#import "RKManagedObjectStore.h"
|
||||
#import <Three20/Three20.h>
|
||||
|
||||
@implementation RKRequestModel
|
||||
@synthesize objects = _objects;
|
||||
@synthesize loaded = _loaded;
|
||||
@synthesize resourcePath = _resourcePath;
|
||||
@synthesize params = _params;
|
||||
@synthesize objectLoader = _objectLoader;
|
||||
@synthesize method = _method;
|
||||
@synthesize refreshRate = _refreshRate;
|
||||
|
||||
- (id)initWithResourcePath:(NSString*)resourcePath delegate:(id)delegate {
|
||||
if (self = [self init]) {
|
||||
_resourcePath = [resourcePath retain];
|
||||
_delegate = [delegate retain];
|
||||
}
|
||||
|
||||
[self loadFromObjectCache];
|
||||
|
||||
return self;
|
||||
}
|
||||
|
||||
/**
|
||||
* TODO: These initializers have to set the ivars so the state is configured before loadFromObjectCache is triggered.
|
||||
* Do NOT DRY these up by adding dependencies or loadFromObjectCache will fire too early.
|
||||
*
|
||||
* WARNING
|
||||
*/
|
||||
|
||||
- (id)initWithResourcePath:(NSString*)resourcePath params:(NSDictionary*)params delegate:(id)delegate {
|
||||
if (self = [self init]) {
|
||||
_resourcePath = [resourcePath retain];
|
||||
_delegate = [delegate retain];
|
||||
_params = [params retain];
|
||||
}
|
||||
|
||||
[self loadFromObjectCache];
|
||||
|
||||
return self;
|
||||
}
|
||||
|
||||
- (id)initWithResourcePath:(NSString*)resourcePath params:(NSDictionary*)params objectClass:(Class)klass delegate:(id)delegate {
|
||||
if (self = [self init]) {
|
||||
_resourcePath = [resourcePath retain];
|
||||
_delegate = [delegate retain];
|
||||
_params = [params retain];
|
||||
_objectClass = [klass retain];
|
||||
}
|
||||
|
||||
[self loadFromObjectCache];
|
||||
|
||||
return self;
|
||||
}
|
||||
|
||||
- (id)initWithResourcePath:(NSString*)resourcePath params:(NSDictionary*)params objectClass:(Class)klass keyPath:(NSString*)keyPath delegate:(id)delegate {
|
||||
if (self = [self init]) {
|
||||
_resourcePath = [resourcePath retain];
|
||||
_delegate = [delegate retain];
|
||||
_params = [params retain];
|
||||
_objectClass = [klass retain];
|
||||
_keyPath = [keyPath retain];
|
||||
}
|
||||
|
||||
[self loadFromObjectCache];
|
||||
|
||||
return self;
|
||||
}
|
||||
|
||||
- (id)initWithResourcePath:(NSString*)resourcePath params:(NSDictionary*)params method:(RKRequestMethod)method delegate:(id)delegate {
|
||||
if (self = [self init]) {
|
||||
_resourcePath = [resourcePath retain];
|
||||
_delegate = [delegate retain];
|
||||
_params = [params retain];
|
||||
_method = method;
|
||||
}
|
||||
|
||||
[self loadFromObjectCache];
|
||||
|
||||
return self;
|
||||
}
|
||||
|
||||
- (id)initWithResourcePath:(NSString*)resourcePath params:(NSDictionary*)params method:(RKRequestMethod)method objectClass:(Class)klass delegate:(id)delegate {
|
||||
if (self = [self init]) {
|
||||
_resourcePath = [resourcePath retain];
|
||||
_delegate = [delegate retain];
|
||||
_params = [params retain];
|
||||
_objectClass = [klass retain];
|
||||
_method = method;
|
||||
}
|
||||
|
||||
[self loadFromObjectCache];
|
||||
|
||||
return self;
|
||||
}
|
||||
|
||||
- (id)initWithResourcePath:(NSString*)resourcePath params:(NSDictionary*)params method:(RKRequestMethod)method objectClass:(Class)klass keyPath:(NSString*)keyPath delegate:(id)delegate {
|
||||
if (self = [self init]) {
|
||||
_resourcePath = [resourcePath retain];
|
||||
_delegate = [delegate retain];
|
||||
_params = [params retain];
|
||||
_objectClass = [klass retain];
|
||||
_keyPath = [keyPath retain];
|
||||
_method = method;
|
||||
}
|
||||
|
||||
[self loadFromObjectCache];
|
||||
|
||||
return self;
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
// NSObject
|
||||
|
||||
- (id)init {
|
||||
if (self = [super init]) {
|
||||
_method = RKRequestMethodGET;
|
||||
_refreshRate = NSTimeIntervalSince1970; // Essentially, default to never
|
||||
}
|
||||
return self;
|
||||
}
|
||||
|
||||
- (void)dealloc {
|
||||
[_delegate release];
|
||||
[_objectLoader.request cancel];
|
||||
[_objectLoader release];
|
||||
[_params release];
|
||||
[_objects release];
|
||||
[_objectClass release];
|
||||
[_keyPath release];
|
||||
[super dealloc];
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
// RKRequestDelegate
|
||||
|
||||
- (void)requestDidFinishLoad:(RKRequest*)request {
|
||||
[self saveLoadedTime];
|
||||
if ([_delegate respondsToSelector:@selector(rkModelDidFinishLoad)]) {
|
||||
[_delegate rkModelDidFinishLoad];
|
||||
}
|
||||
}
|
||||
|
||||
//// TODO: I get replaced...
|
||||
- (void)request:(RKRequest*)request didFailLoadWithError:(NSError*)error {
|
||||
if ([_delegate respondsToSelector:@selector(rkModelDidFailLoadWithError:)]) {
|
||||
[_delegate rkModelDidFailLoadWithError:error];
|
||||
}
|
||||
}
|
||||
|
||||
- (void)requestDidCancelLoad:(RKRequest*)request {
|
||||
if ([_delegate respondsToSelector:@selector(rkModelDidCancelLoad)]) {
|
||||
[_delegate rkModelDidCancelLoad];
|
||||
}
|
||||
}
|
||||
|
||||
- (BOOL)needsRefresh {
|
||||
NSDate* loadedTime = self.loadedTime;
|
||||
BOOL outdated = NO;
|
||||
if (loadedTime) {
|
||||
outdated = -[loadedTime timeIntervalSinceNow] > _refreshRate;
|
||||
} else {
|
||||
[self saveLoadedTime];
|
||||
}
|
||||
return outdated;
|
||||
}
|
||||
|
||||
- (void)clearLoadedTime {
|
||||
[[NSUserDefaults standardUserDefaults] removeObjectForKey:_resourcePath];
|
||||
}
|
||||
|
||||
- (void)saveLoadedTime {
|
||||
[[NSUserDefaults standardUserDefaults] setObject:[NSDate date] forKey:_resourcePath];
|
||||
}
|
||||
|
||||
- (NSDate*)loadedTime {
|
||||
return [[NSUserDefaults standardUserDefaults] objectForKey:_resourcePath];
|
||||
}
|
||||
|
||||
- (void)loadFromObjectCache {
|
||||
RKManagedObjectStore* store = [RKObjectManager sharedManager].objectStore;
|
||||
NSArray* cachedObjects = nil;
|
||||
|
||||
if (store.managedObjectCache) {
|
||||
cachedObjects = [RKManagedObject objectsWithFetchRequests:[store.managedObjectCache fetchRequestsForResourcePath:self.resourcePath]];
|
||||
|
||||
if (cachedObjects && [cachedObjects count] > 0) {
|
||||
if ([_delegate respondsToSelector:@selector(rkModelDidStartLoad)]) {
|
||||
[_delegate rkModelDidStartLoad];
|
||||
}
|
||||
|
||||
_objects = [cachedObjects retain];
|
||||
_loaded = YES;
|
||||
|
||||
if ([_delegate respondsToSelector:@selector(rkModelDidLoad)]) {
|
||||
[_delegate rkModelDidLoad];
|
||||
}
|
||||
} else {
|
||||
[self load];
|
||||
}
|
||||
}
|
||||
|
||||
if ([self needsRefresh]) {
|
||||
[self load];
|
||||
}
|
||||
}
|
||||
|
||||
- (BOOL)errorWarrantsOptionToGoOffline:(NSError*)error {
|
||||
switch ([error code]) {
|
||||
case NSURLErrorTimedOut:
|
||||
case NSURLErrorCannotFindHost:
|
||||
case NSURLErrorCannotConnectToHost:
|
||||
case NSURLErrorNetworkConnectionLost:
|
||||
case NSURLErrorDNSLookupFailed:
|
||||
case NSURLErrorNotConnectedToInternet:
|
||||
case NSURLErrorInternationalRoamingOff:
|
||||
return YES;
|
||||
break;
|
||||
default:
|
||||
return NO;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
- (void)showAlertWithOptionToGoOfflineForError:(NSError*)error {
|
||||
UIAlertView* alert = [[[UIAlertView alloc] initWithTitle:TTLocalizedString(@"Network Error", @"")
|
||||
message:[error localizedDescription]
|
||||
delegate:self
|
||||
cancelButtonTitle:TTLocalizedString(@"OK", @"")
|
||||
otherButtonTitles:TTLocalizedString(@"Go Offline", @""), nil] autorelease];
|
||||
[alert show];
|
||||
}
|
||||
|
||||
- (void)alertView:(UIAlertView *)alertView didDismissWithButtonIndex:(NSInteger)buttonIndex {
|
||||
// Go Offline button
|
||||
if (1 == buttonIndex) {
|
||||
[[RKObjectManager sharedManager] goOffline];
|
||||
}
|
||||
}
|
||||
|
||||
- (void)modelsDidLoad:(NSArray*)models {
|
||||
[models retain];
|
||||
[_objects release];
|
||||
_objects = models;
|
||||
_loaded = YES;
|
||||
|
||||
// NOTE: You must finish load after clearing the loadingRequest and setting the loaded flag
|
||||
if ([_delegate respondsToSelector:@selector(rkModelDidLoad)]) {
|
||||
[_delegate rkModelDidLoad];
|
||||
}
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
// RKModelLoaderDelegate
|
||||
|
||||
// This callback is invoked after the request has been fully serviced. Finish the load here.
|
||||
- (void)objectLoader:(RKObjectLoader *)objectLoader didLoadObjects:(NSArray *)objects {
|
||||
[objectLoader release];
|
||||
_objectLoader = nil;
|
||||
[self modelsDidLoad:objects];
|
||||
}
|
||||
|
||||
- (void)objectLoader:(RKObjectLoader *)objectLoader didFailWithError:(NSError *)error {
|
||||
[objectLoader release];
|
||||
_objectLoader = nil;
|
||||
if ([self errorWarrantsOptionToGoOffline:error]) {
|
||||
[self showAlertWithOptionToGoOfflineForError:error];
|
||||
} else {
|
||||
[_delegate didFailLoadWithError:error];
|
||||
}
|
||||
}
|
||||
|
||||
- (void)objectLoaderDidLoadUnexpectedResponse:(RKObjectLoader*)objectLoader {
|
||||
[objectLoader release];
|
||||
_objectLoader = nil;
|
||||
[_delegate didFailLoadWithError:nil];
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
// public
|
||||
|
||||
- (void)reset {
|
||||
[self clearLoadedTime];
|
||||
}
|
||||
|
||||
- (void)load {
|
||||
if ([[RKObjectManager sharedManager] isOnline]) {
|
||||
if ([_delegate respondsToSelector:@selector(rkModelDidStartLoad)]) {
|
||||
[_delegate rkModelDidStartLoad];
|
||||
}
|
||||
|
||||
_objectLoader = [[[RKObjectManager sharedManager] objectLoaderWithResourcePath:_resourcePath delegate:self] retain];
|
||||
_objectLoader.method = _method;
|
||||
_objectLoader.objectClass = _objectClass;
|
||||
_objectLoader.keyPath = _keyPath;
|
||||
_objectLoader.params = _params;
|
||||
[_objectLoader send];
|
||||
}
|
||||
}
|
||||
|
||||
@end
|
||||
@@ -7,27 +7,86 @@
|
||||
//
|
||||
|
||||
#import <Three20/Three20.h>
|
||||
#import "RKRequestModel.h"
|
||||
#import "../RestKit.h"
|
||||
|
||||
/**
|
||||
* Generic class for loading a remote model using a RestKit request and supplying the model to a
|
||||
* TTListDataSource subclass
|
||||
*/
|
||||
@interface RKRequestTTModel : TTModel <RKRequestModelDelegate> {
|
||||
RKRequestModel* _model;
|
||||
@interface RKRequestTTModel : TTModel <RKObjectLoaderDelegate> {
|
||||
NSArray *_objects;
|
||||
BOOL _isLoaded;
|
||||
BOOL _isLoading;
|
||||
BOOL _cacheLoaded;
|
||||
|
||||
NSString* _resourcePath;
|
||||
NSDictionary* _params;
|
||||
RKRequestMethod _method;
|
||||
Class _objectClass;
|
||||
NSString* _keyPath;
|
||||
|
||||
NSTimeInterval _refreshRate;
|
||||
}
|
||||
|
||||
@property (nonatomic, readonly) RKRequestModel* model;
|
||||
/**
|
||||
* Domain objects loaded via this model
|
||||
*/
|
||||
@property (nonatomic, readonly) NSArray* objects;
|
||||
|
||||
/**
|
||||
* The resourcePath used to create this model
|
||||
*/
|
||||
@property (nonatomic, readonly) NSString* resourcePath;
|
||||
|
||||
/**
|
||||
* The NSDate object representing the last time this model was loaded.
|
||||
*/
|
||||
@property (nonatomic, readonly) NSDate* loadedTime;
|
||||
|
||||
/**
|
||||
* Request parameters
|
||||
*/
|
||||
@property (nonatomic, retain) NSDictionary* params;
|
||||
|
||||
/**
|
||||
* The HTTP method to load the models with. Defaults to RKRequestMethodGET
|
||||
*/
|
||||
@property (nonatomic, assign) RKRequestMethod method;
|
||||
|
||||
/**
|
||||
* The rate at which this model should be refreshed after initial load.
|
||||
* Defaults to the value returned by + (NSTimeInterval)defaultRefreshRate.
|
||||
*/
|
||||
@property (assign) NSTimeInterval refreshRate;
|
||||
|
||||
/**
|
||||
* Init methods for creating new models
|
||||
*/
|
||||
- (id)initWithResourcePath:(NSString*)resourcePath;
|
||||
- (id)initWithResourcePath:(NSString*)resourcePath params:(NSDictionary*)params;
|
||||
- (id)initWithResourcePath:(NSString*)resourcePath params:(NSDictionary*)params objectClass:(Class)klass;
|
||||
- (id)initWithResourcePath:(NSString*)resourcePath params:(NSDictionary*)params objectClass:(Class)klass keyPath:(NSString*)keyPath;
|
||||
|
||||
- (id)initWithResourcePath:(NSString*)resourcePath params:(NSDictionary*)params method:(RKRequestMethod)method;
|
||||
- (id)initWithResourcePath:(NSString*)resourcePath params:(NSDictionary*)params method:(RKRequestMethod)method objectClass:(Class)klass;
|
||||
- (id)initWithResourcePath:(NSString*)resourcePath params:(NSDictionary*)params method:(RKRequestMethod)method objectClass:(Class)klass keyPath:(NSString*)keyPath;
|
||||
|
||||
- (NSArray*)objects;
|
||||
/**
|
||||
* The NSDate representing the first time the app was run. This defaultLoadedTime
|
||||
* is used in comparison with refreshRate in cases where a resourcePath-specific
|
||||
* loadedTime has yet to be established for a given resourcePath.
|
||||
*/
|
||||
+ (NSDate*)defaultLoadedTime;
|
||||
|
||||
/**
|
||||
* App-level default refreshRate used in determining when to refresh a given model.
|
||||
* Defaults to NSTimeIntervalSince1970, which essentially means all app models
|
||||
* will never refresh.
|
||||
*/
|
||||
+ (NSTimeInterval)defaultRefreshRate;
|
||||
|
||||
/**
|
||||
* Setter for defaultRefreshRate, which allows one to set an app-wide refreshRate
|
||||
* for all models, as opposed to having to set the refreshRate on every instantiation
|
||||
* of RKRequestTTModel.
|
||||
*/
|
||||
+ (void)setDefaultRefreshRate:(NSTimeInterval)newDefaultRefreshRate;
|
||||
|
||||
@end
|
||||
|
||||
@@ -7,56 +7,81 @@
|
||||
//
|
||||
|
||||
#import "RKRequestTTModel.h"
|
||||
#import "RKManagedObjectStore.h"
|
||||
#import "../Network/Network.h"
|
||||
|
||||
static NSTimeInterval defaultRefreshRate = NSTimeIntervalSince1970;
|
||||
static NSString* const kDefaultLoadedTimeKey = @"RKRequestTTModelDefaultLoadedTimeKey";
|
||||
|
||||
@interface RKRequestTTModel (Private)
|
||||
|
||||
- (void)clearLoadedTime;
|
||||
- (void)saveLoadedTime;
|
||||
- (BOOL)errorWarrantsOptionToGoOffline:(NSError*)error;
|
||||
- (void)showAlertWithOptionToGoOfflineForError:(NSError*)error;
|
||||
- (void)alertView:(UIAlertView *)alertView didDismissWithButtonIndex:(NSInteger)buttonIndex;
|
||||
- (void)modelsDidLoad:(NSArray*)models;
|
||||
- (void)load;
|
||||
|
||||
@end
|
||||
|
||||
|
||||
@implementation RKRequestTTModel
|
||||
|
||||
@synthesize model = _model;
|
||||
@synthesize objects = _objects;
|
||||
@synthesize resourcePath = _resourcePath;
|
||||
@synthesize params = _params;
|
||||
@synthesize method = _method;
|
||||
@synthesize refreshRate = _refreshRate;
|
||||
|
||||
+ (NSDate*)defaultLoadedTime {
|
||||
NSDate* defaultLoadedTime = [[NSUserDefaults standardUserDefaults] objectForKey:kDefaultLoadedTimeKey];
|
||||
if (defaultLoadedTime == nil) {
|
||||
defaultLoadedTime = [NSDate date];
|
||||
[[NSUserDefaults standardUserDefaults] setObject:defaultLoadedTime forKey:kDefaultLoadedTimeKey];
|
||||
}
|
||||
return defaultLoadedTime;
|
||||
}
|
||||
|
||||
+ (NSTimeInterval)defaultRefreshRate {
|
||||
return defaultRefreshRate;
|
||||
}
|
||||
|
||||
+ (void)setDefaultRefreshRate:(NSTimeInterval)newDefaultRefreshRate {
|
||||
defaultRefreshRate = defaultRefreshRate;
|
||||
}
|
||||
|
||||
- (id)initWithResourcePath:(NSString*)resourcePath {
|
||||
if (self = [self init]) {
|
||||
_model = [[RKRequestModel alloc] initWithResourcePath:resourcePath delegate:self];
|
||||
_resourcePath = [resourcePath retain];
|
||||
}
|
||||
return self;
|
||||
}
|
||||
|
||||
- (id)initWithResourcePath:(NSString*)resourcePath params:(NSDictionary*)params {
|
||||
if (self = [self init]) {
|
||||
_model = [[RKRequestModel alloc] initWithResourcePath:resourcePath params:params delegate:self];
|
||||
}
|
||||
if (self = [self initWithResourcePath:resourcePath]) {
|
||||
self.params = [params retain];
|
||||
}
|
||||
return self;
|
||||
}
|
||||
|
||||
- (id)initWithResourcePath:(NSString*)resourcePath params:(NSDictionary*)params objectClass:(Class)klass{
|
||||
if (self = [self init]) {
|
||||
_model = [[RKRequestModel alloc] initWithResourcePath:resourcePath params:params objectClass:klass delegate:self];
|
||||
- (id)initWithResourcePath:(NSString*)resourcePath params:(NSDictionary*)params objectClass:(Class)klass {
|
||||
if (self = [self initWithResourcePath:resourcePath params:params]) {
|
||||
_objectClass = [klass retain];
|
||||
}
|
||||
return self;
|
||||
}
|
||||
|
||||
- (id)initWithResourcePath:(NSString*)resourcePath params:(NSDictionary*)params objectClass:(Class)klass keyPath:(NSString*)keyPath {
|
||||
if (self = [self init]) {
|
||||
_model = [[RKRequestModel alloc] initWithResourcePath:resourcePath params:params objectClass:klass keyPath:keyPath delegate:self];
|
||||
if (self = [self initWithResourcePath:resourcePath params:params objectClass:klass]) {
|
||||
_keyPath = [keyPath retain];
|
||||
}
|
||||
return self;
|
||||
}
|
||||
|
||||
- (id)initWithResourcePath:(NSString*)resourcePath params:(NSDictionary*)params method:(RKRequestMethod)method {
|
||||
if (self = [self init]) {
|
||||
_model = [[RKRequestModel alloc] initWithResourcePath:resourcePath params:params method:method delegate:self];
|
||||
}
|
||||
return self;
|
||||
}
|
||||
|
||||
- (id)initWithResourcePath:(NSString*)resourcePath params:(NSDictionary*)params method:(RKRequestMethod)method objectClass:(Class)klass {
|
||||
if (self = [self init]) {
|
||||
_model = [[RKRequestModel alloc] initWithResourcePath:resourcePath params:params method:method objectClass:klass delegate:self];
|
||||
}
|
||||
return self;
|
||||
}
|
||||
|
||||
- (id)initWithResourcePath:(NSString*)resourcePath params:(NSDictionary*)params method:(RKRequestMethod)method objectClass:(Class)klass keyPath:(NSString*)keyPath {
|
||||
if (self = [self init]) {
|
||||
_model = [[RKRequestModel alloc] initWithResourcePath:resourcePath params:params method:method objectClass:klass keyPath:keyPath delegate:self];
|
||||
if (self = [self initWithResourcePath:resourcePath params:params]) {
|
||||
_method = method;
|
||||
}
|
||||
return self;
|
||||
}
|
||||
@@ -66,14 +91,29 @@
|
||||
|
||||
- (id)init {
|
||||
if (self = [super init]) {
|
||||
_model = nil;
|
||||
self.method = RKRequestMethodGET;
|
||||
self.refreshRate = [RKRequestTTModel defaultRefreshRate];
|
||||
self.params = nil;
|
||||
_cacheLoaded = NO;
|
||||
_objects = nil;
|
||||
_isLoaded = NO;
|
||||
_isLoading = NO;
|
||||
_resourcePath = nil;
|
||||
}
|
||||
return self;
|
||||
}
|
||||
|
||||
- (void)dealloc {
|
||||
[_model release];
|
||||
_model = nil;
|
||||
[[RKRequestQueue sharedQueue] cancelRequestsWithDelegate:self];
|
||||
[_objects release];
|
||||
_objects = nil;
|
||||
[_resourcePath release];
|
||||
_resourcePath = nil;
|
||||
[_objectClass release];
|
||||
_objectClass = nil;
|
||||
[_keyPath release];
|
||||
_keyPath = nil;
|
||||
self.params = nil;
|
||||
[super dealloc];
|
||||
}
|
||||
|
||||
@@ -81,11 +121,11 @@
|
||||
// TTModel
|
||||
|
||||
- (BOOL)isLoaded {
|
||||
return _model.loaded;
|
||||
return _isLoaded;
|
||||
}
|
||||
|
||||
- (BOOL)isLoading {
|
||||
return nil != _model.objectLoader;
|
||||
return _isLoading;
|
||||
}
|
||||
|
||||
- (BOOL)isLoadingMore {
|
||||
@@ -93,52 +133,138 @@
|
||||
}
|
||||
|
||||
- (BOOL)isOutdated {
|
||||
return NO;
|
||||
return (![self isLoading] && (-[self.loadedTime timeIntervalSinceNow] > _refreshRate));
|
||||
}
|
||||
|
||||
- (void)cancel {
|
||||
if (_model && _model.objectLoader.request) {
|
||||
[_model.objectLoader.request cancel];
|
||||
}
|
||||
[[RKRequestQueue sharedQueue] cancelRequestsWithDelegate:self];
|
||||
[self didCancelLoad];
|
||||
}
|
||||
|
||||
- (void)invalidate:(BOOL)erase {
|
||||
// TODO: Note sure how to handle erase...
|
||||
[_model clearLoadedTime];
|
||||
}
|
||||
|
||||
- (void)reset {
|
||||
[_model reset];
|
||||
[self clearLoadedTime];
|
||||
}
|
||||
|
||||
- (void)load:(TTURLRequestCachePolicy)cachePolicy more:(BOOL)more {
|
||||
[_model load];
|
||||
[self load];
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
// RKRequestModelDelegate
|
||||
|
||||
- (void)rkModelDidStartLoad {
|
||||
[self didStartLoad];
|
||||
- (NSDate*)loadedTime {
|
||||
NSDate* loadedTime = [[NSUserDefaults standardUserDefaults] objectForKey:_resourcePath];
|
||||
if (loadedTime == nil) {
|
||||
return [RKRequestTTModel defaultLoadedTime];
|
||||
}
|
||||
return loadedTime;
|
||||
}
|
||||
|
||||
- (void)rkModelDidFailLoadWithError:(NSError*)error {
|
||||
#pragma mark RKModelLoaderDelegate
|
||||
|
||||
- (void)objectLoader:(RKObjectLoader*)objectLoader didLoadObjects:(NSArray*)objects {
|
||||
_isLoading = NO;
|
||||
[self saveLoadedTime];
|
||||
[self modelsDidLoad:objects];
|
||||
}
|
||||
|
||||
- (void)objectLoader:(RKObjectLoader*)objectLoader didFailWithError:(NSError*)error {
|
||||
_isLoading = NO;
|
||||
[self didFailLoadWithError:error];
|
||||
// if ([self errorWarrantsOptionToGoOffline:error]) {
|
||||
// [self showAlertWithOptionToGoOfflineForError:error];
|
||||
// }
|
||||
}
|
||||
|
||||
- (void)rkModelDidCancelLoad {
|
||||
[self didCancelLoad];
|
||||
- (void)objectLoaderDidLoadUnexpectedResponse:(RKObjectLoader*)objectLoader {
|
||||
_isLoading = NO;
|
||||
|
||||
// TODO: Passing a nil error here does nothing for Three20. Need to construct our
|
||||
// own error here to make Three20 happy??
|
||||
[self didFailLoadWithError:nil];
|
||||
}
|
||||
|
||||
- (void)rkModelDidLoad {
|
||||
|
||||
#pragma mark RKRequestTTModel (Private)
|
||||
|
||||
- (void)clearLoadedTime {
|
||||
[[NSUserDefaults standardUserDefaults] removeObjectForKey:_resourcePath];
|
||||
}
|
||||
|
||||
- (void)saveLoadedTime {
|
||||
[[NSUserDefaults standardUserDefaults] setObject:[NSDate date] forKey:_resourcePath];
|
||||
}
|
||||
|
||||
- (BOOL)errorWarrantsOptionToGoOffline:(NSError*)error {
|
||||
switch ([error code]) {
|
||||
case NSURLErrorTimedOut:
|
||||
case NSURLErrorCannotFindHost:
|
||||
case NSURLErrorCannotConnectToHost:
|
||||
case NSURLErrorNetworkConnectionLost:
|
||||
case NSURLErrorDNSLookupFailed:
|
||||
case NSURLErrorNotConnectedToInternet:
|
||||
case NSURLErrorInternationalRoamingOff:
|
||||
return YES;
|
||||
break;
|
||||
default:
|
||||
return NO;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
- (void)showAlertWithOptionToGoOfflineForError:(NSError*)error {
|
||||
UIAlertView* alert = [[[UIAlertView alloc] initWithTitle:TTLocalizedString(@"Network Error", @"")
|
||||
message:[error localizedDescription]
|
||||
delegate:self
|
||||
cancelButtonTitle:TTLocalizedString(@"OK", @"")
|
||||
otherButtonTitles:TTLocalizedString(@"Go Offline", @""), nil] autorelease];
|
||||
[alert show];
|
||||
}
|
||||
|
||||
- (void)alertView:(UIAlertView*)alertView didDismissWithButtonIndex:(NSInteger)buttonIndex {
|
||||
// Go Offline button
|
||||
if (1 == buttonIndex) {
|
||||
[[RKObjectManager sharedManager] goOffline];
|
||||
}
|
||||
}
|
||||
|
||||
- (void)modelsDidLoad:(NSArray*)models {
|
||||
[models retain];
|
||||
[_objects release];
|
||||
_objects = nil;
|
||||
|
||||
_objects = models;
|
||||
_isLoaded = YES;
|
||||
|
||||
[self didFinishLoad];
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
// public
|
||||
|
||||
- (NSArray*)objects {
|
||||
return _model.objects;
|
||||
- (void)load {
|
||||
RKManagedObjectStore* store = [RKObjectManager sharedManager].objectStore;
|
||||
NSArray* cacheFetchRequests = nil;
|
||||
NSArray* cachedObjects = nil;
|
||||
if (store.managedObjectCache) {
|
||||
cacheFetchRequests = [store.managedObjectCache fetchRequestsForResourcePath:self.resourcePath];
|
||||
cachedObjects = [RKManagedObject objectsWithFetchRequests:cacheFetchRequests];
|
||||
}
|
||||
|
||||
if (!store.managedObjectCache || !cacheFetchRequests || _cacheLoaded ||
|
||||
([cachedObjects count] == 0 && [[RKObjectManager sharedManager] isOnline])) {
|
||||
RKObjectLoader* objectLoader = [[[RKObjectManager sharedManager] objectLoaderWithResourcePath:_resourcePath delegate:self] retain];
|
||||
objectLoader.method = self.method;
|
||||
objectLoader.objectClass = _objectClass;
|
||||
objectLoader.keyPath = _keyPath;
|
||||
objectLoader.params = self.params;
|
||||
|
||||
_isLoading = YES;
|
||||
[self didStartLoad];
|
||||
[objectLoader send];
|
||||
|
||||
} else if (cacheFetchRequests && !_cacheLoaded) {
|
||||
_cacheLoaded = YES;
|
||||
[self modelsDidLoad:cachedObjects];
|
||||
}
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
@@ -6,6 +6,5 @@
|
||||
// Copyright 2010 Two Toasters. All rights reserved.
|
||||
//
|
||||
|
||||
#import "RKRequestModel.h"
|
||||
#import "RKRequestTTModel.h"
|
||||
#import "RKRequestFilterableTTModel.h"
|
||||
|
||||
Reference in New Issue
Block a user