mirror of
https://github.com/zhigang1992/RestKit.git
synced 2026-04-29 13:15:34 +08:00
Add support for customizing the RKObjectRequestOperation and RKManagedObjectRequestOperation instances built through the object manager using a registration API very similar to that of AFHTTPClient. closes #1131
This commit is contained in:
@@ -430,11 +430,32 @@ RKMappingResult, RKRequestDescriptor, RKResponseDescriptor;
|
||||
@see `RKHTTPRequestOperation`
|
||||
@warning The given class must inherit from `RKHTTPRequestOperation`, else an exception will be raised.
|
||||
*/
|
||||
- (void)setHTTPOperationClass:(Class)operationClass;
|
||||
- (void)setHTTPRequestOperationClass:(Class)operationClass;
|
||||
|
||||
/**
|
||||
Attempts to register a subclass of `RKObjectRequestOperation`, adding it to a list of classes that are consulted each time the receiver needs to construct an object request operation with a URL request.
|
||||
|
||||
When `objectRequestOperationWithRequest:success:failure:` or `managedObjectRequestOperationWithRequest:managedObjectContext:success:failure:` is invoked, each registered subclass is consulted to see if it can handle the request. The first class to return `YES` when sent a `+ canProcessRequest:` message is used to create an operation using `initWithHTTPRequestOperation:responseDescriptors:`. The HTTP request operation class sent is an `RKHTTPRequestOperation` object whose type is of the class configured by `setHTTPRequestOperationClass:`, with a default value of `RKHTTPRequestOperation`.
|
||||
|
||||
There is no guarantee that all registered classes will be consulted. The object manager will only consider direct subclasses of `RKObjectRequestOperation` when `objectRequestOperationWithRequest:success:failure` is called and will only consider subclasses of `RKManagedObjectRequestOperation` when `managedObjectRequestOperationWithRequest:managedObjectContext:success:failure:` is called. If you wish to map a mixture of managed and unmanaged objects within the same object request operation you must register a `RKManagedObjectRequestOperation` subclass. Classes are consulted in the reverse order of their registration. Attempting to register an already-registered class will move it to the top of the list.
|
||||
|
||||
@param operationClass The subclass of `RKObjectRequestOperation` to register.
|
||||
@return `YES` if the given class was registered successfully, else `NO`. The only failure condition is if `operationClass` is not a subclass of `RKObjectRequestOperation`.
|
||||
*/
|
||||
- (BOOL)registerObjectRequestOperationClass:(Class)operationClass;
|
||||
|
||||
/**
|
||||
Unregisters the specified subclass of `RKObjectRequestOperation` from the list of classes consulted when `objectRequestOperationWithRequest:success:failure:` or `managedObjectRequestOperationWithRequest:managedObjectContext:success:failure:` is called.
|
||||
|
||||
@param operationClass The subclass of `RKObjectRequestOperation` to register
|
||||
*/
|
||||
- (void)unregisterObjectRequestOperationClass:(Class)operationClass;
|
||||
|
||||
/**
|
||||
Creates an `RKObjectRequestOperation` operation with the given request and sets the completion block with the given success and failure blocks.
|
||||
|
||||
In order to determine what kind of operation is created, each registered `RKObjectRequestOperation` subclass is consulted (in reverse order of when they were specified) to see if it can handle the specific request. The first class to return `YES` when sent a `canProcessRequest:` message is used to create an operation using `initWithHTTPRequestOperation:responseDescriptors:`. The HTTP request operation is an instance of `RKHTTPRequestOperation` whose type is determined by `setHTTPRequestOperationClass:`.
|
||||
|
||||
@param request The request object to be loaded asynchronously during execution of the operation.
|
||||
@param success A block object to be executed when the request operation finishes successfully. This block has no return value and takes two arguments: the created object request operation and the `RKMappingResult` object created by object mapping the response data of request.
|
||||
@param failure A block object to be executed when the request operation finishes unsuccessfully, or that finishes successfully, but encountered an error while parsing the resonse data. This block has no return value and takes two arguments:, the created request operation and the `NSError` object describing the network or parsing error that occurred.
|
||||
@@ -451,6 +472,8 @@ RKMappingResult, RKRequestDescriptor, RKResponseDescriptor;
|
||||
|
||||
The given managed object context given will be used as the parent context of the private managed context in which the response is mapped and will be used to fetch the results upon invocation of the success completion block.
|
||||
|
||||
In order to determine what kind of operation is created, each registered `RKManagedObjectRequestOperation` subclass is consulted (in reverse order of when they were specified) to see if it can handle the specific request. The first class to return `YES` when sent a `canProcessRequest:` message is used to create an operation using `initWithHTTPRequestOperation:responseDescriptors:`. The HTTP request operation is an instance of `RKHTTPRequestOperation` whose type is determined by `setHTTPRequestOperationClass:`.
|
||||
|
||||
@param request The request object to be loaded asynchronously during execution of the operation.
|
||||
@param managedObjectContext The managed object context with which to associate the operation. This context will be used as the parent context of a new operation local `NSManagedObjectContext` with the `NSPrivateQueueConcurrencyType` concurrency type. Upon success, the private context will be saved and changes resulting from the object mapping will be 'pushed' to the given context.
|
||||
@param success A block object to be executed when the request operation finishes successfully. This block has no return value and takes two arguments: the created object request operation and the `RKMappingResult` object created by object mapping the response data of request.
|
||||
|
||||
@@ -277,6 +277,7 @@ static NSString *RKMIMETypeFromAFHTTPClientParameterEncoding(AFHTTPClientParamet
|
||||
@property (nonatomic, strong) NSMutableArray *mutableRequestDescriptors;
|
||||
@property (nonatomic, strong) NSMutableArray *mutableResponseDescriptors;
|
||||
@property (nonatomic, strong) NSMutableArray *mutableFetchRequestBlocks;
|
||||
@property (nonatomic, strong) NSMutableArray *registeredObjectRequestOperationClasses;
|
||||
@property (nonatomic) Class HTTPOperationClass;
|
||||
@end
|
||||
|
||||
@@ -292,6 +293,7 @@ static NSString *RKMIMETypeFromAFHTTPClientParameterEncoding(AFHTTPClientParamet
|
||||
self.mutableRequestDescriptors = [NSMutableArray new];
|
||||
self.mutableResponseDescriptors = [NSMutableArray new];
|
||||
self.mutableFetchRequestBlocks = [NSMutableArray new];
|
||||
self.registeredObjectRequestOperationClasses = [NSMutableArray new];
|
||||
self.requestSerializationMIMEType = RKMIMETypeFromAFHTTPClientParameterEncoding(client.parameterEncoding);
|
||||
|
||||
// Set shared manager if nil
|
||||
@@ -437,25 +439,68 @@ static NSString *RKMIMETypeFromAFHTTPClientParameterEncoding(AFHTTPClientParamet
|
||||
return multipartRequest;
|
||||
}
|
||||
|
||||
- (void)setHTTPOperationClass:(Class)operationClass
|
||||
{
|
||||
NSAssert(operationClass == nil || [operationClass isSubclassOfClass:[RKHTTPRequestOperation class]], @"The HTTP operation class must be a subclass of `RKHTTPRequestOperation`");
|
||||
_HTTPOperationClass = operationClass;
|
||||
}
|
||||
|
||||
- (RKHTTPRequestOperation *)HTTPOperationWithRequest:(NSURLRequest *)request
|
||||
- (RKHTTPRequestOperation *)HTTPRequestOperationWithRequest:(NSURLRequest *)request
|
||||
{
|
||||
Class operationClass = self.HTTPOperationClass ?: [RKHTTPRequestOperation class];
|
||||
return [[operationClass alloc] initWithRequest:request];
|
||||
}
|
||||
|
||||
#pragma mark - Registering Subclasses
|
||||
|
||||
- (void)setHTTPRequestOperationClass:(Class)operationClass
|
||||
{
|
||||
NSAssert(operationClass == nil || [operationClass isSubclassOfClass:[RKHTTPRequestOperation class]], @"The HTTP operation class must be a subclass of `RKHTTPRequestOperation`");
|
||||
_HTTPOperationClass = operationClass;
|
||||
}
|
||||
|
||||
- (BOOL)registerObjectRequestOperationClass:(Class)operationClass
|
||||
{
|
||||
if (![operationClass isSubclassOfClass:[RKObjectRequestOperation class]]) {
|
||||
return NO;
|
||||
}
|
||||
|
||||
[self.registeredObjectRequestOperationClasses removeObject:operationClass];
|
||||
[self.registeredObjectRequestOperationClasses insertObject:operationClass atIndex:0];
|
||||
|
||||
return YES;
|
||||
}
|
||||
|
||||
- (void)unregisterObjectRequestOperationClass:(Class)operationClass
|
||||
{
|
||||
[self.registeredObjectRequestOperationClasses removeObject:operationClass];
|
||||
}
|
||||
|
||||
#pragma mark - Object Request Operations
|
||||
|
||||
- (RKObjectRequestOperation *)objectRequestOperationWithRequest:(NSURLRequest *)request responseDescriptors:(NSArray *)responseDescriptors managed:(BOOL)isManaged
|
||||
{
|
||||
RKHTTPRequestOperation *HTTPRequestOperation = [self HTTPRequestOperationWithRequest:request];
|
||||
RKObjectRequestOperation *operation = nil;
|
||||
Class objectRequestOperationClass = nil;
|
||||
NSEnumerator *enumerator = [self.registeredObjectRequestOperationClasses reverseObjectEnumerator];
|
||||
while (!operation && (objectRequestOperationClass = [enumerator nextObject])) {
|
||||
if ((isManaged && ![objectRequestOperationClass isSubclassOfClass:[RKManagedObjectRequestOperation class]]) ||
|
||||
(!isManaged && [objectRequestOperationClass isSubclassOfClass:[RKManagedObjectRequestOperation class]])) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if ([objectRequestOperationClass canProcessRequest:request]) {
|
||||
operation = [(RKObjectRequestOperation *)[objectRequestOperationClass alloc] initWithHTTPRequestOperation:HTTPRequestOperation responseDescriptors:responseDescriptors];
|
||||
}
|
||||
}
|
||||
|
||||
if (!operation) {
|
||||
objectRequestOperationClass = isManaged ? [RKManagedObjectRequestOperation class] : [RKObjectRequestOperation class];
|
||||
operation = [(RKObjectRequestOperation *)[objectRequestOperationClass alloc] initWithHTTPRequestOperation:HTTPRequestOperation responseDescriptors:responseDescriptors];
|
||||
}
|
||||
return operation;
|
||||
}
|
||||
|
||||
- (RKObjectRequestOperation *)objectRequestOperationWithRequest:(NSURLRequest *)request
|
||||
success:(void (^)(RKObjectRequestOperation *operation, RKMappingResult *mappingResult))success
|
||||
failure:(void (^)(RKObjectRequestOperation *operation, NSError *error))failure
|
||||
{
|
||||
RKObjectRequestOperation *operation = [[RKObjectRequestOperation alloc] initWithHTTPRequestOperation:[self HTTPOperationWithRequest:request] responseDescriptors:self.responseDescriptors];
|
||||
RKObjectRequestOperation *operation = [self objectRequestOperationWithRequest:request responseDescriptors:self.responseDescriptors managed:NO];
|
||||
[operation setCompletionBlockWithSuccess:success failure:failure];
|
||||
return operation;
|
||||
}
|
||||
@@ -465,7 +510,7 @@ static NSString *RKMIMETypeFromAFHTTPClientParameterEncoding(AFHTTPClientParamet
|
||||
success:(void (^)(RKObjectRequestOperation *operation, RKMappingResult *mappingResult))success
|
||||
failure:(void (^)(RKObjectRequestOperation *operation, NSError *error))failure
|
||||
{
|
||||
RKManagedObjectRequestOperation *operation = [[RKManagedObjectRequestOperation alloc] initWithHTTPRequestOperation:[self HTTPOperationWithRequest:request] responseDescriptors:self.responseDescriptors];
|
||||
RKManagedObjectRequestOperation *operation = (RKManagedObjectRequestOperation *)[self objectRequestOperationWithRequest:request responseDescriptors:self.responseDescriptors managed:YES];
|
||||
[operation setCompletionBlockWithSuccess:success failure:failure];
|
||||
operation.managedObjectContext = managedObjectContext ?: self.managedObjectStore.mainQueueManagedObjectContext;
|
||||
operation.managedObjectCache = self.managedObjectStore.managedObjectCache;
|
||||
|
||||
@@ -168,6 +168,17 @@
|
||||
*/
|
||||
- (void)setWillMapDeserializedResponseBlock:(id (^)(id deserializedResponseBody))block;
|
||||
|
||||
///-----------------------------------------------------
|
||||
/// @name Determining Whether a Request Can Be Processed
|
||||
///-----------------------------------------------------
|
||||
|
||||
/**
|
||||
Returns a Boolean value determining whether or not the class can process the specified request.
|
||||
|
||||
@param request The request that is determined to be supported or not supported for this class.
|
||||
*/
|
||||
+ (BOOL)canProcessRequest:(NSURLRequest *)request;
|
||||
|
||||
///-------------------------------------------
|
||||
/// @name Accessing the Response Mapping Queue
|
||||
///-------------------------------------------
|
||||
|
||||
@@ -117,6 +117,11 @@ static NSString *RKStringDescribingURLResponseWithData(NSURLResponse *response,
|
||||
return responseMappingQueue;
|
||||
}
|
||||
|
||||
+ (BOOL)canProcessRequest:(NSURLRequest *)request
|
||||
{
|
||||
return YES;
|
||||
}
|
||||
|
||||
- (void)dealloc
|
||||
{
|
||||
#if !OS_OBJECT_USE_OBJC
|
||||
|
||||
@@ -56,6 +56,30 @@
|
||||
@implementation RKTestHTTPRequestOperation : RKHTTPRequestOperation
|
||||
@end
|
||||
|
||||
@interface RKTestObjectRequestOperation : RKObjectRequestOperation
|
||||
@end
|
||||
|
||||
@implementation RKTestObjectRequestOperation
|
||||
|
||||
+ (BOOL)canProcessRequest:(NSURLRequest *)request
|
||||
{
|
||||
return [[request.URL relativePath] isEqualToString:@"/match"];
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
@interface RKTestManagedObjectRequestOperation : RKManagedObjectRequestOperation
|
||||
@end
|
||||
|
||||
@implementation RKTestManagedObjectRequestOperation
|
||||
|
||||
+ (BOOL)canProcessRequest:(NSURLRequest *)request
|
||||
{
|
||||
return [[request.URL relativePath] isEqualToString:@"/match"];
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
@interface RKObjectManagerTest : RKTestCase
|
||||
|
||||
@property (nonatomic, strong) RKObjectManager *objectManager;
|
||||
@@ -405,7 +429,7 @@
|
||||
- (void)testRegistrationOfHTTPRequestOperationClass
|
||||
{
|
||||
RKObjectManager *manager = [RKObjectManager managerWithBaseURL:[NSURL URLWithString:@"http://restkit.org"]];
|
||||
[manager setHTTPOperationClass:[RKTestHTTPRequestOperation class]];
|
||||
[manager setHTTPRequestOperationClass:[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]);
|
||||
@@ -414,8 +438,8 @@
|
||||
- (void)testSettingNilHTTPRequestOperationClassRestoresDefaultHTTPOperationClass
|
||||
{
|
||||
RKObjectManager *manager = [RKObjectManager managerWithBaseURL:[NSURL URLWithString:@"http://restkit.org"]];
|
||||
[manager setHTTPOperationClass:[RKTestHTTPRequestOperation class]];
|
||||
[manager setHTTPOperationClass:nil];
|
||||
[manager setHTTPRequestOperationClass:[RKTestHTTPRequestOperation class]];
|
||||
[manager setHTTPRequestOperationClass: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]);
|
||||
@@ -854,4 +878,50 @@
|
||||
expect(caughtException).notTo.beNil();
|
||||
}
|
||||
|
||||
#pragma mark - Object Request Operation Registration
|
||||
|
||||
- (void)testRegistrationOfObjectRequestOperationClass
|
||||
{
|
||||
RKObjectManager *manager = [RKObjectManager managerWithBaseURL:[NSURL URLWithString:@"http://restkit.org"]];
|
||||
[manager registerObjectRequestOperationClass:[RKTestObjectRequestOperation class]];
|
||||
NSURL *URL = [NSURL URLWithString:@"/match" relativeToURL:manager.baseURL];
|
||||
NSURLRequest *request = [NSURLRequest requestWithURL:URL];
|
||||
RKObjectRequestOperation *operation = [manager objectRequestOperationWithRequest:request success:nil failure:nil];
|
||||
expect(operation).to.beInstanceOf([RKTestObjectRequestOperation class]);
|
||||
}
|
||||
|
||||
- (void)testRegistrationOfObjectRequestOperationClassRespectsSubclassDecisionToProcessRequest
|
||||
{
|
||||
RKObjectManager *manager = [RKObjectManager managerWithBaseURL:[NSURL URLWithString:@"http://restkit.org"]];
|
||||
[manager registerObjectRequestOperationClass:[RKTestObjectRequestOperation class]];
|
||||
NSURL *URL = [NSURL URLWithString:@"/mismatch" relativeToURL:manager.baseURL];
|
||||
NSURLRequest *request = [NSURLRequest requestWithURL:URL];
|
||||
RKObjectRequestOperation *operation = [manager objectRequestOperationWithRequest:request success:nil failure:nil];
|
||||
expect(operation).notTo.beInstanceOf([RKTestObjectRequestOperation class]);
|
||||
expect(operation).to.beInstanceOf([RKObjectRequestOperation class]);
|
||||
}
|
||||
|
||||
- (void)testRegistrationOfManagedObjectRequestOperationClass
|
||||
{
|
||||
RKManagedObjectStore *managedObjectStore = [RKTestFactory managedObjectStore];
|
||||
RKObjectManager *manager = [RKObjectManager managerWithBaseURL:[NSURL URLWithString:@"http://restkit.org"]];
|
||||
[manager registerObjectRequestOperationClass:[RKTestManagedObjectRequestOperation class]];
|
||||
NSURL *URL = [NSURL URLWithString:@"/match" relativeToURL:manager.baseURL];
|
||||
NSURLRequest *request = [NSURLRequest requestWithURL:URL];
|
||||
RKObjectRequestOperation *operation = [manager managedObjectRequestOperationWithRequest:request managedObjectContext:managedObjectStore.mainQueueManagedObjectContext success:nil failure:nil];
|
||||
expect(operation).to.beInstanceOf([RKTestManagedObjectRequestOperation class]);
|
||||
}
|
||||
|
||||
- (void)testRegistrationOfManagedObjectRequestOperationClassRespectsSubclassDecisionToProcessRequest
|
||||
{
|
||||
RKManagedObjectStore *managedObjectStore = [RKTestFactory managedObjectStore];
|
||||
RKObjectManager *manager = [RKObjectManager managerWithBaseURL:[NSURL URLWithString:@"http://restkit.org"]];
|
||||
[manager registerObjectRequestOperationClass:[RKTestManagedObjectRequestOperation class]];
|
||||
NSURL *URL = [NSURL URLWithString:@"/mismatch" relativeToURL:manager.baseURL];
|
||||
NSURLRequest *request = [NSURLRequest requestWithURL:URL];
|
||||
RKObjectRequestOperation *operation = [manager managedObjectRequestOperationWithRequest:request managedObjectContext:managedObjectStore.mainQueueManagedObjectContext success:nil failure:nil];
|
||||
expect(operation).notTo.beInstanceOf([RKTestManagedObjectRequestOperation class]);
|
||||
expect(operation).to.beInstanceOf([RKManagedObjectRequestOperation class]);
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
Reference in New Issue
Block a user