mirror of
https://github.com/zhigang1992/RestKit.git
synced 2026-04-23 04:20:21 +08:00
Add support for the registration of HTTP request operation subclasses on the manager to support easy customization of request operation handling. refs #997
This commit is contained in:
@@ -54,8 +54,7 @@
|
||||
@property (nonatomic, strong) NSSet *acceptableContentTypes;
|
||||
|
||||
/**
|
||||
Whether the response received a 304 response, whether via the initial request, or by virtue of
|
||||
cache revalidation occurring from NSURLCache.
|
||||
Whether the response received a 304 response, whether via the initial request, or by virtue of cache revalidation occurring from `NSURLCache`.
|
||||
*/
|
||||
@property (nonatomic, readonly) BOOL wasNotModified;
|
||||
|
||||
|
||||
@@ -92,8 +92,8 @@
|
||||
return [[RKMappingResult alloc] initWithDictionary:@{}];
|
||||
}
|
||||
|
||||
RKManagedObjectResponseMapperOperation *mapperOperation = [[RKManagedObjectResponseMapperOperation alloc] initWithResponse:self.response
|
||||
data:self.responseData
|
||||
RKManagedObjectResponseMapperOperation *mapperOperation = [[RKManagedObjectResponseMapperOperation alloc] initWithResponse:self.HTTPRequestOperation.response
|
||||
data:self.HTTPRequestOperation.responseData
|
||||
responseDescriptors:self.responseDescriptors];
|
||||
mapperOperation.targetObjectID = self.targetObjectID;
|
||||
mapperOperation.managedObjectContext = self.privateContext;
|
||||
@@ -113,8 +113,8 @@
|
||||
__block BOOL _blockSuccess = YES;
|
||||
|
||||
if (self.targetObjectID
|
||||
&& NSLocationInRange(self.response.statusCode, RKStatusCodeRangeForClass(RKStatusCodeClassSuccessful))
|
||||
&& [[[self.request HTTPMethod] uppercaseString] isEqualToString:@"DELETE"]) {
|
||||
&& NSLocationInRange(self.HTTPRequestOperation.response.statusCode, RKStatusCodeRangeForClass(RKStatusCodeClassSuccessful))
|
||||
&& [[[self.HTTPRequestOperation.request HTTPMethod] uppercaseString] isEqualToString:@"DELETE"]) {
|
||||
|
||||
// 2xx DELETE request, proceed with deletion from the MOC
|
||||
__block NSError *_blockError = nil;
|
||||
@@ -142,7 +142,7 @@
|
||||
__block NSArray *_blockObjects;
|
||||
|
||||
// Pass the fetch request blocks a relative `NSURL` object if possible
|
||||
NSURL *URL = [self.request URL];
|
||||
NSURL *URL = [self.HTTPRequestOperation.request URL];
|
||||
NSArray *baseURLs = [self.responseDescriptors valueForKeyPath:@"@distinctUnionOfObjects.baseURL"];
|
||||
if ([baseURLs count] == 1) {
|
||||
NSURL *baseURL = baseURLs[0];
|
||||
@@ -180,7 +180,7 @@
|
||||
return YES;
|
||||
}
|
||||
|
||||
if (! [[self.request.HTTPMethod uppercaseString] isEqualToString:@"GET"]) {
|
||||
if (! [[self.HTTPRequestOperation.request.HTTPMethod uppercaseString] isEqualToString:@"GET"]) {
|
||||
RKLogDebug(@"Skipping cleanup of objects via managed object cache: only used for GET requests.");
|
||||
return YES;
|
||||
}
|
||||
|
||||
@@ -390,6 +390,18 @@ RKMappingResult, RKRequestDescriptor, RKResponseDescriptor;
|
||||
/// @name Creating Object Request Operations
|
||||
///-----------------------------------------
|
||||
|
||||
/**
|
||||
Sets the `RKHTTPRequestOperation` subclass to be used when constructing HTTP request operations for requests dispatched through the manager.
|
||||
|
||||
When set, an instance of the given class will be initialized via `initWithRequest:` each time that the receiver constructs an HTTP request operation. HTTP request operations are used to initialize instances of `RKObjectRequestOperation` and are responsible for managing the HTTP request/response lifecycle of a request whose response is destined to be object mapped. Providing a subclass implementation of `RKHTTPRequestOperation` allows the behavior of all requests sent through the manager to be changed.
|
||||
|
||||
@param operationClass A class object inheriting from `RKHTTPRequestOperation` to be used for HTTP requests dispatched through the manager.
|
||||
@raises `NSInvalidArgumentException` Raised if the given class does not inherit from `RKHTTPRequestOperation`.
|
||||
@see `RKHTTPRequestOperation`
|
||||
@warning The given class must inherit from `RKHTTPRequestOperation`, else an exception will be raised.
|
||||
*/
|
||||
- (void)setHTTPOperationClass:(Class)operationClass;
|
||||
|
||||
/**
|
||||
Creates an `RKObjectRequestOperation` operation with the given request and sets the completion block with the given success and failure blocks.
|
||||
|
||||
|
||||
@@ -121,6 +121,7 @@ static NSString *RKMIMETypeFromAFHTTPClientParameterEncoding(AFHTTPClientParamet
|
||||
@property (nonatomic, strong) NSMutableArray *mutableResponseDescriptors;
|
||||
@property (nonatomic, strong) NSMutableArray *mutableFetchRequestBlocks;
|
||||
@property (nonatomic, strong) NSString *acceptHeaderValue;
|
||||
@property (nonatomic) Class HTTPOperationClass;
|
||||
@end
|
||||
|
||||
@implementation RKObjectManager
|
||||
@@ -288,11 +289,23 @@ static NSString *RKMIMETypeFromAFHTTPClientParameterEncoding(AFHTTPClientParamet
|
||||
return [self.HTTPClient multipartFormRequestWithMethod:stringMethod path:requestPath parameters:requestParameters constructingBodyWithBlock:block];
|
||||
}
|
||||
|
||||
- (void)setHTTPOperationClass:(Class)operationClass
|
||||
{
|
||||
NSAssert(operationClass == nil || [operationClass isSubclassOfClass:[RKHTTPRequestOperation class]], @"");
|
||||
_HTTPOperationClass = operationClass;
|
||||
}
|
||||
|
||||
- (RKHTTPRequestOperation *)HTTPOperationWithRequest:(NSURLRequest *)request
|
||||
{
|
||||
Class operationClass = self.HTTPOperationClass ?: [RKHTTPRequestOperation class];
|
||||
return [[operationClass alloc] initWithRequest:request];
|
||||
}
|
||||
|
||||
- (RKObjectRequestOperation *)objectRequestOperationWithRequest:(NSURLRequest *)request
|
||||
success:(void (^)(RKObjectRequestOperation *operation, RKMappingResult *mappingResult))success
|
||||
failure:(void (^)(RKObjectRequestOperation *operation, NSError *error))failure
|
||||
{
|
||||
RKObjectRequestOperation *operation = [[RKObjectRequestOperation alloc] initWithRequest:request responseDescriptors:self.responseDescriptors];
|
||||
RKObjectRequestOperation *operation = [[RKObjectRequestOperation alloc] initWithHTTPRequestOperation:[self HTTPOperationWithRequest:request] responseDescriptors:self.responseDescriptors];
|
||||
[operation setCompletionBlockWithSuccess:success failure:failure];
|
||||
return operation;
|
||||
}
|
||||
@@ -302,7 +315,7 @@ static NSString *RKMIMETypeFromAFHTTPClientParameterEncoding(AFHTTPClientParamet
|
||||
success:(void (^)(RKObjectRequestOperation *operation, RKMappingResult *mappingResult))success
|
||||
failure:(void (^)(RKObjectRequestOperation *operation, NSError *error))failure
|
||||
{
|
||||
RKManagedObjectRequestOperation *operation = [[RKManagedObjectRequestOperation alloc] initWithRequest:request responseDescriptors:self.responseDescriptors];
|
||||
RKManagedObjectRequestOperation *operation = [[RKManagedObjectRequestOperation alloc] initWithHTTPRequestOperation:[self HTTPOperationWithRequest:request] responseDescriptors:self.responseDescriptors];
|
||||
[operation setCompletionBlockWithSuccess:success failure:failure];
|
||||
operation.managedObjectContext = managedObjectContext;
|
||||
operation.managedObjectCache = self.managedObjectStore.managedObjectCache;
|
||||
@@ -514,7 +527,7 @@ static NSString *RKMIMETypeFromAFHTTPClientParameterEncoding(AFHTTPClientParamet
|
||||
continue;
|
||||
}
|
||||
|
||||
NSURLRequest *request = [(RKObjectRequestOperation *)operation request];
|
||||
NSURLRequest *request = [(RKObjectRequestOperation *)operation HTTPRequestOperation].request;
|
||||
NSString *pathAndQueryString = RKPathAndQueryStringFromURLRelativeToURL([request URL], self.baseURL);
|
||||
if ((!methodName || [methodName isEqualToString:[request HTTPMethod]]) && [pathMatcher matchesPath:pathAndQueryString tokenizeQueryStrings:NO parsedArguments:nil]) {
|
||||
[operation cancel];
|
||||
|
||||
@@ -56,10 +56,24 @@
|
||||
///-----------------------------------------------
|
||||
|
||||
/**
|
||||
Initializes an object request operation with a request object and a set of response descriptors.
|
||||
Initializes an object request operation with an HTTP request operation and a set of response descriptors.
|
||||
|
||||
This is the designated initializer.
|
||||
|
||||
@param request The request object to be used with the underlying network operation.
|
||||
@param responseDescriptors An array of `RKResponseDescriptor` objects specifying how object mapping is to be performed on the response loaded by the network operation.
|
||||
@return The receiver, initialized with the given request and response descriptors.
|
||||
*/
|
||||
- (id)initWithHTTPRequestOperation:(RKHTTPRequestOperation *)requestOperation responseDescriptors:(NSArray *)responseDescriptors;
|
||||
|
||||
/**
|
||||
Initializes an object request operation with a request object and a set of response descriptors.
|
||||
|
||||
This method is a convenience initializer for initializing an object request operation from a URL request with the default HTTP operation class `RKHTTPRequestOperation`. This method is functionally equivalent to the following example code:
|
||||
|
||||
RKHTTPRequestOperation *requestOperation = [[RKHTTPRequestOperation alloc] initWithRequest:request];
|
||||
RKObjectRequestOperation *objectRequestOperation = [[RKObjectRequestOperation alloc] initWithHTTPRequestOperation:requestOperation responseDescriptors:responseDescriptors];
|
||||
|
||||
@param request The request object to be used with the underlying network operation.
|
||||
@param responseDescriptors An array of `RKResponseDescriptor` objects specifying how object mapping is to be performed on the response loaded by the network operation.
|
||||
@return The receiver, initialized with the given request and response descriptors.
|
||||
@@ -100,26 +114,14 @@
|
||||
*/
|
||||
@property (nonatomic, strong, readonly) NSError *error;
|
||||
|
||||
///-----------------------------------
|
||||
/// @name Accessing Network Properties
|
||||
///-----------------------------------
|
||||
///-------------------------------------------
|
||||
/// @name Accessing the HTTP Request Operation
|
||||
///-------------------------------------------
|
||||
|
||||
/**
|
||||
The request object used by the underlying `RKHTTPRequestOperation` network operation.
|
||||
The underlying `RKHTTPRequestOperation` object used to manage the HTTP request/response lifecycle of the object request operation.
|
||||
*/
|
||||
@property (nonatomic, strong, readonly) NSURLRequest *request;
|
||||
|
||||
/**
|
||||
The response object loaded by the underlying `RKHTTPRequestOperation` network operation.
|
||||
*/
|
||||
@property (nonatomic, readonly) NSHTTPURLResponse *response;
|
||||
|
||||
/**
|
||||
The response data loaded by the underlying `RKHTTRequestOperation` network operation.
|
||||
|
||||
Object mapping is performed on the deserialized `responseData`.
|
||||
*/
|
||||
@property (nonatomic, readonly) NSData *responseData;
|
||||
@property (nonatomic, strong, readonly) RKHTTPRequestOperation *HTTPRequestOperation;
|
||||
|
||||
///-------------------------------------------------------
|
||||
/// @name Setting the Completion Block and Callback Queues
|
||||
|
||||
@@ -45,11 +45,10 @@ static NSIndexSet *RKObjectRequestOperationAcceptableMIMETypes()
|
||||
}
|
||||
|
||||
@interface RKObjectRequestOperation ()
|
||||
@property (nonatomic, strong, readwrite) RKHTTPRequestOperation *requestOperation;
|
||||
@property (nonatomic, strong, readwrite) RKHTTPRequestOperation *HTTPRequestOperation;
|
||||
@property (nonatomic, strong, readwrite) NSArray *responseDescriptors;
|
||||
@property (nonatomic, strong, readwrite) RKMappingResult *mappingResult;
|
||||
@property (nonatomic, strong, readwrite) NSError *error;
|
||||
@property (nonatomic, strong, readwrite) NSURLRequest *request;
|
||||
@end
|
||||
|
||||
@implementation RKObjectRequestOperation
|
||||
@@ -62,23 +61,30 @@ static NSIndexSet *RKObjectRequestOperationAcceptableMIMETypes()
|
||||
#endif
|
||||
}
|
||||
|
||||
- (id)initWithRequest:(NSURLRequest *)request responseDescriptors:(NSArray *)responseDescriptors
|
||||
// Designated initializer
|
||||
- (id)initWithHTTPRequestOperation:(RKHTTPRequestOperation *)requestOperation responseDescriptors:(NSArray *)responseDescriptors
|
||||
{
|
||||
NSParameterAssert(request);
|
||||
NSParameterAssert(requestOperation);
|
||||
NSParameterAssert(responseDescriptors);
|
||||
|
||||
self = [self init];
|
||||
if (self) {
|
||||
self.request = request;
|
||||
self.responseDescriptors = responseDescriptors;
|
||||
self.requestOperation = [[RKHTTPRequestOperation alloc] initWithRequest:request];
|
||||
self.requestOperation.acceptableContentTypes = [RKMIMETypeSerialization registeredMIMETypes];
|
||||
self.requestOperation.acceptableStatusCodes = RKObjectRequestOperationAcceptableMIMETypes();
|
||||
self.HTTPRequestOperation = requestOperation;
|
||||
self.HTTPRequestOperation.acceptableContentTypes = [RKMIMETypeSerialization registeredMIMETypes];
|
||||
self.HTTPRequestOperation.acceptableStatusCodes = RKObjectRequestOperationAcceptableMIMETypes();
|
||||
}
|
||||
|
||||
return self;
|
||||
}
|
||||
|
||||
- (id)initWithRequest:(NSURLRequest *)request responseDescriptors:(NSArray *)responseDescriptors
|
||||
{
|
||||
NSParameterAssert(request);
|
||||
NSParameterAssert(responseDescriptors);
|
||||
return [self initWithHTTPRequestOperation:[[RKHTTPRequestOperation alloc] initWithRequest:request] responseDescriptors:responseDescriptors];
|
||||
}
|
||||
|
||||
- (void)setSuccessCallbackQueue:(dispatch_queue_t)successCallbackQueue
|
||||
{
|
||||
if (successCallbackQueue != _successCallbackQueue) {
|
||||
@@ -142,21 +148,11 @@ static NSIndexSet *RKObjectRequestOperationAcceptableMIMETypes()
|
||||
};
|
||||
}
|
||||
|
||||
- (NSHTTPURLResponse *)response
|
||||
{
|
||||
return (NSHTTPURLResponse *)self.requestOperation.response;
|
||||
}
|
||||
|
||||
- (NSData *)responseData
|
||||
{
|
||||
return self.requestOperation.responseData;
|
||||
}
|
||||
|
||||
- (RKMappingResult *)performMappingOnResponse:(NSError **)error
|
||||
{
|
||||
// Spin up an RKObjectResponseMapperOperation
|
||||
RKObjectResponseMapperOperation *mapperOperation = [[RKObjectResponseMapperOperation alloc] initWithResponse:self.response
|
||||
data:self.responseData
|
||||
RKObjectResponseMapperOperation *mapperOperation = [[RKObjectResponseMapperOperation alloc] initWithResponse:self.HTTPRequestOperation.response
|
||||
data:self.HTTPRequestOperation.responseData
|
||||
responseDescriptors:self.responseDescriptors];
|
||||
mapperOperation.targetObject = self.targetObject;
|
||||
[mapperOperation start];
|
||||
@@ -176,7 +172,7 @@ static NSIndexSet *RKObjectRequestOperationAcceptableMIMETypes()
|
||||
- (void)cancel
|
||||
{
|
||||
[super cancel];
|
||||
[self.requestOperation cancel];
|
||||
[self.HTTPRequestOperation cancel];
|
||||
}
|
||||
|
||||
- (void)main
|
||||
@@ -184,12 +180,12 @@ static NSIndexSet *RKObjectRequestOperationAcceptableMIMETypes()
|
||||
if (self.isCancelled) return;
|
||||
|
||||
// Send the request
|
||||
[self.requestOperation start];
|
||||
[self.requestOperation waitUntilFinished];
|
||||
[self.HTTPRequestOperation start];
|
||||
[self.HTTPRequestOperation waitUntilFinished];
|
||||
|
||||
if (self.requestOperation.error) {
|
||||
RKLogError(@"Object request failed: Underlying HTTP request operation failed with error: %@", self.requestOperation.error);
|
||||
self.error = self.requestOperation.error;
|
||||
if (self.HTTPRequestOperation.error) {
|
||||
RKLogError(@"Object request failed: Underlying HTTP request operation failed with error: %@", self.HTTPRequestOperation.error);
|
||||
self.error = self.HTTPRequestOperation.error;
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
@@ -42,6 +42,11 @@
|
||||
|
||||
@end
|
||||
|
||||
@interface RKTestHTTPRequestOperation : RKHTTPRequestOperation
|
||||
@end
|
||||
@implementation RKTestHTTPRequestOperation : RKHTTPRequestOperation
|
||||
@end
|
||||
|
||||
@interface RKObjectManagerTest : RKTestCase
|
||||
|
||||
@property (nonatomic, strong) RKObjectManager *objectManager;
|
||||
@@ -354,7 +359,7 @@
|
||||
temporaryHuman.name = @"My Name";
|
||||
temporaryHuman.railsID = @204;
|
||||
RKManagedObjectRequestOperation *operation = [_objectManager appropriateObjectRequestOperationWithObject:temporaryHuman method:RKRequestMethodGET path:nil parameters:@{@"this": @"that"}];
|
||||
expect([operation.request.URL absoluteString]).to.equal(@"http://127.0.0.1:4567/humans/204?this=that");
|
||||
expect([operation.HTTPRequestOperation.request.URL absoluteString]).to.equal(@"http://127.0.0.1:4567/humans/204?this=that");
|
||||
}
|
||||
|
||||
- (void)testThatObjectParametersAreNotSentDuringDeleteObject
|
||||
@@ -363,7 +368,7 @@
|
||||
temporaryHuman.name = @"My Name";
|
||||
temporaryHuman.railsID = @204;
|
||||
RKManagedObjectRequestOperation *operation = [_objectManager appropriateObjectRequestOperationWithObject:temporaryHuman method:RKRequestMethodDELETE path:nil parameters:@{@"this": @"that"}];
|
||||
expect([operation.request.URL absoluteString]).to.equal(@"http://127.0.0.1:4567/humans/204?this=that");
|
||||
expect([operation.HTTPRequestOperation.request.URL absoluteString]).to.equal(@"http://127.0.0.1:4567/humans/204?this=that");
|
||||
}
|
||||
|
||||
- (void)testInitializationOfObjectRequestOperationProducesCorrectURLRequest
|
||||
@@ -404,6 +409,25 @@
|
||||
expect([request allHTTPHeaderFields][@"Accept"]).to.equal(@"application/json");
|
||||
}
|
||||
|
||||
- (void)testRegistrationOfHTTPRequestOperationClass
|
||||
{
|
||||
RKObjectManager *manager = [RKObjectManager managerWithBaseURL:[NSURL URLWithString:@"http://restkit.org"]];
|
||||
[manager setHTTPOperationClass:[RKTestHTTPRequestOperation class]];
|
||||
NSURLRequest *request = [NSURLRequest requestWithURL:[NSURL URLWithString:@"/test" relativeToURL:manager.baseURL]];
|
||||
RKObjectRequestOperation *operation = [manager objectRequestOperationWithRequest:request success:nil failure:nil];
|
||||
expect(operation.HTTPRequestOperation).to.beKindOf([RKTestHTTPRequestOperation class]);
|
||||
}
|
||||
|
||||
- (void)testSettingNilHTTPRequestOperationClassRestoresDefaultHTTPOperationClass
|
||||
{
|
||||
RKObjectManager *manager = [RKObjectManager managerWithBaseURL:[NSURL URLWithString:@"http://restkit.org"]];
|
||||
[manager setHTTPOperationClass:[RKTestHTTPRequestOperation class]];
|
||||
[manager setHTTPOperationClass:nil];
|
||||
NSURLRequest *request = [NSURLRequest requestWithURL:[NSURL URLWithString:@"/test" relativeToURL:manager.baseURL]];
|
||||
RKObjectRequestOperation *operation = [manager objectRequestOperationWithRequest:request success:nil failure:nil];
|
||||
expect(operation.HTTPRequestOperation).to.beKindOf([RKHTTPRequestOperation class]);
|
||||
}
|
||||
|
||||
// TODO: Move to Core Data specific spec file...
|
||||
//- (void)testShouldLoadAHuman
|
||||
//{
|
||||
|
||||
Reference in New Issue
Block a user