mirror of
https://github.com/zhigang1992/RestKit.git
synced 2026-04-13 22:45:23 +08:00
Refactored object loaders to provide easier support for non-nested JSON responses. There are new flavors of getObject:, postObject:, etc.
that allow the developer to explicitly specify the object mapping to use for processing the response. closes #168
This commit is contained in:
@@ -77,12 +77,26 @@
|
||||
*/
|
||||
@interface RKObjectLoader : RKRequest {
|
||||
RKObjectManager* _objectManager;
|
||||
RKResponse* _response;
|
||||
RKResponse* _response;
|
||||
RKObjectMapping* _objectMapping;
|
||||
RKObjectMappingResult* _result;
|
||||
RKObjectMappingResult* _result;
|
||||
RKObjectMapping* _serializationMapping;
|
||||
NSString* _serializationMIMEType;
|
||||
NSObject* _targetObject;
|
||||
}
|
||||
|
||||
/**
|
||||
* The object mapping to use when processing the response. If this is nil,
|
||||
* then RestKit will search the parsed response body for mappable keyPaths and
|
||||
* perform mapping on all available content. For instances where your target JSON
|
||||
* is not returned under a uniquely identifiable keyPath, you must specify the object
|
||||
* mapping directly for RestKit to know how to map it.
|
||||
*
|
||||
* @default nil
|
||||
* @see RKObjectMappingProvider
|
||||
*/
|
||||
@property (nonatomic, retain) RKObjectMapping* objectMapping;
|
||||
|
||||
/**
|
||||
* The object manager that initialized this loader. The object manager is responsible
|
||||
* for supplying the mapper and object store used after HTTP transport is completed
|
||||
@@ -95,9 +109,31 @@
|
||||
@property (nonatomic, readonly) RKResponse* response;
|
||||
|
||||
/**
|
||||
* The object mapping to apply to the response
|
||||
* The mapping result that was produced after the request finished loading and
|
||||
* object mapping has completed. Provides access to the final products of the
|
||||
* object mapper in a variety of formats.
|
||||
*/
|
||||
@property (nonatomic, retain) RKObjectMapping* objectMapping;
|
||||
@property (nonatomic, readonly) RKObjectMappingResult* result;
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////////////
|
||||
// Serialization
|
||||
|
||||
/**
|
||||
* The object mapping to use when serializing a target object for transport
|
||||
* to the remote server.
|
||||
*
|
||||
* @see RKObjectMappingProvider
|
||||
*/
|
||||
@property (nonatomic, retain) RKObjectMapping* serializationMapping;
|
||||
|
||||
/**
|
||||
* The MIME Type to serialize the targetObject into according to the mapping
|
||||
* rules in the serializationMapping. Typical MIME Types for serialization are
|
||||
* JSON (RKMIMETypeJSON) and URL Form Encoded (RKMIMETypeFormURLEncoded).
|
||||
*
|
||||
* @see RKMIMEType
|
||||
*/
|
||||
@property (nonatomic, retain) NSString* serializationMIMEType;
|
||||
|
||||
/**
|
||||
* The mappable object that generated this loader. This is used to map object
|
||||
@@ -105,10 +141,7 @@
|
||||
*/
|
||||
@property (nonatomic, retain) NSObject* targetObject;
|
||||
|
||||
/**
|
||||
* If the request was sent synchronously, this is how you get at the object mapping result.
|
||||
*/
|
||||
@property (nonatomic, retain) RKObjectMappingResult* result;
|
||||
///////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
/**
|
||||
* Initialize and return an object loader for a resource path against an object manager. The resource path
|
||||
@@ -118,9 +151,10 @@
|
||||
+ (id)loaderWithResourcePath:(NSString*)resourcePath objectManager:(RKObjectManager*)objectManager delegate:(id<RKObjectLoaderDelegate>)delegate;
|
||||
|
||||
/**
|
||||
* Initialize a new object loader with an object mapper, a request, and a delegate
|
||||
* Initialize a new object loader with an object manager, a request, and a delegate
|
||||
*/
|
||||
- (id)initWithResourcePath:(NSString*)resourcePath objectManager:(RKObjectManager*)objectManager delegate:(id<RKObjectLoaderDelegate>)delegate;
|
||||
|
||||
/**
|
||||
* Handle an error in the response preventing it from being mapped, called from -isResponseMappable
|
||||
*/
|
||||
|
||||
@@ -16,6 +16,7 @@
|
||||
#import "RKObjectLoader_Internals.h"
|
||||
#import "RKParserRegistry.h"
|
||||
#import "../Network/RKRequest_Internals.h"
|
||||
#import "RKObjectSerializer.h"
|
||||
|
||||
// Set Logging Component
|
||||
#undef RKLogComponent
|
||||
@@ -26,6 +27,8 @@
|
||||
@synthesize objectManager = _objectManager, response = _response;
|
||||
@synthesize targetObject = _targetObject, objectMapping = _objectMapping;
|
||||
@synthesize result = _result;
|
||||
@synthesize serializationMapping = _serializationMapping;
|
||||
@synthesize serializationMIMEType = _serializationMIMEType;
|
||||
|
||||
+ (id)loaderWithResourcePath:(NSString*)resourcePath objectManager:(RKObjectManager*)objectManager delegate:(id<RKObjectLoaderDelegate>)delegate {
|
||||
return [[[self alloc] initWithResourcePath:resourcePath objectManager:objectManager delegate:delegate] autorelease];
|
||||
@@ -52,6 +55,8 @@
|
||||
_objectMapping = nil;
|
||||
[_result release];
|
||||
_result = nil;
|
||||
[_serializationMIMEType release];
|
||||
[_serializationMapping release];
|
||||
|
||||
[super dealloc];
|
||||
}
|
||||
@@ -64,6 +69,8 @@
|
||||
|
||||
#pragma mark - Response Processing
|
||||
|
||||
// NOTE: This method is significant because the notifications posted are used by
|
||||
// RKRequestQueue to remove requests from the queue. All requests need to be finalized.
|
||||
- (void)finalizeLoad:(BOOL)successful error:(NSError*)error {
|
||||
_isLoading = NO;
|
||||
|
||||
@@ -167,9 +174,11 @@
|
||||
- (RKObjectMappingResult*)performMapping:(NSError**)error {
|
||||
RKObjectMappingProvider* mappingProvider;
|
||||
if (self.objectMapping) {
|
||||
RKLogDebug(@"Found directly configured object mapping, creating temporary mapping provider...");
|
||||
mappingProvider = [[RKObjectMappingProvider new] autorelease];
|
||||
[mappingProvider setObjectMapping:self.objectMapping forKeyPath:@""];
|
||||
} else {
|
||||
RKLogDebug(@"No object mapping provider, using mapping provider from parent object manager to perform KVC mapping");
|
||||
mappingProvider = self.objectManager.mappingProvider;
|
||||
}
|
||||
|
||||
@@ -181,7 +190,7 @@
|
||||
NSAutoreleasePool* pool = [[NSAutoreleasePool alloc] init];
|
||||
|
||||
NSError* error = nil;
|
||||
self.result = [self performMapping:&error];
|
||||
_result = [[self performMapping:&error] retain];
|
||||
if (self.result) {
|
||||
[self processMappingResult:self.result];
|
||||
} else {
|
||||
@@ -221,6 +230,8 @@
|
||||
[(NSObject<RKObjectLoaderDelegate>*)_delegate objectLoader:self didFailWithError:error];
|
||||
}
|
||||
|
||||
// NOTE: We skip didFailLoadWithError: here so that we don't send the delegate
|
||||
// conflicting messages around unexpected response and failure with error
|
||||
[self finalizeLoad:NO error:error];
|
||||
|
||||
return NO;
|
||||
@@ -250,7 +261,23 @@
|
||||
#pragma mark - RKRequest & RKRequestDelegate methods
|
||||
|
||||
// Invoked just before request hits the network
|
||||
- (void)prepareURLRequest {
|
||||
- (BOOL)prepareURLRequest {
|
||||
if (self.targetObject && (self.method == RKRequestMethodPOST || self.method == RKRequestMethodPUT)) {
|
||||
NSAssert(self.serializationMapping, @"Cannot send an object to the remote");
|
||||
RKLogDebug(@"POST or PUT request for target object %@, serializing to MIME Type %@ for transport...", self.targetObject, self.serializationMIMEType);
|
||||
RKObjectSerializer* serializer = [RKObjectSerializer serializerWithObject:self.targetObject mapping:self.serializationMapping];
|
||||
NSError* error = nil;
|
||||
id params = [serializer serializationForMIMEType:self.serializationMIMEType error:&error];
|
||||
|
||||
if (error) {
|
||||
RKLogError(@"Serializing failed for target object %@ to MIME Type %@: %@", self.targetObject, self.serializationMIMEType, [error localizedDescription]);
|
||||
[self didFailLoadWithError:error];
|
||||
return NO;
|
||||
}
|
||||
|
||||
self.params = params;
|
||||
}
|
||||
|
||||
// TODO: This is an informal protocol ATM. Maybe its not obvious enough?
|
||||
if (self.targetObject) {
|
||||
if ([self.targetObject respondsToSelector:@selector(willSendWithObjectLoader:)]) {
|
||||
@@ -258,7 +285,7 @@
|
||||
}
|
||||
}
|
||||
|
||||
[super prepareURLRequest];
|
||||
return [super prepareURLRequest];
|
||||
}
|
||||
|
||||
- (void)didFailLoadWithError:(NSError*)error {
|
||||
@@ -303,7 +330,7 @@
|
||||
// Determine if we are synchronous here or not.
|
||||
if (_sentSynchronously) {
|
||||
NSError* error = nil;
|
||||
self.result = [self performMapping:&error];
|
||||
_result = [[self performMapping:&error] retain];
|
||||
if (self.result) {
|
||||
[self processMappingResult:self.result];
|
||||
} else {
|
||||
|
||||
@@ -183,28 +183,16 @@ typedef enum {
|
||||
*/
|
||||
- (RKObjectLoader*)loadObjectsAtResourcePath:(NSString*)resourcePath delegate:(id<RKObjectLoaderDelegate>)delegate;
|
||||
|
||||
/**
|
||||
Create and send an asynchronous GET request to load the objects at the specified resource path with a dictionary
|
||||
of query parameters to append to the URL and call back the delegate with the loaded objects. Remote objects will be mapped
|
||||
to local objects by consulting the keyPath registrations set on the mapping provider.
|
||||
|
||||
These methods have been deprecated. You can use [resourcePath appendQueryParams:queryParams] to achieve the same effect.
|
||||
|
||||
@deprecated
|
||||
*/
|
||||
- (RKObjectLoader*)loadObjectsAtResourcePath:(NSString *)resourcePath queryParams:(NSDictionary*)queryParams delegate:(id<RKObjectLoaderDelegate>)delegate DEPRECATED_ATTRIBUTE;
|
||||
- (RKObjectLoader*)loadObjectsAtResourcePath:(NSString *)resourcePath queryParams:(NSDictionary*)queryParams objectMapping:(RKObjectMapping*)objectMapping delegate:(id<RKObjectLoaderDelegate>)delegate DEPRECATED_ATTRIBUTE;
|
||||
|
||||
/**
|
||||
Load mappable objects at the specified resourcePath using the specified object mapping.
|
||||
*/
|
||||
- (RKObjectLoader*)loadObjectsAtResourcePath:(NSString*)resourcePath objectMapping:(RKObjectMapping*)objectMapping delegate:(id<RKObjectLoaderDelegate>)delegate;
|
||||
|
||||
////////////////////////////////////////////////////////
|
||||
/// @name Mappable object helpers
|
||||
/// @name Mappable Object Loaders
|
||||
|
||||
/**
|
||||
Update a mappable model by loading its attributes from the web
|
||||
Fetch the data for a mappable object by performing an HTTP GET.
|
||||
*/
|
||||
- (RKObjectLoader*)getObject:(id<NSObject>)object delegate:(id<RKObjectLoaderDelegate>)delegate;
|
||||
|
||||
@@ -223,8 +211,31 @@ typedef enum {
|
||||
*/
|
||||
- (RKObjectLoader*)deleteObject:(id<NSObject>)object delegate:(id<RKObjectLoaderDelegate>)delegate;
|
||||
|
||||
////////////////////////////////////////////////////////
|
||||
/// @name Object Loader Primitives
|
||||
//////
|
||||
|
||||
/**
|
||||
Fetch the data for a mappable object by performing an HTTP GET. The data returned in the response will be mapped according
|
||||
to the object mapping provided.
|
||||
*/
|
||||
- (RKObjectLoader*)getObject:(id<NSObject>)object mapResponseWith:(RKObjectMapping*)objectMapping delegate:(id<RKObjectLoaderDelegate>)delegate;
|
||||
|
||||
/**
|
||||
Send the data for a mappable object by performing an HTTP POST. The data returned in the response will be mapped according
|
||||
to the object mapping provided.
|
||||
*/
|
||||
- (RKObjectLoader*)postObject:(id<NSObject>)object mapResponseWith:(RKObjectMapping*)objectMapping delegate:(id<RKObjectLoaderDelegate>)delegate;
|
||||
|
||||
/**
|
||||
Send the data for a mappable object by performing an HTTP PUT. The data returned in the response will be mapped according
|
||||
to the object mapping provided.
|
||||
*/
|
||||
- (RKObjectLoader*)putObject:(id<NSObject>)object mapResponseWith:(RKObjectMapping*)objectMapping delegate:(id<RKObjectLoaderDelegate>)delegate;
|
||||
|
||||
/**
|
||||
Delete a remote object representation by performing an HTTP DELETE. The data returned in the response will be mapped according
|
||||
to the object mapping provided.
|
||||
*/
|
||||
- (RKObjectLoader*)deleteObject:(id<NSObject>)object mapResponseWith:(RKObjectMapping*)objectMapping delegate:(id<RKObjectLoaderDelegate>)delegate;
|
||||
|
||||
/**
|
||||
These methods are provided for situations where the remote system you are working with has slightly different conventions
|
||||
|
||||
@@ -10,7 +10,6 @@
|
||||
#import "RKObjectSerializer.h"
|
||||
#import "../CoreData/RKManagedObjectStore.h"
|
||||
#import "../CoreData/RKManagedObjectLoader.h"
|
||||
//#import "../Support/RKMIMETypes.h"
|
||||
#import "../Support/Support.h"
|
||||
#import "RKErrorMessage.h"
|
||||
|
||||
@@ -142,16 +141,6 @@ static RKObjectManager* sharedManager = nil;
|
||||
return loader;
|
||||
}
|
||||
|
||||
- (RKObjectLoader*)loadObjectsAtResourcePath:(NSString *)resourcePath queryParams:(NSDictionary*)queryParams delegate:(id<RKObjectLoaderDelegate>)delegate {
|
||||
NSString* resourcePathWithQuery = RKPathAppendQueryParams(resourcePath, queryParams);
|
||||
RKObjectLoader* loader = [self objectLoaderWithResourcePath:resourcePathWithQuery delegate:delegate];
|
||||
loader.method = RKRequestMethodGET;
|
||||
|
||||
[loader send];
|
||||
|
||||
return loader;
|
||||
}
|
||||
|
||||
- (RKObjectLoader*)loadObjectsAtResourcePath:(NSString*)resourcePath objectMapping:(RKObjectMapping*)objectMapping delegate:(id<RKObjectLoaderDelegate>)delegate {
|
||||
RKObjectLoader* loader = [self objectLoaderWithResourcePath:resourcePath delegate:delegate];
|
||||
loader.method = RKRequestMethodGET;
|
||||
@@ -162,17 +151,6 @@ static RKObjectManager* sharedManager = nil;
|
||||
return loader;
|
||||
}
|
||||
|
||||
- (RKObjectLoader*)loadObjectsAtResourcePath:(NSString *)resourcePath queryParams:(NSDictionary*)queryParams objectMapping:(RKObjectMapping*)objectMapping delegate:(id<RKObjectLoaderDelegate>)delegate {
|
||||
NSString* resourcePathWithQuery = RKPathAppendQueryParams(resourcePath, queryParams);
|
||||
RKObjectLoader* loader = [self objectLoaderWithResourcePath:resourcePathWithQuery delegate:delegate];
|
||||
loader.method = RKRequestMethodGET;
|
||||
loader.objectMapping = objectMapping;
|
||||
|
||||
[loader send];
|
||||
|
||||
return loader;
|
||||
}
|
||||
|
||||
/////////////////////////////////////////////////////////////
|
||||
#pragma mark - Object Instance Loaders
|
||||
|
||||
@@ -181,20 +159,8 @@ static RKObjectManager* sharedManager = nil;
|
||||
RKObjectLoader* loader = [self objectLoaderWithResourcePath:resourcePath delegate:delegate];
|
||||
loader.method = method;
|
||||
loader.targetObject = object;
|
||||
|
||||
if (method == RKRequestMethodPOST || method == RKRequestMethodPUT) {
|
||||
RKObjectMapping* serializationMapping = [self.mappingProvider serializationMappingForClass:[object class]];
|
||||
RKObjectSerializer* serializer = [RKObjectSerializer serializerWithObject:object mapping:serializationMapping];
|
||||
NSError* error = nil;
|
||||
id params = [serializer serializationForMIMEType:self.serializationMIMEType error:&error];
|
||||
|
||||
if (error) {
|
||||
[delegate objectLoader:loader didFailWithError:error];
|
||||
return nil;
|
||||
}
|
||||
|
||||
loader.params = params;
|
||||
}
|
||||
loader.serializationMIMEType = self.serializationMIMEType;
|
||||
loader.serializationMapping = [self.mappingProvider serializationMappingForClass:[object class]];
|
||||
|
||||
return loader;
|
||||
}
|
||||
@@ -223,4 +189,35 @@ static RKObjectManager* sharedManager = nil;
|
||||
return loader;
|
||||
}
|
||||
|
||||
#pragma mark - Object Instance Loaders for Non-nested JSON
|
||||
|
||||
- (RKObjectLoader*)getObject:(id<NSObject>)object mapResponseWith:(RKObjectMapping*)objectMapping delegate:(id<RKObjectLoaderDelegate>)delegate {
|
||||
RKObjectLoader* loader = [self objectLoaderForObject:object method:RKRequestMethodGET delegate:delegate];
|
||||
loader.objectMapping = objectMapping;
|
||||
[loader send];
|
||||
return loader;
|
||||
}
|
||||
|
||||
- (RKObjectLoader*)postObject:(id<NSObject>)object mapResponseWith:(RKObjectMapping*)objectMapping delegate:(id<RKObjectLoaderDelegate>)delegate {
|
||||
RKObjectLoader* loader = [self objectLoaderForObject:object method:RKRequestMethodPOST delegate:delegate];
|
||||
loader.objectMapping = objectMapping;
|
||||
[loader send];
|
||||
return loader;
|
||||
}
|
||||
|
||||
- (RKObjectLoader*)putObject:(id<NSObject>)object mapResponseWith:(RKObjectMapping*)objectMapping delegate:(id<RKObjectLoaderDelegate>)delegate {
|
||||
RKObjectLoader* loader = [self objectLoaderForObject:object method:RKRequestMethodPUT delegate:delegate];
|
||||
loader.objectMapping = objectMapping;
|
||||
[loader send];
|
||||
return loader;
|
||||
}
|
||||
|
||||
- (RKObjectLoader*)deleteObject:(id<NSObject>)object mapResponseWith:(RKObjectMapping*)objectMapping delegate:(id<RKObjectLoaderDelegate>)delegate {
|
||||
RKObjectLoader* loader = [self objectLoaderForObject:object method:RKRequestMethodDELETE delegate:delegate];
|
||||
loader.objectMapping = objectMapping;
|
||||
[loader send];
|
||||
return loader;
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
Reference in New Issue
Block a user