mirror of
https://github.com/zhigang1992/RestKit.git
synced 2026-04-23 12:27:52 +08:00
Added support for polymorphic object mapping (Github #105, #244). This enables you to dynamically map objects to different destination classes or using different mapping strategies via configuration or callbacks. See Docs/Object Mapping.md for details.
Other changes include: * Eliminated the RKObjectFactory protocol and implementations. Object mapping instances themselves are now responsible for instantiating target objects for mapping. * Introduced RKObjectAbstractMapping superclass for RKObjectMapping and RKObjectPolymorphicMapping. * Updated example applications to use block object loaders (RKTwitter and RKTwitterCoreData) * Refactored method signatures of RKObjectMapper, RKObjectMapping, and RKObjectMappingProvider to reflect the existence of abstract mapping types. This was necessary to make polymorphic mappings integrate cleanly. * Fixed overlap in RestKit error domains between network and object mapping. fixes #208
This commit is contained in:
@@ -13,5 +13,4 @@
|
||||
#import "RKObjectMappingProvider.h"
|
||||
#import "RKObjectMappingResult.h"
|
||||
#import "RKObjectMapper.h"
|
||||
#import "RKObjectFactory.h"
|
||||
#import "RKParserRegistry.h"
|
||||
|
||||
19
Code/ObjectMapping/RKObjectAbstractMapping.h
Normal file
19
Code/ObjectMapping/RKObjectAbstractMapping.h
Normal file
@@ -0,0 +1,19 @@
|
||||
//
|
||||
// RKObjectAbstractMapping.h
|
||||
// RestKit
|
||||
//
|
||||
// Created by Blake Watters on 7/29/11.
|
||||
// Copyright 2011 RestKit. All rights reserved.
|
||||
//
|
||||
|
||||
#import <Foundation/Foundation.h>
|
||||
|
||||
/**
|
||||
An abstract superclass for RKObjectMapping and RKObjectPolymorphic mapping.
|
||||
Provides type safety checks
|
||||
*/
|
||||
@interface RKObjectAbstractMapping : NSObject
|
||||
|
||||
- (BOOL)forceCollectionMapping;
|
||||
- (Class)objectClass;
|
||||
@end
|
||||
25
Code/ObjectMapping/RKObjectAbstractMapping.m
Normal file
25
Code/ObjectMapping/RKObjectAbstractMapping.m
Normal file
@@ -0,0 +1,25 @@
|
||||
//
|
||||
// RKObjectAbstractMapping.m
|
||||
// RestKit
|
||||
//
|
||||
// Created by Blake Watters on 7/29/11.
|
||||
// Copyright 2011 RestKit. All rights reserved.
|
||||
//
|
||||
|
||||
#import "RKObjectAbstractMapping.h"
|
||||
|
||||
@implementation RKObjectAbstractMapping
|
||||
|
||||
- (BOOL)forceCollectionMapping {
|
||||
@throw [NSException exceptionWithName:NSInternalInconsistencyException
|
||||
reason:[NSString stringWithFormat:@"You must override %@ in a subclass", NSStringFromSelector(_cmd)]
|
||||
userInfo:nil];
|
||||
}
|
||||
|
||||
- (Class)objectClass {
|
||||
@throw [NSException exceptionWithName:NSInternalInconsistencyException
|
||||
reason:[NSString stringWithFormat:@"You must override %@ in a subclass", NSStringFromSelector(_cmd)]
|
||||
userInfo:nil];
|
||||
}
|
||||
|
||||
@end
|
||||
@@ -1,23 +0,0 @@
|
||||
//
|
||||
// RKObjectFactory.h
|
||||
// RestKit
|
||||
//
|
||||
// Created by Blake Watters on 5/10/11.
|
||||
// Copyright 2011 Two Toasters. All rights reserved.
|
||||
//
|
||||
|
||||
#import "RKObjectMapping.h"
|
||||
|
||||
/**
|
||||
Defines a protocol for the creation of objects during an
|
||||
object mapping operation. Used to initialize objects that
|
||||
are going to be subsequently mapped with an object mapping
|
||||
*/
|
||||
@protocol RKObjectFactory <NSObject>
|
||||
|
||||
/**
|
||||
Return a new initialized, auto-released object with the specified object mapping.
|
||||
*/
|
||||
- (id)objectWithMapping:(RKObjectMapping*)objectMapping andData:(id)mappableData;
|
||||
|
||||
@end
|
||||
@@ -127,16 +127,6 @@
|
||||
|
||||
#pragma mark - Subclass Hooks
|
||||
|
||||
/**
|
||||
Overloaded by RKManagedObjectLoader to provide support for creation
|
||||
and find/update of managed object instances
|
||||
|
||||
@protected
|
||||
*/
|
||||
- (id<RKObjectFactory>)createObjectFactory {
|
||||
return nil;
|
||||
}
|
||||
|
||||
/**
|
||||
Overloaded by RKManagedObjectLoader to serialize/deserialize managed objects
|
||||
at thread boundaries.
|
||||
@@ -179,7 +169,6 @@
|
||||
}
|
||||
|
||||
RKObjectMapper* mapper = [RKObjectMapper mapperWithObject:parsedData mappingProvider:mappingProvider];
|
||||
mapper.objectFactory = [self createObjectFactory];
|
||||
mapper.targetObject = targetObject;
|
||||
mapper.delegate = self;
|
||||
RKObjectMappingResult* result = [mapper performMapping];
|
||||
@@ -208,7 +197,7 @@
|
||||
NSString* rootKeyPath = self.objectMapping.rootKeyPath ? self.objectMapping.rootKeyPath : @"";
|
||||
RKLogDebug(@"Found directly configured object mapping, creating temporary mapping provider %@", (rootKeyPath ? @"for keyPath '%@'" : nil));
|
||||
mappingProvider = [[RKObjectMappingProvider new] autorelease];
|
||||
[mappingProvider setObjectMapping:self.objectMapping forKeyPath:rootKeyPath];
|
||||
[mappingProvider setMapping:self.objectMapping forKeyPath:rootKeyPath];
|
||||
} else {
|
||||
RKLogDebug(@"No object mapping provider, using mapping provider from parent object manager to perform KVC mapping");
|
||||
mappingProvider = self.objectManager.mappingProvider;
|
||||
|
||||
@@ -281,6 +281,7 @@ typedef enum {
|
||||
POST a remote object instance and yield the object loader to the block before sending
|
||||
|
||||
@see sendObject:method:delegate:block
|
||||
- (RKObjectLoader*)postObject:(id<NSObject>)object delegate:(id<RKObjectLoaderDelegate>)delegate block:(void(^)(RKObjectLoader*))block;
|
||||
*/
|
||||
- (RKObjectLoader*)postObject:(id<NSObject>)object delegate:(id<RKObjectLoaderDelegate>)delegate block:(void(^)(RKObjectLoader*))block;
|
||||
|
||||
|
||||
@@ -47,8 +47,8 @@ static RKObjectManager* sharedManager = nil;
|
||||
// Setup default error message mappings
|
||||
RKObjectMapping* errorMapping = [RKObjectMapping mappingForClass:[RKErrorMessage class]];
|
||||
[errorMapping mapKeyPath:@"" toAttribute:@"errorMessage"];
|
||||
[_mappingProvider setObjectMapping:errorMapping forKeyPath:@"error"];
|
||||
[_mappingProvider setObjectMapping:errorMapping forKeyPath:@"errors"];
|
||||
[_mappingProvider setMapping:errorMapping forKeyPath:@"error"];
|
||||
[_mappingProvider setMapping:errorMapping forKeyPath:@"errors"];
|
||||
|
||||
[[NSNotificationCenter defaultCenter] addObserver:self
|
||||
selector:@selector(reachabilityChanged:)
|
||||
|
||||
@@ -11,7 +11,6 @@
|
||||
#import "RKObjectMappingOperation.h"
|
||||
#import "RKObjectMappingResult.h"
|
||||
#import "RKObjectMappingProvider.h"
|
||||
#import "RKObjectFactory.h"
|
||||
#import "../Support/Support.h"
|
||||
|
||||
/**
|
||||
@@ -27,12 +26,12 @@
|
||||
- (void)objectMapperWillBeginMapping:(RKObjectMapper*)objectMapper;
|
||||
- (void)objectMapperDidFinishMapping:(RKObjectMapper*)objectMapper;
|
||||
- (void)objectMapper:(RKObjectMapper*)objectMapper didAddError:(NSError*)error;
|
||||
- (void)objectMapper:(RKObjectMapper*)objectMapper didFindMappableObject:(id)object atKeyPath:(NSString*)keyPath withMapping:(RKObjectMapping*)mapping;
|
||||
- (void)objectMapper:(RKObjectMapper*)objectMapper didFindMappableObject:(id)object atKeyPath:(NSString*)keyPath withMapping:(RKObjectAbstractMapping*)mapping;
|
||||
- (void)objectMapper:(RKObjectMapper*)objectMapper didNotFindMappableObjectAtKeyPath:(NSString*)keyPath;
|
||||
|
||||
- (void)objectMapper:(RKObjectMapper*)objectMapper willMapFromObject:(id)sourceObject toObject:(id)destinationObject atKeyPath:(NSString*)keyPath usingMapping:(RKObjectMapping*)objectMapping;
|
||||
- (void)objectMapper:(RKObjectMapper*)objectMapper didMapFromObject:(id)sourceObject toObject:(id)destinationObject atKeyPath:(NSString*)keyPath usingMapping:(RKObjectMapping*)objectMapping;
|
||||
- (void)objectMapper:(RKObjectMapper*)objectMapper didFailMappingFromObject:(id)sourceObject toObject:(id)destinationObject withError:(NSError*)error atKeyPath:(NSString*)keyPath usingMapping:(RKObjectMapping*)objectMapping;
|
||||
- (void)objectMapper:(RKObjectMapper*)objectMapper willMapFromObject:(id)sourceObject toObject:(id)destinationObject atKeyPath:(NSString*)keyPath usingMapping:(RKObjectAbstractMapping*)objectMapping;
|
||||
- (void)objectMapper:(RKObjectMapper*)objectMapper didMapFromObject:(id)sourceObject toObject:(id)destinationObject atKeyPath:(NSString*)keyPath usingMapping:(RKObjectAbstractMapping*)objectMapping;
|
||||
- (void)objectMapper:(RKObjectMapper*)objectMapper didFailMappingFromObject:(id)sourceObject toObject:(id)destinationObject withError:(NSError*)error atKeyPath:(NSString*)keyPath usingMapping:(RKObjectAbstractMapping*)objectMapping;
|
||||
@end
|
||||
|
||||
@interface RKObjectMapper : NSObject {
|
||||
@@ -40,7 +39,6 @@
|
||||
id _targetObject;
|
||||
RKObjectMappingProvider* _mappingProvider;
|
||||
id<RKObjectMapperDelegate> _delegate;
|
||||
id<RKObjectFactory> _objectFactory;
|
||||
NSMutableArray* _errors;
|
||||
}
|
||||
|
||||
@@ -48,7 +46,6 @@
|
||||
@property (nonatomic, assign) id targetObject;
|
||||
@property (nonatomic, readonly) RKObjectMappingProvider* mappingProvider;
|
||||
@property (nonatomic, assign) id<RKObjectMapperDelegate> delegate;
|
||||
@property (nonatomic, assign) id<RKObjectFactory> objectFactory;
|
||||
@property (nonatomic, readonly) NSArray* errors;
|
||||
|
||||
+ (id)mapperWithObject:(id)object mappingProvider:(RKObjectMappingProvider*)mappingProvider;
|
||||
|
||||
@@ -20,7 +20,6 @@
|
||||
@synthesize targetObject = _targetObject;
|
||||
@synthesize delegate =_delegate;
|
||||
@synthesize mappingProvider = _mappingProvider;
|
||||
@synthesize objectFactory = _objectFactory;
|
||||
@synthesize errors = _errors;
|
||||
|
||||
+ (id)mapperWithObject:(id)object mappingProvider:(RKObjectMappingProvider*)mappingProvider {
|
||||
@@ -98,7 +97,7 @@
|
||||
|
||||
#pragma mark - Mapping Primitives
|
||||
|
||||
- (id)mapObject:(id)mappableObject atKeyPath:(NSString*)keyPath usingMapping:(RKObjectMapping*)objectMapping {
|
||||
- (id)mapObject:(id)mappableObject atKeyPath:(NSString*)keyPath usingMapping:(RKObjectAbstractMapping*)objectMapping {
|
||||
NSAssert([mappableObject respondsToSelector:@selector(setValue:forKeyPath:)], @"Expected self.object to be KVC compliant");
|
||||
id destinationObject = nil;
|
||||
|
||||
@@ -130,7 +129,7 @@
|
||||
return nil;
|
||||
}
|
||||
|
||||
- (NSArray*)mapCollection:(NSArray*)mappableObjects atKeyPath:(NSString*)keyPath usingMapping:(RKObjectMapping*)mapping {
|
||||
- (NSArray*)mapCollection:(NSArray*)mappableObjects atKeyPath:(NSString*)keyPath usingMapping:(RKObjectAbstractMapping*)mapping {
|
||||
NSAssert(mappableObjects != nil, @"Cannot map without an collection of mappable objects");
|
||||
NSAssert(mapping != nil, @"Cannot map without a mapping to consult");
|
||||
|
||||
@@ -158,8 +157,13 @@
|
||||
[self addErrorWithCode:RKObjectMapperErrorObjectMappingTypeMismatch message:errorMessage keyPath:keyPath userInfo:nil];
|
||||
return nil;
|
||||
}
|
||||
|
||||
for (id mappableObject in objectsToMap) {
|
||||
id destinationObject = [self objectWithMapping:mapping andData:mappableObject];
|
||||
if (! destinationObject) {
|
||||
continue;
|
||||
}
|
||||
|
||||
BOOL success = [self mapFromObject:mappableObject toObject:destinationObject atKeyPath:keyPath usingMapping:mapping];
|
||||
if (success) {
|
||||
[mappedObjects addObject:destinationObject];
|
||||
@@ -170,7 +174,7 @@
|
||||
}
|
||||
|
||||
// The workhorse of this entire process. Emits object loading operations
|
||||
- (BOOL)mapFromObject:(id)mappableObject toObject:(id)destinationObject atKeyPath:keyPath usingMapping:(RKObjectMapping*)mapping {
|
||||
- (BOOL)mapFromObject:(id)mappableObject toObject:(id)destinationObject atKeyPath:keyPath usingMapping:(RKObjectAbstractMapping*)mapping {
|
||||
NSAssert(destinationObject != nil, @"Cannot map without a target object to assign the results to");
|
||||
NSAssert(mappableObject != nil, @"Cannot map without a collection of attributes");
|
||||
NSAssert(mapping != nil, @"Cannot map without an mapping");
|
||||
@@ -180,9 +184,11 @@
|
||||
[self.delegate objectMapper:self willMapFromObject:mappableObject toObject:destinationObject atKeyPath:keyPath usingMapping:mapping];
|
||||
}
|
||||
|
||||
NSError* error = nil;
|
||||
RKObjectMappingOperation* operation = [RKObjectMappingOperation mappingOperationFromObject:mappableObject toObject:destinationObject withObjectMapping:mapping];
|
||||
operation.objectFactory = self;
|
||||
NSError* error = nil;
|
||||
|
||||
RKObjectMappingOperation* operation = [RKObjectMappingOperation mappingOperationFromObject:mappableObject
|
||||
toObject:destinationObject
|
||||
withMapping:mapping];
|
||||
BOOL success = [operation performMapping:&error];
|
||||
if (success) {
|
||||
if ([self.delegate respondsToSelector:@selector(objectMapper:didMapFromObject:toObject:atKeyPath:usingMapping:)]) {
|
||||
@@ -212,7 +218,7 @@
|
||||
// Perform the mapping
|
||||
BOOL foundMappable = NO;
|
||||
NSMutableDictionary* results = [NSMutableDictionary dictionary];
|
||||
NSDictionary* keyPathsAndObjectMappings = [self.mappingProvider objectMappingsByKeyPath];
|
||||
NSDictionary* keyPathsAndObjectMappings = [self.mappingProvider mappingsByKeyPath];
|
||||
for (NSString* keyPath in keyPathsAndObjectMappings) {
|
||||
id mappingResult;
|
||||
id mappableValue;
|
||||
@@ -238,16 +244,16 @@
|
||||
|
||||
// Found something to map
|
||||
foundMappable = YES;
|
||||
RKObjectMapping* objectMapping = [keyPathsAndObjectMappings objectForKey:keyPath];
|
||||
RKObjectAbstractMapping* mapping = [keyPathsAndObjectMappings objectForKey:keyPath];
|
||||
if ([self.delegate respondsToSelector:@selector(objectMapper:didFindMappableObject:atKeyPath:withMapping:)]) {
|
||||
[self.delegate objectMapper:self didFindMappableObject:mappableValue atKeyPath:keyPath withMapping:objectMapping];
|
||||
}
|
||||
if (objectMapping.forceCollectionMapping || [mappableValue isKindOfClass:[NSArray class]] || [mappableValue isKindOfClass:[NSSet class]]) {
|
||||
[self.delegate objectMapper:self didFindMappableObject:mappableValue atKeyPath:keyPath withMapping:mapping];
|
||||
}
|
||||
if (mapping.forceCollectionMapping || [mappableValue isKindOfClass:[NSArray class]] || [mappableValue isKindOfClass:[NSSet class]]) {
|
||||
RKLogDebug(@"Found mappable collection at keyPath '%@': %@", keyPath, mappableValue);
|
||||
mappingResult = [self mapCollection:mappableValue atKeyPath:keyPath usingMapping:objectMapping];
|
||||
mappingResult = [self mapCollection:mappableValue atKeyPath:keyPath usingMapping:mapping];
|
||||
} else {
|
||||
RKLogDebug(@"Found mappable data at keyPath '%@': %@", keyPath, mappableValue);
|
||||
mappingResult = [self mapObject:mappableValue atKeyPath:keyPath usingMapping:objectMapping];
|
||||
mappingResult = [self mapObject:mappableValue atKeyPath:keyPath usingMapping:mapping];
|
||||
}
|
||||
|
||||
if (mappingResult) {
|
||||
@@ -272,14 +278,25 @@
|
||||
return [RKObjectMappingResult mappingResultWithDictionary:results];
|
||||
}
|
||||
|
||||
#pragma - RKObjectFactory methods
|
||||
|
||||
- (id)objectWithMapping:(RKObjectMapping*)objectMapping andData:(id)mappableData {
|
||||
if (self.objectFactory) {
|
||||
return [self.objectFactory objectWithMapping:objectMapping andData:mappableData];
|
||||
- (id)objectWithMapping:(RKObjectAbstractMapping*)abstractMapping andData:(id)mappableData {
|
||||
NSAssert(! [abstractMapping isMemberOfClass:[RKObjectAbstractMapping class]], @"Expected a concrete subclass of RKObjectAbstractMapping");
|
||||
RKObjectMapping* objectMapping = nil;
|
||||
if ([abstractMapping isKindOfClass:[RKObjectPolymorphicMapping class]]) {
|
||||
objectMapping = [(RKObjectPolymorphicMapping*)abstractMapping objectMappingForDictionary:mappableData];
|
||||
if (! objectMapping) {
|
||||
RKLogDebug(@"Mapping %@ declined mapping for data %@: returned nil objectMapping", abstractMapping, mappableData);
|
||||
}
|
||||
} else if ([abstractMapping isKindOfClass:[RKObjectMapping class]]) {
|
||||
objectMapping = (RKObjectMapping*)abstractMapping;
|
||||
} else {
|
||||
NSAssert(objectMapping, @"Encountered unknown mapping type '%@'", NSStringFromClass([abstractMapping class]));
|
||||
}
|
||||
|
||||
return [[objectMapping.objectClass new] autorelease];
|
||||
if (objectMapping) {
|
||||
return [objectMapping mappableObjectForData:mappableData];
|
||||
}
|
||||
|
||||
return nil;
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
@@ -9,8 +9,9 @@
|
||||
#import "../Support/Errors.h"
|
||||
|
||||
typedef enum RKObjectMapperErrors {
|
||||
RKObjectMapperErrorObjectMappingNotFound, // No mapping found
|
||||
RKObjectMapperErrorObjectMappingTypeMismatch, // Target class and object mapping are in disagreement
|
||||
RKObjectMapperErrorUnmappableContent, // No mappable attributes or relationships were found
|
||||
RKObjectMapperErrorFromMappingResult
|
||||
RKObjectMapperErrorObjectMappingNotFound = 1001, // No mapping found
|
||||
RKObjectMapperErrorObjectMappingTypeMismatch = 1002, // Target class and object mapping are in disagreement
|
||||
RKObjectMapperErrorUnmappableContent = 1003, // No mappable attributes or relationships were found
|
||||
RKObjectMapperErrorFromMappingResult = 1004, // The error was returned from the mapping result
|
||||
RKObjectMapperErrorValidationFailure = 1005 // Generic error code for use when constructing validation errors
|
||||
} RKObjectMapperErrorCode;
|
||||
|
||||
@@ -6,10 +6,11 @@
|
||||
// Copyright 2011 Two Toasters. All rights reserved.
|
||||
//
|
||||
|
||||
@interface RKObjectMapper (Private) <RKObjectFactory>
|
||||
@interface RKObjectMapper (Private)
|
||||
|
||||
- (id)mapObject:(id)mappableObject atKeyPath:keyPath usingMapping:(RKObjectMapping*)mapping;
|
||||
- (NSArray*)mapCollection:(NSArray*)mappableObjects atKeyPath:(NSString*)keyPath usingMapping:(RKObjectMapping*)mapping;
|
||||
- (BOOL)mapFromObject:(id)mappableObject toObject:(id)destinationObject atKeyPath:keyPath usingMapping:(RKObjectMapping*)mapping;
|
||||
- (id)mapObject:(id)mappableObject atKeyPath:keyPath usingMapping:(RKObjectAbstractMapping*)mapping;
|
||||
- (NSArray*)mapCollection:(NSArray*)mappableObjects atKeyPath:(NSString*)keyPath usingMapping:(RKObjectAbstractMapping*)mapping;
|
||||
- (BOOL)mapFromObject:(id)mappableObject toObject:(id)destinationObject atKeyPath:keyPath usingMapping:(RKObjectAbstractMapping*)mapping;
|
||||
- (id)objectWithMapping:(RKObjectAbstractMapping*)objectMapping andData:(id)mappableData;
|
||||
|
||||
@end
|
||||
|
||||
@@ -7,6 +7,7 @@
|
||||
//
|
||||
|
||||
#import <Foundation/Foundation.h>
|
||||
#import "RKObjectAbstractMapping.h"
|
||||
#import "RKObjectAttributeMapping.h"
|
||||
#import "RKObjectRelationshipMapping.h"
|
||||
|
||||
@@ -30,7 +31,7 @@ relationship. Relationships are processed using an object mapping as well.
|
||||
Instances of RKObjectMapping are used to configure RKObjectMappingOperation instances, which actually
|
||||
perform the mapping work. Both object loading and serialization are defined in terms of object mappings.
|
||||
*/
|
||||
@interface RKObjectMapping : NSObject {
|
||||
@interface RKObjectMapping : RKObjectAbstractMapping {
|
||||
Class _objectClass;
|
||||
NSMutableArray* _mappings;
|
||||
NSMutableArray* _dateFormatStrings;
|
||||
@@ -247,9 +248,9 @@ relationship. Relationships are processed using an object mapping as well.
|
||||
|
||||
@param relationshipKey A key-value coding key corresponding to a value in the mappable source object and a property
|
||||
on the destination class that have the same name.
|
||||
@param objectMapping An object mapping to use for processing the relationship.
|
||||
@param objectOrPolymorphicMapping An RKObjectMapping or RKObjectPolymorphic mapping to apply when mapping the relationship
|
||||
*/
|
||||
- (void)mapRelationship:(NSString*)relationshipKey withObjectMapping:(RKObjectMapping*)objectMapping;
|
||||
- (void)mapRelationship:(NSString*)relationshipKey withMapping:(RKObjectAbstractMapping*)objectOrPolymorphicMapping;
|
||||
|
||||
/**
|
||||
Syntactic sugar to improve readability when defining a relationship mapping. Implies that the mapping
|
||||
@@ -257,7 +258,7 @@ relationship. Relationships are processed using an object mapping as well.
|
||||
|
||||
@see mapRelationship:withObjectMapping:
|
||||
*/
|
||||
- (void)hasMany:(NSString*)keyPath withObjectMapping:(RKObjectMapping*)mapping;
|
||||
- (void)hasMany:(NSString*)keyPath withMapping:(RKObjectAbstractMapping*)objectOrPolymorphicMapping;
|
||||
|
||||
/**
|
||||
Syntactic sugar to improve readability when defining a relationship mapping. Implies that the mapping
|
||||
@@ -265,7 +266,7 @@ relationship. Relationships are processed using an object mapping as well.
|
||||
|
||||
@see mapRelationship:withObjectMapping:
|
||||
*/
|
||||
- (void)hasOne:(NSString*)keyPath withObjectMapping:(RKObjectMapping*)mapping;
|
||||
- (void)hasOne:(NSString*)keyPath withMapping:(RKObjectAbstractMapping*)objectOrPolymorphicMapping;
|
||||
|
||||
/**
|
||||
Instantiate and add an RKObjectAttributeMapping instance targeting a keyPath within the mappable
|
||||
@@ -306,7 +307,7 @@ relationship. Relationships are processed using an object mapping as well.
|
||||
@param objectMapping An object mapping to use when processing the nested objects
|
||||
@see RKObjectRelationshipMapping
|
||||
*/
|
||||
- (void)mapKeyPath:(NSString *)sourceKeyPath toRelationship:(NSString*)destinationRelationship withObjectMapping:(RKObjectMapping *)objectMapping;
|
||||
- (void)mapKeyPath:(NSString *)sourceKeyPath toRelationship:(NSString*)destinationRelationship withMapping:(RKObjectAbstractMapping *)objectOrPolymorphicMapping;
|
||||
|
||||
/**
|
||||
Instantiate and add an RKObjectRelationshipMapping instance targeting a keyPath within the mappable
|
||||
@@ -321,7 +322,7 @@ relationship. Relationships are processed using an object mapping as well.
|
||||
|
||||
@see mapKeyPath:toRelationship:withObjectMapping:
|
||||
*/
|
||||
- (void)mapKeyPath:(NSString *)relationshipKeyPath toRelationship:(NSString*)keyPath withObjectMapping:(RKObjectMapping *)objectMapping serialize:(BOOL)serialize;
|
||||
- (void)mapKeyPath:(NSString *)relationshipKeyPath toRelationship:(NSString*)keyPath withMapping:(RKObjectAbstractMapping *)objectOrPolymorphicMapping serialize:(BOOL)serialize;
|
||||
|
||||
/**
|
||||
Quickly define a group of attribute mappings using alternating keyPath and attribute names. You must provide
|
||||
@@ -397,4 +398,12 @@ relationship. Relationships are processed using an object mapping as well.
|
||||
*/
|
||||
- (id)defaultValueForMissingAttribute:(NSString*)attributeName;
|
||||
|
||||
/**
|
||||
Returns an auto-released object that can be used to apply this object mapping
|
||||
given a set of mappable data. For transient objects, this generally returns an
|
||||
instance of the objectClass. For Core Data backed persistent objects, mappableData
|
||||
will be inspected to search for primary key data to lookup existing object instances.
|
||||
*/
|
||||
- (id)mappableObjectForData:(id)mappableData;
|
||||
|
||||
@end
|
||||
|
||||
@@ -8,6 +8,7 @@
|
||||
|
||||
#import "RKObjectMapping.h"
|
||||
#import "RKObjectRelationshipMapping.h"
|
||||
#import "../Support/RKLog.h"
|
||||
|
||||
// Constants
|
||||
NSString* const RKObjectMappingNestingAttributeKeyName = @"<RK_NESTING_ATTRIBUTE>";
|
||||
@@ -139,17 +140,17 @@ NSString* const RKObjectMappingNestingAttributeKeyName = @"<RK_NESTING_ATTRIBUTE
|
||||
[self mapAttributesSet:attributeKeyPaths];
|
||||
}
|
||||
|
||||
- (void)mapKeyPath:(NSString *)relationshipKeyPath toRelationship:(NSString*)keyPath withObjectMapping:(RKObjectMapping *)objectMapping serialize:(BOOL)serialize {
|
||||
RKObjectRelationshipMapping* mapping = [RKObjectRelationshipMapping mappingFromKeyPath:relationshipKeyPath toKeyPath:keyPath objectMapping:objectMapping reversible:serialize];
|
||||
- (void)mapKeyPath:(NSString *)relationshipKeyPath toRelationship:(NSString*)keyPath withMapping:(RKObjectAbstractMapping *)objectOrPolymorphicMapping serialize:(BOOL)serialize {
|
||||
RKObjectRelationshipMapping* mapping = [RKObjectRelationshipMapping mappingFromKeyPath:relationshipKeyPath toKeyPath:keyPath withMapping:objectOrPolymorphicMapping reversible:serialize];
|
||||
[self addRelationshipMapping:mapping];
|
||||
}
|
||||
|
||||
- (void)mapKeyPath:(NSString *)relationshipKeyPath toRelationship:(NSString*)keyPath withObjectMapping:(RKObjectMapping *)objectMapping {
|
||||
[self mapKeyPath:relationshipKeyPath toRelationship:keyPath withObjectMapping:objectMapping serialize:YES];
|
||||
- (void)mapKeyPath:(NSString *)relationshipKeyPath toRelationship:(NSString*)keyPath withMapping:(RKObjectAbstractMapping*)objectOrPolymorphicMapping {
|
||||
[self mapKeyPath:relationshipKeyPath toRelationship:keyPath withMapping:objectOrPolymorphicMapping serialize:YES];
|
||||
}
|
||||
|
||||
- (void)mapRelationship:(NSString*)relationshipKeyPath withObjectMapping:(RKObjectMapping*)objectMapping {
|
||||
[self mapKeyPath:relationshipKeyPath toRelationship:relationshipKeyPath withObjectMapping:objectMapping];
|
||||
- (void)mapRelationship:(NSString*)relationshipKeyPath withMapping:(RKObjectAbstractMapping*)objectOrPolymorphicMapping {
|
||||
[self mapKeyPath:relationshipKeyPath toRelationship:relationshipKeyPath withMapping:objectOrPolymorphicMapping];
|
||||
}
|
||||
|
||||
- (void)mapKeyPath:(NSString*)sourceKeyPath toAttribute:(NSString*)destinationKeyPath {
|
||||
@@ -157,12 +158,12 @@ NSString* const RKObjectMappingNestingAttributeKeyName = @"<RK_NESTING_ATTRIBUTE
|
||||
[self addAttributeMapping:mapping];
|
||||
}
|
||||
|
||||
- (void)hasMany:(NSString*)keyPath withObjectMapping:(RKObjectMapping*)objectMapping {
|
||||
[self mapRelationship:keyPath withObjectMapping:objectMapping];
|
||||
- (void)hasMany:(NSString*)keyPath withMapping:(RKObjectAbstractMapping*)objectOrPolymorphicMapping {
|
||||
[self mapRelationship:keyPath withMapping:objectOrPolymorphicMapping];
|
||||
}
|
||||
|
||||
- (void)hasOne:(NSString*)keyPath withObjectMapping:(RKObjectMapping*)mapping {
|
||||
[self mapRelationship:keyPath withObjectMapping:mapping];
|
||||
- (void)hasOne:(NSString*)keyPath withMapping:(RKObjectAbstractMapping*)objectOrPolymorphicMapping {
|
||||
[self mapRelationship:keyPath withMapping:objectOrPolymorphicMapping];
|
||||
}
|
||||
|
||||
- (void)removeAllMappings {
|
||||
@@ -189,8 +190,13 @@ NSString* const RKObjectMappingNestingAttributeKeyName = @"<RK_NESTING_ATTRIBUTE
|
||||
}
|
||||
|
||||
for (RKObjectRelationshipMapping* relationshipMapping in self.relationshipMappings) {
|
||||
if (relationshipMapping.reversible) {
|
||||
[inverseMapping mapKeyPath:relationshipMapping.destinationKeyPath toRelationship:relationshipMapping.sourceKeyPath withObjectMapping:[relationshipMapping.objectMapping inverseMappingAtDepth:depth+1]];
|
||||
if (relationshipMapping.reversible) {
|
||||
RKObjectAbstractMapping* mapping = relationshipMapping.mapping;
|
||||
if (! [mapping isKindOfClass:[RKObjectMapping class]]) {
|
||||
RKLogWarning(@"Unable to generate inverse mapping for relationship '%@': %@ relationships cannot be inversed.", relationshipMapping.sourceKeyPath, NSStringFromClass([mapping class]));
|
||||
continue;
|
||||
}
|
||||
[inverseMapping mapKeyPath:relationshipMapping.destinationKeyPath toRelationship:relationshipMapping.sourceKeyPath withMapping:[(RKObjectMapping*)mapping inverseMappingAtDepth:depth+1]];
|
||||
}
|
||||
}
|
||||
|
||||
@@ -241,4 +247,8 @@ NSString* const RKObjectMappingNestingAttributeKeyName = @"<RK_NESTING_ATTRIBUTE
|
||||
return nil;
|
||||
}
|
||||
|
||||
- (id)mappableObjectForData:(id)mappableData {
|
||||
return [[self.objectClass new] autorelease];
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
@@ -8,7 +8,6 @@
|
||||
|
||||
#import "RKObjectMapping.h"
|
||||
#import "RKObjectAttributeMapping.h"
|
||||
#import "RKObjectFactory.h"
|
||||
|
||||
@class RKObjectMappingOperation;
|
||||
|
||||
@@ -31,7 +30,6 @@
|
||||
id _destinationObject;
|
||||
RKObjectMapping* _objectMapping;
|
||||
id<RKObjectMappingOperationDelegate> _delegate;
|
||||
id<RKObjectFactory> _objectFactory;
|
||||
NSDictionary* _nestedAttributeSubstitution;
|
||||
NSError* _validationError;
|
||||
}
|
||||
@@ -57,22 +55,16 @@
|
||||
*/
|
||||
@property (nonatomic, assign) id<RKObjectMappingOperationDelegate> delegate;
|
||||
|
||||
/**
|
||||
An object factory responsible for creating new instances of mappable objects
|
||||
necessary for the processing of relationship mappings
|
||||
*/
|
||||
@property (nonatomic, assign) id<RKObjectFactory> objectFactory;
|
||||
|
||||
/**
|
||||
Create a new mapping operation configured to transform the object representation
|
||||
in a source object to a new destination object according to an object mapping definition
|
||||
*/
|
||||
+ (RKObjectMappingOperation*)mappingOperationFromObject:(id)sourceObject toObject:(id)destinationObject withObjectMapping:(RKObjectMapping*)objectMapping;
|
||||
+ (RKObjectMappingOperation*)mappingOperationFromObject:(id)sourceObject toObject:(id)destinationObject withMapping:(RKObjectAbstractMapping*)mapping;
|
||||
|
||||
/**
|
||||
Initialize a mapping operation for an object and set of data at a particular key path with an object mapping definition
|
||||
*/
|
||||
- (id)initWithSourceObject:(id)sourceObject destinationObject:(id)destinationObject objectMapping:(RKObjectMapping*)objectMapping;
|
||||
- (id)initWithSourceObject:(id)sourceObject destinationObject:(id)destinationObject mapping:(RKObjectAbstractMapping*)mapping;
|
||||
|
||||
/**
|
||||
Process all mappable values from the mappable dictionary and assign them to the target object
|
||||
|
||||
@@ -22,29 +22,64 @@
|
||||
|
||||
extern NSString* const RKObjectMappingNestingAttributeKeyName;
|
||||
|
||||
// Temporary home for object equivalancy tests
|
||||
BOOL RKObjectIsValueEqualToValue(id sourceValue, id destinationValue) {
|
||||
NSCAssert(sourceValue, @"Expected sourceValue not to be nil");
|
||||
NSCAssert(destinationValue, @"Expected destinationValue not to be nil");
|
||||
|
||||
SEL comparisonSelector;
|
||||
if ([sourceValue isKindOfClass:[NSString class]]) {
|
||||
comparisonSelector = @selector(isEqualToString:);
|
||||
} else if ([sourceValue isKindOfClass:[NSNumber class]]) {
|
||||
comparisonSelector = @selector(isEqualToNumber:);
|
||||
} else if ([sourceValue isKindOfClass:[NSDate class]]) {
|
||||
comparisonSelector = @selector(isEqualToDate:);
|
||||
} else if ([sourceValue isKindOfClass:[NSArray class]]) {
|
||||
comparisonSelector = @selector(isEqualToArray:);
|
||||
} else if ([sourceValue isKindOfClass:[NSDictionary class]]) {
|
||||
comparisonSelector = @selector(isEqualToDictionary:);
|
||||
} else if ([sourceValue isKindOfClass:[NSSet class]]) {
|
||||
comparisonSelector = @selector(isEqualToSet:);
|
||||
} else {
|
||||
comparisonSelector = @selector(isEqual:);
|
||||
}
|
||||
|
||||
// Comparison magic using function pointers. See this page for details: http://www.red-sweater.com/blog/320/abusing-objective-c-with-class
|
||||
// Original code courtesy of Greg Parker
|
||||
// This is necessary because isEqualToNumber will return negative integer values that aren't coercable directly to BOOL's without help [sbw]
|
||||
BOOL (*ComparisonSender)(id, SEL, id) = (BOOL (*)(id, SEL, id)) objc_msgSend;
|
||||
return ComparisonSender(sourceValue, comparisonSelector, destinationValue);
|
||||
}
|
||||
|
||||
@implementation RKObjectMappingOperation
|
||||
|
||||
@synthesize sourceObject = _sourceObject;
|
||||
@synthesize destinationObject = _destinationObject;
|
||||
@synthesize objectMapping = _objectMapping;
|
||||
@synthesize delegate = _delegate;
|
||||
@synthesize objectFactory = _objectFactory;
|
||||
|
||||
+ (RKObjectMappingOperation*)mappingOperationFromObject:(id)sourceObject toObject:(id)destinationObject withObjectMapping:(RKObjectMapping*)objectMapping {
|
||||
return [[[self alloc] initWithSourceObject:sourceObject destinationObject:destinationObject objectMapping:objectMapping] autorelease];
|
||||
+ (RKObjectMappingOperation*)mappingOperationFromObject:(id)sourceObject toObject:(id)destinationObject withMapping:(RKObjectAbstractMapping*)objectMapping {
|
||||
return [[[self alloc] initWithSourceObject:sourceObject destinationObject:destinationObject mapping:objectMapping] autorelease];
|
||||
}
|
||||
|
||||
- (id)initWithSourceObject:(id)sourceObject destinationObject:(id)destinationObject objectMapping:(RKObjectMapping*)objectMapping {
|
||||
- (id)initWithSourceObject:(id)sourceObject destinationObject:(id)destinationObject mapping:(RKObjectAbstractMapping*)objectMapping {
|
||||
NSAssert(sourceObject != nil, @"Cannot perform a mapping operation without a sourceObject object");
|
||||
NSAssert(destinationObject != nil, @"Cannot perform a mapping operation without a destinationObject");
|
||||
NSAssert(objectMapping != nil, @"Cannot perform a mapping operation without an object mapping to apply");
|
||||
NSAssert(objectMapping != nil, @"Cannot perform a mapping operation without a mapping");
|
||||
|
||||
self = [super init];
|
||||
if (self) {
|
||||
_sourceObject = [sourceObject retain];
|
||||
_sourceObject = [sourceObject retain];
|
||||
_destinationObject = [destinationObject retain];
|
||||
_objectMapping = [objectMapping retain];
|
||||
}
|
||||
|
||||
if ([objectMapping isKindOfClass:[RKObjectPolymorphicMapping class]]) {
|
||||
_objectMapping = [[(RKObjectPolymorphicMapping*)objectMapping objectMappingForDictionary:_sourceObject] retain];
|
||||
RKLogDebug(@"RKObjectMappingOperation was initialized with a polymorphic mapping. Determined concrete mapping = %@", _objectMapping);
|
||||
} else if ([objectMapping isKindOfClass:[RKObjectMapping class]]) {
|
||||
_objectMapping = (RKObjectMapping*)[objectMapping retain];
|
||||
}
|
||||
NSAssert(_objectMapping, @"Cannot perform a mapping operation with an object mapping");
|
||||
}
|
||||
|
||||
return self;
|
||||
}
|
||||
@@ -131,32 +166,8 @@ extern NSString* const RKObjectMappingNestingAttributeKeyName;
|
||||
return nil;
|
||||
}
|
||||
|
||||
- (BOOL)isValue:(id)sourceValue equalToValue:(id)destinationValue {
|
||||
NSAssert(sourceValue, @"Expected sourceValue not to be nil");
|
||||
NSAssert(destinationValue, @"Expected destinationValue not to be nil");
|
||||
|
||||
SEL comparisonSelector;
|
||||
if ([sourceValue isKindOfClass:[NSString class]]) {
|
||||
comparisonSelector = @selector(isEqualToString:);
|
||||
} else if ([sourceValue isKindOfClass:[NSNumber class]]) {
|
||||
comparisonSelector = @selector(isEqualToNumber:);
|
||||
} else if ([sourceValue isKindOfClass:[NSDate class]]) {
|
||||
comparisonSelector = @selector(isEqualToDate:);
|
||||
} else if ([sourceValue isKindOfClass:[NSArray class]]) {
|
||||
comparisonSelector = @selector(isEqualToArray:);
|
||||
} else if ([sourceValue isKindOfClass:[NSDictionary class]]) {
|
||||
comparisonSelector = @selector(isEqualToDictionary:);
|
||||
} else if ([sourceValue isKindOfClass:[NSSet class]]) {
|
||||
comparisonSelector = @selector(isEqualToSet:);
|
||||
} else {
|
||||
comparisonSelector = @selector(isEqual:);
|
||||
}
|
||||
|
||||
// Comparison magic using function pointers. See this page for details: http://www.red-sweater.com/blog/320/abusing-objective-c-with-class
|
||||
// Original code courtesy of Greg Parker
|
||||
// This is necessary because isEqualToNumber will return negative integer values that aren't coercable directly to BOOL's without help [sbw]
|
||||
BOOL (*ComparisonSender)(id, SEL, id) = (BOOL (*)(id, SEL, id)) objc_msgSend;
|
||||
return ComparisonSender(sourceValue, comparisonSelector, destinationValue);
|
||||
- (BOOL)isValue:(id)sourceValue equalToValue:(id)destinationValue {
|
||||
return RKObjectIsValueEqualToValue(sourceValue, destinationValue);
|
||||
}
|
||||
|
||||
- (BOOL)validateValue:(id)value atKeyPath:(NSString*)keyPath {
|
||||
@@ -300,12 +311,14 @@ extern NSString* const RKObjectMappingNestingAttributeKeyName;
|
||||
return ([value isKindOfClass:[NSSet class]] || [value isKindOfClass:[NSArray class]]);
|
||||
}
|
||||
|
||||
- (BOOL)mapNestedObject:(id)anObject toObject:(id)anotherObject withMapping:(RKObjectRelationshipMapping*)mapping {
|
||||
- (BOOL)mapNestedObject:(id)anObject toObject:(id)anotherObject withRealtionshipMapping:(RKObjectRelationshipMapping*)relationshipMapping {
|
||||
NSAssert(anObject, @"Cannot map nested object without a nested source object");
|
||||
NSAssert(anotherObject, @"Cannot map nested object without a destination object");
|
||||
NSAssert(relationshipMapping, @"Cannot map a nested object relationship without a relationship mapping");
|
||||
NSError* error = nil;
|
||||
|
||||
RKObjectMappingOperation* subOperation = [RKObjectMappingOperation mappingOperationFromObject:anObject toObject:anotherObject withObjectMapping:mapping.objectMapping];
|
||||
RKObjectMappingOperation* subOperation = [RKObjectMappingOperation mappingOperationFromObject:anObject toObject:anotherObject withMapping:relationshipMapping.mapping];
|
||||
subOperation.delegate = self.delegate;
|
||||
subOperation.objectFactory = self.objectFactory;
|
||||
if (NO == [subOperation performMapping:&error]) {
|
||||
RKLogWarning(@"WARNING: Failed mapping nested object: %@", [error localizedDescription]);
|
||||
}
|
||||
@@ -317,16 +330,16 @@ extern NSString* const RKObjectMappingNestingAttributeKeyName;
|
||||
BOOL appliedMappings = NO;
|
||||
id destinationObject = nil;
|
||||
|
||||
for (RKObjectRelationshipMapping* mapping in [self relationshipMappings]) {
|
||||
id value = [self.sourceObject valueForKeyPath:mapping.sourceKeyPath];
|
||||
for (RKObjectRelationshipMapping* relationshipMapping in [self relationshipMappings]) {
|
||||
id value = [self.sourceObject valueForKeyPath:relationshipMapping.sourceKeyPath];
|
||||
|
||||
if (value == nil || value == [NSNull null] || [value isEqual:[NSNull null]]) {
|
||||
RKLogDebug(@"Did not find mappable relationship value keyPath '%@'", mapping.sourceKeyPath);
|
||||
RKLogDebug(@"Did not find mappable relationship value keyPath '%@'", relationshipMapping.sourceKeyPath);
|
||||
|
||||
// Optionally nil out the property
|
||||
if ([self.objectMapping setNilForMissingRelationships] && [self shouldSetValue:nil atKeyPath:mapping.destinationKeyPath]) {
|
||||
RKLogTrace(@"Setting nil for missing relationship value at keyPath '%@'", mapping.sourceKeyPath);
|
||||
[self.destinationObject setValue:nil forKey:mapping.destinationKeyPath];
|
||||
if ([self.objectMapping setNilForMissingRelationships] && [self shouldSetValue:nil atKeyPath:relationshipMapping.destinationKeyPath]) {
|
||||
RKLogTrace(@"Setting nil for missing relationship value at keyPath '%@'", relationshipMapping.sourceKeyPath);
|
||||
[self.destinationObject setValue:nil forKey:relationshipMapping.destinationKeyPath];
|
||||
}
|
||||
|
||||
continue;
|
||||
@@ -334,37 +347,57 @@ extern NSString* const RKObjectMappingNestingAttributeKeyName;
|
||||
|
||||
if ([self isValueACollection:value]) {
|
||||
// One to many relationship
|
||||
RKLogDebug(@"Mapping one to many relationship value at keyPath '%@' to '%@'", mapping.sourceKeyPath, mapping.destinationKeyPath);
|
||||
RKLogDebug(@"Mapping one to many relationship value at keyPath '%@' to '%@'", relationshipMapping.sourceKeyPath, relationshipMapping.destinationKeyPath);
|
||||
appliedMappings = YES;
|
||||
|
||||
destinationObject = [NSMutableArray arrayWithCapacity:[value count]];
|
||||
for (id nestedObject in value) {
|
||||
id mappedObject = [self.objectFactory objectWithMapping:mapping.objectMapping andData:nestedObject];
|
||||
if ([self mapNestedObject:nestedObject toObject:mappedObject withMapping:mapping]) {
|
||||
for (id nestedObject in value) {
|
||||
RKObjectAbstractMapping* abstractMapping = relationshipMapping.mapping;
|
||||
RKObjectMapping* objectMapping = nil;
|
||||
if ([abstractMapping isKindOfClass:[RKObjectPolymorphicMapping class]]) {
|
||||
objectMapping = [(RKObjectPolymorphicMapping*)abstractMapping objectMappingForDictionary:nestedObject];
|
||||
if (! objectMapping) {
|
||||
RKLogDebug(@"Mapping %@ declined mapping for data %@: returned nil objectMapping", abstractMapping, nestedObject);
|
||||
continue;
|
||||
}
|
||||
} else if ([abstractMapping isKindOfClass:[RKObjectMapping class]]) {
|
||||
objectMapping = (RKObjectMapping*)abstractMapping;
|
||||
} else {
|
||||
NSAssert(objectMapping, @"Encountered unknown mapping type '%@'", NSStringFromClass([abstractMapping class]));
|
||||
}
|
||||
id mappedObject = [objectMapping mappableObjectForData:nestedObject];
|
||||
if ([self mapNestedObject:nestedObject toObject:mappedObject withRealtionshipMapping:relationshipMapping]) {
|
||||
[destinationObject addObject:mappedObject];
|
||||
}
|
||||
}
|
||||
|
||||
// Transform from NSSet <-> NSArray if necessary
|
||||
Class type = [[RKObjectPropertyInspector sharedInspector] typeForProperty:mapping.destinationKeyPath ofClass:[self.destinationObject class]];
|
||||
Class type = [[RKObjectPropertyInspector sharedInspector] typeForProperty:relationshipMapping.destinationKeyPath ofClass:[self.destinationObject class]];
|
||||
if (type && NO == [[destinationObject class] isSubclassOfClass:type]) {
|
||||
destinationObject = [self transformValue:destinationObject atKeyPath:mapping.sourceKeyPath toType:type];
|
||||
destinationObject = [self transformValue:destinationObject atKeyPath:relationshipMapping.sourceKeyPath toType:type];
|
||||
}
|
||||
} else {
|
||||
// One to one relationship
|
||||
RKLogDebug(@"Mapping one to one relationship value at keyPath '%@' to '%@'", mapping.sourceKeyPath, mapping.destinationKeyPath);
|
||||
RKLogDebug(@"Mapping one to one relationship value at keyPath '%@' to '%@'", relationshipMapping.sourceKeyPath, relationshipMapping.destinationKeyPath);
|
||||
|
||||
destinationObject = [self.objectFactory objectWithMapping:mapping.objectMapping andData:value];
|
||||
NSAssert(destinationObject, @"Cannot map a relationship without an object factory to create it...");
|
||||
if ([self mapNestedObject:value toObject:destinationObject withMapping:mapping]) {
|
||||
RKObjectAbstractMapping* abstractMapping = relationshipMapping.mapping;
|
||||
RKObjectMapping* objectMapping = nil;
|
||||
if ([abstractMapping isKindOfClass:[RKObjectPolymorphicMapping class]]) {
|
||||
objectMapping = [(RKObjectPolymorphicMapping*)abstractMapping objectMappingForDictionary:value];
|
||||
} else if ([abstractMapping isKindOfClass:[RKObjectMapping class]]) {
|
||||
objectMapping = (RKObjectMapping*)abstractMapping;
|
||||
}
|
||||
NSAssert(objectMapping, @"Encountered unknown mapping type '%@'", NSStringFromClass([abstractMapping class]));
|
||||
destinationObject = [objectMapping mappableObjectForData:value];
|
||||
if ([self mapNestedObject:value toObject:destinationObject withRealtionshipMapping:relationshipMapping]) {
|
||||
appliedMappings = YES;
|
||||
}
|
||||
}
|
||||
|
||||
// If the relationship has changed, set it
|
||||
if ([self shouldSetValue:destinationObject atKeyPath:mapping.destinationKeyPath]) {
|
||||
RKLogTrace(@"Mapped relationship object from keyPath '%@' to '%@'. Value: %@", mapping.sourceKeyPath, mapping.destinationKeyPath, destinationObject);
|
||||
[self.destinationObject setValue:destinationObject forKey:mapping.destinationKeyPath];
|
||||
if ([self shouldSetValue:destinationObject atKeyPath:relationshipMapping.destinationKeyPath]) {
|
||||
RKLogTrace(@"Mapped relationship object from keyPath '%@' to '%@'. Value: %@", relationshipMapping.sourceKeyPath, relationshipMapping.destinationKeyPath, destinationObject);
|
||||
[self.destinationObject setValue:destinationObject forKey:relationshipMapping.destinationKeyPath];
|
||||
}
|
||||
|
||||
// Fail out if a validation error has occurred
|
||||
|
||||
@@ -7,6 +7,7 @@
|
||||
//
|
||||
|
||||
#import "RKObjectMapping.h"
|
||||
#import "RKObjectPolymorphicMapping.h"
|
||||
|
||||
/**
|
||||
Responsible for providing object mappings to an instance of the object mapper
|
||||
@@ -14,33 +15,27 @@
|
||||
*/
|
||||
@interface RKObjectMappingProvider : NSObject {
|
||||
NSMutableArray* _objectMappings;
|
||||
NSMutableDictionary* _objectMappingsByKeyPath;
|
||||
NSMutableDictionary* _mappingsByKeyPath;
|
||||
NSMutableDictionary* _serializationMappings;
|
||||
}
|
||||
|
||||
/**
|
||||
Set a mapping for a keypath that comes back in your payload
|
||||
|
||||
@deprecated
|
||||
Instructs the mapping provider to use the mapping provided when it encounters content at the specified
|
||||
key path
|
||||
*/
|
||||
- (void)setMapping:(RKObjectMapping*)mapping forKeyPath:(NSString*)keyPath DEPRECATED_ATTRIBUTE;
|
||||
- (void)setMapping:(RKObjectAbstractMapping*)objectOrPolymorphicMapping forKeyPath:(NSString*)keyPath;
|
||||
|
||||
/**
|
||||
Configure an object mapping to handle data that appears at a particular keyPath in
|
||||
a payload loaded from a
|
||||
Returns the RKObjectMapping or RKObjectPolymorphic mapping configured for use
|
||||
when mappable content is encountered at keyPath
|
||||
*/
|
||||
- (void)setObjectMapping:(RKObjectMapping*)mapping forKeyPath:(NSString*)keyPath;
|
||||
- (RKObjectAbstractMapping*)mappingForKeyPath:(NSString*)keyPath;
|
||||
|
||||
/**
|
||||
Returns the object mapping to use for mapping the specified keyPath into an object graph
|
||||
Returns a dictionary where the keys are mappable keyPaths and the values are the RKObjectMapping
|
||||
or RKObjectPolymorphic mappings to use for mappable data that appears at the keyPath.
|
||||
*/
|
||||
- (RKObjectMapping*)objectMappingForKeyPath:(NSString*)keyPath;
|
||||
|
||||
/**
|
||||
Returns a dictionary where the keys are mappable keyPaths and the values are the object
|
||||
mapping to use for objects that appear at the keyPath.
|
||||
*/
|
||||
- (NSDictionary*)objectMappingsByKeyPath;
|
||||
- (NSDictionary*)mappingsByKeyPath;
|
||||
|
||||
/**
|
||||
Registers an object mapping as being rooted at a specific keyPath. The keyPath will be registered
|
||||
@@ -111,4 +106,30 @@
|
||||
*/
|
||||
- (RKObjectMapping*)serializationMappingForClass:(Class)objectClass;
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////
|
||||
/// @name Deprecated Object Mapping Methods
|
||||
|
||||
/**
|
||||
Configure an object mapping to handle data that appears at a particular keyPath in
|
||||
a payload loaded from a
|
||||
|
||||
@deprecated
|
||||
*/
|
||||
- (void)setObjectMapping:(RKObjectMapping*)mapping forKeyPath:(NSString*)keyPath DEPRECATED_ATTRIBUTE;
|
||||
|
||||
/**
|
||||
Returns the object mapping to use for mapping the specified keyPath into an object graph
|
||||
|
||||
@deprecated
|
||||
*/
|
||||
- (RKObjectMapping*)objectMappingForKeyPath:(NSString*)keyPath DEPRECATED_ATTRIBUTE;
|
||||
|
||||
/**
|
||||
Returns a dictionary where the keys are mappable keyPaths and the values are the object
|
||||
mapping to use for objects that appear at the keyPath.
|
||||
|
||||
@deprecated
|
||||
*/
|
||||
- (NSDictionary*)objectMappingsByKeyPath DEPRECATED_ATTRIBUTE;
|
||||
|
||||
@end
|
||||
|
||||
@@ -13,7 +13,7 @@
|
||||
- (id)init {
|
||||
if ((self = [super init])) {
|
||||
_objectMappings = [NSMutableArray new];
|
||||
_objectMappingsByKeyPath = [NSMutableDictionary new];
|
||||
_mappingsByKeyPath = [NSMutableDictionary new];
|
||||
_serializationMappings = [NSMutableDictionary new];
|
||||
}
|
||||
return self;
|
||||
@@ -21,21 +21,17 @@
|
||||
|
||||
- (void)dealloc {
|
||||
[_objectMappings release];
|
||||
[_objectMappingsByKeyPath release];
|
||||
[_mappingsByKeyPath release];
|
||||
[_serializationMappings release];
|
||||
[super dealloc];
|
||||
}
|
||||
|
||||
- (RKObjectMapping*)objectMappingForKeyPath:(NSString*)keyPath {
|
||||
return [_objectMappingsByKeyPath objectForKey:keyPath];
|
||||
}
|
||||
|
||||
- (void)setMapping:(RKObjectMapping*)mapping forKeyPath:(NSString*)keyPath {
|
||||
[_objectMappingsByKeyPath setValue:mapping forKey:keyPath];
|
||||
[_mappingsByKeyPath setValue:mapping forKey:keyPath];
|
||||
}
|
||||
|
||||
- (void)setObjectMapping:(RKObjectMapping*)mapping forKeyPath:(NSString*)keyPath {
|
||||
[_objectMappingsByKeyPath setValue:mapping forKey:keyPath];
|
||||
- (RKObjectAbstractMapping*)mappingForKeyPath:(NSString*)keyPath {
|
||||
return [_mappingsByKeyPath objectForKey:keyPath];
|
||||
}
|
||||
|
||||
- (void)setSerializationMapping:(RKObjectMapping *)mapping forClass:(Class)objectClass {
|
||||
@@ -46,14 +42,14 @@
|
||||
return (RKObjectMapping*)[_serializationMappings objectForKey:NSStringFromClass(objectClass)];
|
||||
}
|
||||
|
||||
- (NSDictionary*)objectMappingsByKeyPath {
|
||||
return _objectMappingsByKeyPath;
|
||||
- (NSDictionary*)mappingsByKeyPath {
|
||||
return _mappingsByKeyPath;
|
||||
}
|
||||
|
||||
- (void)registerMapping:(RKObjectMapping*)objectMapping withRootKeyPath:(NSString*)keyPath {
|
||||
// TODO: Should generate logs
|
||||
objectMapping.rootKeyPath = keyPath;
|
||||
[self setObjectMapping:objectMapping forKeyPath:keyPath];
|
||||
[self setMapping:objectMapping forKeyPath:keyPath];
|
||||
RKObjectMapping* inverseMapping = [objectMapping inverseMapping];
|
||||
inverseMapping.rootKeyPath = keyPath;
|
||||
[self setSerializationMapping:inverseMapping forClass:objectMapping.objectClass];
|
||||
@@ -65,7 +61,7 @@
|
||||
|
||||
- (NSArray*)objectMappingsForClass:(Class)theClass {
|
||||
NSMutableArray* mappings = [NSMutableArray array];
|
||||
NSArray* mappingsToSearch = [[NSArray arrayWithArray:_objectMappings] arrayByAddingObjectsFromArray:[_objectMappingsByKeyPath allValues]];
|
||||
NSArray* mappingsToSearch = [[NSArray arrayWithArray:_objectMappings] arrayByAddingObjectsFromArray:[_mappingsByKeyPath allValues]];
|
||||
for (RKObjectMapping* objectMapping in mappingsToSearch) {
|
||||
if (objectMapping.objectClass == theClass && ![mappings containsObject:objectMapping]) {
|
||||
[mappings addObject:objectMapping];
|
||||
@@ -80,4 +76,18 @@
|
||||
return ([objectMappings count] > 0) ? [objectMappings objectAtIndex:0] : nil;
|
||||
}
|
||||
|
||||
#pragma mark - Deprecated
|
||||
|
||||
- (RKObjectMapping*)objectMappingForKeyPath:(NSString*)keyPath {
|
||||
return (RKObjectMapping*) [self mappingForKeyPath:keyPath];
|
||||
}
|
||||
|
||||
- (void)setObjectMapping:(RKObjectMapping*)mapping forKeyPath:(NSString*)keyPath {
|
||||
[self setMapping:mapping forKeyPath:keyPath];
|
||||
}
|
||||
|
||||
- (NSDictionary*)objectMappingsByKeyPath {
|
||||
return [self mappingsByKeyPath];
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
100
Code/ObjectMapping/RKObjectPolymorphicMapping.h
Normal file
100
Code/ObjectMapping/RKObjectPolymorphicMapping.h
Normal file
@@ -0,0 +1,100 @@
|
||||
//
|
||||
// RKDynamicObjectMapping.h
|
||||
// RestKit
|
||||
//
|
||||
// Created by Blake Watters on 7/28/11.
|
||||
// Copyright 2011 Two Toasters. All rights reserved.
|
||||
//
|
||||
|
||||
#import "RKObjectAbstractMapping.h"
|
||||
#import "RKObjectMapping.h"
|
||||
|
||||
/**
|
||||
Return the appropriate object mapping given a mappable data
|
||||
*/
|
||||
@protocol RKObjectPolymorphicMappingDelegate <NSObject>
|
||||
|
||||
@required
|
||||
- (RKObjectMapping*)objectMappingForData:(id)data;
|
||||
|
||||
@end
|
||||
|
||||
#ifdef NS_BLOCKS_AVAILABLE
|
||||
typedef RKObjectMapping*(^RKObjectPolymorphicMappingDelegateBlock)(id);
|
||||
#endif
|
||||
|
||||
/**
|
||||
Defines a polymorphic object mapping that determines the appropriate concrete
|
||||
object mapping to apply at mapping time. This allows you to map very similar payloads
|
||||
differently depending on the type of data contained therein.
|
||||
*/
|
||||
@interface RKObjectPolymorphicMapping : RKObjectAbstractMapping {
|
||||
NSMutableArray* _matchers;
|
||||
id<RKObjectPolymorphicMappingDelegate> _delegate;
|
||||
#ifdef NS_BLOCKS_AVAILABLE
|
||||
RKObjectPolymorphicMappingDelegateBlock _delegateBlock;
|
||||
#endif
|
||||
BOOL _forceCollectionMapping;
|
||||
}
|
||||
|
||||
/**
|
||||
A delegate to call back to determine the appropriate concrete object mapping
|
||||
to apply to the mappable data.
|
||||
|
||||
@see RKDynamicObjectMappingDelegate
|
||||
*/
|
||||
@property (nonatomic, assign) id<RKObjectPolymorphicMappingDelegate> delegate;
|
||||
|
||||
#ifdef NS_BLOCKS_AVAILABLE
|
||||
/**
|
||||
A block to invoke to determine the appropriate concrete object mapping
|
||||
to apply to the mappable data.
|
||||
*/
|
||||
@property (nonatomic, copy) RKObjectPolymorphicMappingDelegateBlock delegateBlock;
|
||||
#endif
|
||||
|
||||
/**
|
||||
When YES, an NSDictionary encountered by RKObjectMapper will be treated as a collection
|
||||
rather than as a single mappable entity. This is used to perform sub-keypath mapping wherein
|
||||
the keys of the dictionary are part of the mappable data.
|
||||
*/
|
||||
@property (nonatomic, assign) BOOL forceCollectionMapping;
|
||||
|
||||
/**
|
||||
Return a new auto-released polymorphic object mapping
|
||||
*/
|
||||
+ (RKObjectPolymorphicMapping*)polymorphicMapping;
|
||||
|
||||
#if NS_BLOCKS_AVAILABLE
|
||||
|
||||
/**
|
||||
Return a new auto-released polymorphic object mapping after yielding it to the block for configuration
|
||||
*/
|
||||
+ (RKObjectPolymorphicMapping*)polymorphicMappingWithBlock:(void(^)(RKObjectPolymorphicMapping*))block;
|
||||
|
||||
#endif
|
||||
|
||||
//+ (id)mappingForClass:(Class)objectClass block:(void(^)(RKObjectMapping*))block {
|
||||
// TODO: polymorphicMappingWithBlock
|
||||
|
||||
/**
|
||||
Defines a polymorphic mapping rule stating that when the value of the key property matches the specified
|
||||
value, the objectMapping should be used.
|
||||
|
||||
For example, suppose that we have a JSON fragment for a person that we want to map differently based on
|
||||
the gender of the person. When the gender is 'male', we want to use the Boy class and when then the gender
|
||||
is 'female' we want to use the Girl class. We might define our polymorphic mapping like so:
|
||||
|
||||
RKObjectPolymorphicMapping* mapping = [RKObjectPolymorphicMapping polymorphicMapping];
|
||||
[mapping setObjectMapping:boyMapping whenValueOfKey:@"gender" isEqualTo:@"male"];
|
||||
[mapping setObjectMapping:boyMapping whenValueOfKey:@"gender" isEqualTo:@"female"];
|
||||
*/
|
||||
- (void)setObjectMapping:(RKObjectMapping*)objectMapping whenValueOfKey:(NSString*)key isEqualTo:(id)value;
|
||||
|
||||
/**
|
||||
Invoked by the RKObjectMapper and RKObjectMappingOperation to determine the appropriate RKObjectMapping to use
|
||||
when mapping the specified dictionary of mappable data.
|
||||
*/
|
||||
- (RKObjectMapping*)objectMappingForDictionary:(NSDictionary*)dictionary;
|
||||
|
||||
@end
|
||||
140
Code/ObjectMapping/RKObjectPolymorphicMapping.m
Normal file
140
Code/ObjectMapping/RKObjectPolymorphicMapping.m
Normal file
@@ -0,0 +1,140 @@
|
||||
//
|
||||
// RKDynamicObjectMapping.m
|
||||
// RestKit
|
||||
//
|
||||
// Created by Blake Watters on 7/28/11.
|
||||
// Copyright 2011 Two Toasters. All rights reserved.
|
||||
//
|
||||
|
||||
#import "RKObjectPolymorphicMapping.h"
|
||||
#import "../Support/RKLog.h"
|
||||
|
||||
// Set Logging Component
|
||||
#undef RKLogComponent
|
||||
#define RKLogComponent lcl_cRestKitObjectMapping
|
||||
|
||||
// Implemented in RKObjectMappingOperation
|
||||
BOOL RKObjectIsValueEqualToValue(id sourceValue, id destinationValue);
|
||||
|
||||
@interface RKObjectPolymorphicMappingMatcher : NSObject {
|
||||
NSString* _key;
|
||||
id _value;
|
||||
RKObjectMapping* _objectMapping;
|
||||
}
|
||||
|
||||
@property (nonatomic, readonly) RKObjectMapping* objectMapping;
|
||||
|
||||
- (id)initWithKey:(NSString*)key value:(id)value objectMapping:(RKObjectMapping*)objectMapping;
|
||||
- (BOOL)isMatchForData:(id)data;
|
||||
- (NSString*)matchDescription;
|
||||
@end
|
||||
|
||||
@implementation RKObjectPolymorphicMappingMatcher
|
||||
|
||||
@synthesize objectMapping = _objectMapping;
|
||||
|
||||
- (id)initWithKey:(NSString*)key value:(id)value objectMapping:(RKObjectMapping*)objectMapping {
|
||||
self = [super init];
|
||||
if (self) {
|
||||
_key = [key retain];
|
||||
_value = [value retain];
|
||||
_objectMapping = [objectMapping retain];
|
||||
}
|
||||
|
||||
return self;
|
||||
}
|
||||
|
||||
- (void)dealloc {
|
||||
[_key release];
|
||||
[_value release];
|
||||
[_objectMapping release];
|
||||
[super dealloc];
|
||||
}
|
||||
|
||||
- (BOOL)isMatchForData:(id)data {
|
||||
return RKObjectIsValueEqualToValue([data valueForKey:_key], _value);
|
||||
}
|
||||
|
||||
- (NSString*)matchDescription {
|
||||
return [NSString stringWithFormat:@"%@ == %@", _key, _value];
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
@implementation RKObjectPolymorphicMapping
|
||||
|
||||
@synthesize delegate = _delegate;
|
||||
@synthesize delegateBlock = _delegateBlock;
|
||||
@synthesize forceCollectionMapping = _forceCollectionMapping;
|
||||
|
||||
+ (RKObjectPolymorphicMapping*)polymorphicMapping {
|
||||
return [[self new] autorelease];
|
||||
}
|
||||
|
||||
#if NS_BLOCKS_AVAILABLE
|
||||
|
||||
+ (RKObjectPolymorphicMapping*)polymorphicMappingWithBlock:(void(^)(RKObjectPolymorphicMapping*))block {
|
||||
RKObjectPolymorphicMapping* mapping = [self polymorphicMapping];
|
||||
block(mapping);
|
||||
return mapping;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
- (id)init {
|
||||
self = [super init];
|
||||
if (self) {
|
||||
_matchers = [NSMutableArray new];
|
||||
}
|
||||
|
||||
return self;
|
||||
}
|
||||
|
||||
- (void)dealloc {
|
||||
[_matchers release];
|
||||
[super dealloc];
|
||||
}
|
||||
|
||||
- (void)setObjectMapping:(RKObjectMapping*)objectMapping whenValueOfKey:(NSString*)key isEqualTo:(id)value {
|
||||
RKLogDebug(@"Adding dynamic object mapping for key '%@' with value '%@' to destination class: %@", key, value, NSStringFromClass(objectMapping.objectClass));
|
||||
RKObjectPolymorphicMappingMatcher* matcher = [[RKObjectPolymorphicMappingMatcher alloc] initWithKey:key value:value objectMapping:objectMapping];
|
||||
[_matchers addObject:matcher];
|
||||
[matcher release];
|
||||
}
|
||||
|
||||
- (RKObjectMapping*)objectMappingForDictionary:(NSDictionary*)data {
|
||||
NSAssert([data isKindOfClass:[NSDictionary class]], @"Dynamic object mapping can only be performed on NSDictionary mappables, got %@", NSStringFromClass([data class]));
|
||||
RKObjectMapping* mapping = nil;
|
||||
|
||||
RKLogTrace(@"Performing dynamic object mapping for mappable data: %@", data);
|
||||
|
||||
// Consult the declarative matchers first
|
||||
for (RKObjectPolymorphicMappingMatcher* matcher in _matchers) {
|
||||
if ([matcher isMatchForData:data]) {
|
||||
RKLogTrace(@"Found declarative match for data: %@.", [matcher matchDescription]);
|
||||
return matcher.objectMapping;
|
||||
}
|
||||
}
|
||||
|
||||
// Otherwise consult the delegates
|
||||
if (self.delegate) {
|
||||
mapping = [self.delegate objectMappingForData:data];
|
||||
if (mapping) {
|
||||
RKLogTrace(@"Found dynamic delegate match. Delegate = %@", self.delegate);
|
||||
return mapping;
|
||||
}
|
||||
}
|
||||
|
||||
if (self.delegateBlock) {
|
||||
mapping = self.delegateBlock(data);
|
||||
if (mapping) {
|
||||
RKLogTrace(@"Found dynamic delegateBlock match. DelegateBlock = %@", self.delegateBlock);
|
||||
}
|
||||
}
|
||||
|
||||
return mapping;
|
||||
}
|
||||
|
||||
@end
|
||||
@@ -9,18 +9,18 @@
|
||||
#import <Foundation/Foundation.h>
|
||||
#import "RKObjectAttributeMapping.h"
|
||||
|
||||
@class RKObjectMapping;
|
||||
@class RKObjectAbstractMapping;
|
||||
|
||||
@interface RKObjectRelationshipMapping : RKObjectAttributeMapping {
|
||||
RKObjectMapping* _objectMapping;
|
||||
RKObjectAbstractMapping* _mapping;
|
||||
BOOL _reversible;
|
||||
}
|
||||
|
||||
@property (nonatomic, retain) RKObjectMapping* objectMapping;
|
||||
@property (nonatomic, retain) RKObjectAbstractMapping* mapping;
|
||||
@property (nonatomic, assign) BOOL reversible;
|
||||
|
||||
+ (RKObjectRelationshipMapping*) mappingFromKeyPath:(NSString*)sourceKeyPath toKeyPath:(NSString*)destinationKeyPath objectMapping:(RKObjectMapping*)objectMapping;
|
||||
+ (RKObjectRelationshipMapping*)mappingFromKeyPath:(NSString*)sourceKeyPath toKeyPath:(NSString*)destinationKeyPath withMapping:(RKObjectAbstractMapping*)objectOrPolymorphicMapping;
|
||||
|
||||
+ (RKObjectRelationshipMapping*) mappingFromKeyPath:(NSString*)sourceKeyPath toKeyPath:(NSString*)destinationKeyPath objectMapping:(RKObjectMapping*)objectMapping reversible:(BOOL)reversible;
|
||||
+ (RKObjectRelationshipMapping*)mappingFromKeyPath:(NSString*)sourceKeyPath toKeyPath:(NSString*)destinationKeyPath withMapping:(RKObjectAbstractMapping*)objectOrPolymorphicMapping reversible:(BOOL)reversible;
|
||||
|
||||
@end
|
||||
|
||||
@@ -10,30 +10,29 @@
|
||||
|
||||
@implementation RKObjectRelationshipMapping
|
||||
|
||||
@synthesize objectMapping = _objectMapping;
|
||||
@synthesize mapping = _mapping;
|
||||
@synthesize reversible = _reversible;
|
||||
|
||||
+ (RKObjectRelationshipMapping*) mappingFromKeyPath:(NSString*)sourceKeyPath toKeyPath:(NSString*)destinationKeyPath objectMapping:(RKObjectMapping*)objectMapping reversible:(BOOL)reversible {
|
||||
RKObjectRelationshipMapping* mapping = (RKObjectRelationshipMapping*) [self mappingFromKeyPath:sourceKeyPath toKeyPath:destinationKeyPath];
|
||||
mapping.objectMapping = objectMapping;
|
||||
mapping.reversible = reversible;
|
||||
return mapping;
|
||||
+ (RKObjectRelationshipMapping*)mappingFromKeyPath:(NSString*)sourceKeyPath toKeyPath:(NSString*)destinationKeyPath withMapping:(RKObjectAbstractMapping*)objectOrPolymorphicMapping reversible:(BOOL)reversible {
|
||||
RKObjectRelationshipMapping* relationshipMapping = (RKObjectRelationshipMapping*) [self mappingFromKeyPath:sourceKeyPath toKeyPath:destinationKeyPath];
|
||||
relationshipMapping.reversible = reversible;
|
||||
relationshipMapping.mapping = objectOrPolymorphicMapping;
|
||||
return relationshipMapping;
|
||||
}
|
||||
|
||||
+ (RKObjectRelationshipMapping*) mappingFromKeyPath:(NSString*)sourceKeyPath toKeyPath:(NSString*)destinationKeyPath objectMapping:(RKObjectMapping*)objectMapping {
|
||||
RKObjectRelationshipMapping* mapping = [self mappingFromKeyPath:sourceKeyPath toKeyPath:destinationKeyPath objectMapping:objectMapping reversible:YES];
|
||||
return mapping;
|
||||
+ (RKObjectRelationshipMapping*)mappingFromKeyPath:(NSString*)sourceKeyPath toKeyPath:(NSString*)destinationKeyPath withMapping:(RKObjectAbstractMapping*)objectOrPolymorphicMapping {
|
||||
return [self mappingFromKeyPath:sourceKeyPath toKeyPath:destinationKeyPath withMapping:objectOrPolymorphicMapping reversible:YES];
|
||||
}
|
||||
|
||||
- (id)copyWithZone:(NSZone *)zone {
|
||||
RKObjectRelationshipMapping* copy = [super copyWithZone:zone];
|
||||
copy.objectMapping = self.objectMapping;
|
||||
copy.mapping = self.mapping;
|
||||
copy.reversible = self.reversible;
|
||||
return copy;
|
||||
}
|
||||
|
||||
- (void)dealloc {
|
||||
[_objectMapping release];
|
||||
[_mapping release];
|
||||
[super dealloc];
|
||||
}
|
||||
|
||||
|
||||
@@ -16,7 +16,7 @@
|
||||
transformed object is then enclosed in an RKRequestSerializable representation
|
||||
that is suitable for inclusion in an RKRequest.
|
||||
*/
|
||||
@interface RKObjectSerializer : NSObject <RKObjectMappingOperationDelegate, RKObjectFactory> {
|
||||
@interface RKObjectSerializer : NSObject <RKObjectMappingOperationDelegate> {
|
||||
id _object;
|
||||
RKObjectMapping* _mapping;
|
||||
}
|
||||
|
||||
@@ -46,9 +46,8 @@
|
||||
// Return it serialized into a dictionary
|
||||
- (id)serializedObject:(NSError**)error {
|
||||
NSMutableDictionary* dictionary = [NSMutableDictionary dictionary];
|
||||
RKObjectMappingOperation* operation = [RKObjectMappingOperation mappingOperationFromObject:_object toObject:dictionary withObjectMapping:_mapping];
|
||||
RKObjectMappingOperation* operation = [RKObjectMappingOperation mappingOperationFromObject:_object toObject:dictionary withMapping:_mapping];
|
||||
operation.delegate = self;
|
||||
operation.objectFactory = self;
|
||||
BOOL success = [operation performMapping:error];
|
||||
if (!success) {
|
||||
return nil;
|
||||
@@ -113,11 +112,4 @@
|
||||
}
|
||||
}
|
||||
|
||||
#pragma mark - RKObjectFactory
|
||||
|
||||
// We always serialize back to a dictionary
|
||||
- (id)objectWithMapping:(RKObjectMapping*)objectMapping andData:(id)mappableData {
|
||||
return [NSMutableDictionary dictionary];
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
Reference in New Issue
Block a user