diff --git a/OCMapper.xcodeproj/project.xcworkspace/xcuserdata/aryaxt.xcuserdatad/UserInterfaceState.xcuserstate b/OCMapper.xcodeproj/project.xcworkspace/xcuserdata/aryaxt.xcuserdatad/UserInterfaceState.xcuserstate index 1d5324c..ea522c1 100644 Binary files a/OCMapper.xcodeproj/project.xcworkspace/xcuserdata/aryaxt.xcuserdatad/UserInterfaceState.xcuserstate and b/OCMapper.xcodeproj/project.xcworkspace/xcuserdata/aryaxt.xcuserdatad/UserInterfaceState.xcuserstate differ diff --git a/OCMapper.xcodeproj/xcshareddata/xcbaselines/15B554CB171B7B3C0058E159.xcbaseline/BC3A5B12-DE29-448A-856D-62B5380399B4.plist b/OCMapper.xcodeproj/xcshareddata/xcbaselines/15B554CB171B7B3C0058E159.xcbaseline/BC3A5B12-DE29-448A-856D-62B5380399B4.plist new file mode 100644 index 0000000..9a8cf0c --- /dev/null +++ b/OCMapper.xcodeproj/xcshareddata/xcbaselines/15B554CB171B7B3C0058E159.xcbaseline/BC3A5B12-DE29-448A-856D-62B5380399B4.plist @@ -0,0 +1,22 @@ + + + + + classNames + + ObjectMapperTests + + testPerformance + + com.apple.XCTPerformanceMetric_WallClockTime + + baselineAverage + 0.01 + baselineIntegrationDisplayName + Local Baseline + + + + + + diff --git a/OCMapper.xcodeproj/xcshareddata/xcbaselines/15B554CB171B7B3C0058E159.xcbaseline/Info.plist b/OCMapper.xcodeproj/xcshareddata/xcbaselines/15B554CB171B7B3C0058E159.xcbaseline/Info.plist index d06cb08..fdc0b96 100644 --- a/OCMapper.xcodeproj/xcshareddata/xcbaselines/15B554CB171B7B3C0058E159.xcbaseline/Info.plist +++ b/OCMapper.xcodeproj/xcshareddata/xcbaselines/15B554CB171B7B3C0058E159.xcbaseline/Info.plist @@ -35,6 +35,37 @@ com.apple.platform.iphonesimulator + BC3A5B12-DE29-448A-856D-62B5380399B4 + + localComputer + + busSpeedInMHz + 100 + cpuCount + 1 + cpuKind + Intel Core i7 + cpuSpeedInMHz + 2200 + logicalCPUCoresPerPackage + 8 + modelCode + MacBookPro11,2 + physicalCPUCoresPerPackage + 4 + platformIdentifier + com.apple.platform.macosx + + targetArchitecture + x86_64 + targetDevice + + modelCode + iPhone7,2 + platformIdentifier + com.apple.platform.iphonesimulator + + diff --git a/OCMapper/Sample/Service Layer/OCMapperConfig.m b/OCMapper/Sample/Service Layer/OCMapperConfig.m index bbe35f1..3abc769 100644 --- a/OCMapper/Sample/Service Layer/OCMapperConfig.m +++ b/OCMapper/Sample/Service Layer/OCMapperConfig.m @@ -18,11 +18,9 @@ @implementation OCMapperConfig + (void)configure { - ObjectInstanceProvider *instanceProvider = [[ObjectInstanceProvider alloc] init]; InCodeMappingProvider *inCodeMappingProvider = [[InCodeMappingProvider alloc] init]; CommonLoggingProvider *commonLoggingProvider = [[CommonLoggingProvider alloc] initWithLogLevel:LogLevelInfo]; - [[ObjectMapper sharedInstance] setInstanceProvider:instanceProvider]; [[ObjectMapper sharedInstance] setMappingProvider:inCodeMappingProvider]; [[ObjectMapper sharedInstance] setLoggingProvider:commonLoggingProvider]; diff --git a/OCMapper/Source/Instance Provider/InstanceProvider.h b/OCMapper/Source/Instance Provider/InstanceProvider.h index 3abfa17..1b1ba8e 100644 --- a/OCMapper/Source/Instance Provider/InstanceProvider.h +++ b/OCMapper/Source/Instance Provider/InstanceProvider.h @@ -29,6 +29,7 @@ @protocol InstanceProvider +- (BOOL)canHandleClass:(Class)class; - (id)emptyInstanceForClass:(Class)class; - (id)emptyCollectionInstance; - (id)upsertObject:(NSObject *)object error:(NSError **)error; diff --git a/OCMapper/Source/Instance Provider/ManagedObjectInstanceProvider.m b/OCMapper/Source/Instance Provider/ManagedObjectInstanceProvider.m index fe6ea2a..b583647 100644 --- a/OCMapper/Source/Instance Provider/ManagedObjectInstanceProvider.m +++ b/OCMapper/Source/Instance Provider/ManagedObjectInstanceProvider.m @@ -63,6 +63,11 @@ - (id)init #pragma mark - Public Methods - +- (BOOL)canHandleClass:(Class)class +{ + return ([class isSubclassOfClass:NSManagedObject.class]) ? YES : NO; +} + - (void)setUniqueKeys:(NSArray *)keys forClass:(Class)class withUpsertMode:(UpsertMode)upsertMode { for (id key in keys) diff --git a/OCMapper/Source/Instance Provider/ObjectInstanceProvider.m b/OCMapper/Source/Instance Provider/ObjectInstanceProvider.m index 6359327..38510e4 100644 --- a/OCMapper/Source/Instance Provider/ObjectInstanceProvider.m +++ b/OCMapper/Source/Instance Provider/ObjectInstanceProvider.m @@ -47,6 +47,16 @@ - (id)init #pragma mark - InstanceProvider Methods - +- (BOOL)canHandleClass:(Class)class +{ + static Class managedObjectClass = nil; + + if (!managedObjectClass) + managedObjectClass = NSClassFromString(@"NSManagedObject"); + + return ([class isSubclassOfClass:managedObjectClass]) ? NO : YES; +} + - (id)emptyInstanceForClass:(Class)class { return [[class alloc] init]; diff --git a/OCMapper/Source/ObjectMapper.h b/OCMapper/Source/ObjectMapper.h index b9f42bc..98e355e 100644 --- a/OCMapper/Source/ObjectMapper.h +++ b/OCMapper/Source/ObjectMapper.h @@ -26,21 +26,19 @@ // THE SOFTWARE. #import -#import -#import "ObjectMappingInfo.h" -#import "InstanceProvider.h" -#import "MappingProvider.h" -#import "LoggingProvider.h" + +@protocol MappingProvider, LoggingProvider, InstanceProvider; @interface ObjectMapper : NSObject @property (nonatomic, strong) NSDateFormatter *defaultDateFormatter; -@property (nonatomic, strong) id instanceProvider; @property (nonatomic, strong) id mappingProvider; @property (nonatomic, strong) id loggingProvider; +@property (nonatomic, assign) BOOL normalizeDictionary; + (ObjectMapper *)sharedInstance; - (id)objectFromSource:(id)source toInstanceOfClass:(Class)class; - (id)dictionaryFromObject:(NSObject *)object; +- (void)addInstanceProvider:(id )instanceProvider; @end diff --git a/OCMapper/Source/ObjectMapper.m b/OCMapper/Source/ObjectMapper.m index acbe537..0a73c66 100644 --- a/OCMapper/Source/ObjectMapper.m +++ b/OCMapper/Source/ObjectMapper.m @@ -26,6 +26,12 @@ // THE SOFTWARE. #import "ObjectMapper.h" +#import +#import "ObjectMappingInfo.h" +#import "InstanceProvider.h" +#import "MappingProvider.h" +#import "LoggingProvider.h" +#import "ObjectInstanceProvider.h" #ifdef DEBUG #define ILog(format, ...) [self.loggingProvider log:[NSString stringWithFormat:(format), ##__VA_ARGS__] withLevel:LogLevelInfo] @@ -42,6 +48,7 @@ @interface ObjectMapper() @property (nonatomic, strong) NSMutableArray *classNamesInMainBundle; @property (nonatomic, strong) NSMutableDictionary *mappedClassNames; @property (nonatomic, strong) NSMutableDictionary *mappedPropertyNames; +@property (nonatomic, strong) NSMutableArray *instanceProviders; @end @implementation ObjectMapper @@ -66,6 +73,10 @@ - (id)init { [self populateClassNamesFromMainBundle]; + self.instanceProviders = [NSMutableArray array]; + ObjectInstanceProvider *objectInstanceProvider = [[ObjectInstanceProvider alloc] init]; + [self addInstanceProvider:objectInstanceProvider]; + self.mappedClassNames = [NSMutableDictionary dictionary]; self.mappedPropertyNames = [NSMutableDictionary dictionary]; } @@ -80,9 +91,6 @@ - (id)objectFromSource:(id)source toInstanceOfClass:(Class)class if (!_mappingProvider) @throw ([NSException exceptionWithName:@"MissingMappingProvider" reason:@"Mapping provider is not set" userInfo:nil]); - if (!_instanceProvider) - @throw ([NSException exceptionWithName:@"MissingInstanceProvider" reason:@"Instance provider is not set" userInfo:nil]); - if ([source isKindOfClass:[NSDictionary class]]) { ILog(@"____________________ Mapping Dictionary to instance [%@] ____________________", NSStringFromClass(class)); @@ -112,6 +120,11 @@ - (id)dictionaryFromObject:(NSObject *)object } } +- (void)addInstanceProvider:(id )instanceProvider +{ + [self.instanceProviders addObject:instanceProvider]; +} + #pragma mark - Private Methods - - (void)populateClassNamesFromMainBundle @@ -259,9 +272,10 @@ - (NSDictionary *)normalizedDictionaryFromDictionary:(NSDictionary *)source forC - (id)processDictionary:(NSDictionary *)source forClass:(Class)class { - NSDictionary *normalizedSource = [self normalizedDictionaryFromDictionary:source forClass:class]; + NSDictionary *normalizedSource = (self.normalizeDictionary) ? [self normalizedDictionaryFromDictionary:source forClass:class] : source; - id object = [self.instanceProvider emptyInstanceForClass:class]; + id instanceProvider = [self instanceProviderForClass:class]; + id object = [instanceProvider emptyInstanceForClass:class]; for (NSString *key in normalizedSource) { @@ -276,13 +290,13 @@ - (id)processDictionary:(NSDictionary *)source forClass:(Class)class if (mappingInfo) { - propertyName = [self.instanceProvider propertyNameForObject:object byCaseInsensitivePropertyName:mappingInfo.propertyKey]; + propertyName = [instanceProvider propertyNameForObject:object byCaseInsensitivePropertyName:mappingInfo.propertyKey]; objectType = mappingInfo.objectType; mappingTransformer = mappingInfo.transformer; } else { - propertyName = [self.instanceProvider propertyNameForObject:object byCaseInsensitivePropertyName:key]; + propertyName = [instanceProvider propertyNameForObject:object byCaseInsensitivePropertyName:key]; if (propertyName && ([value isKindOfClass:[NSDictionary class]] || [value isKindOfClass:[NSArray class]])) { @@ -350,7 +364,7 @@ - (id)processDictionary:(NSDictionary *)source forClass:(Class)class } NSError *error; - object = [self.instanceProvider upsertObject:object error:&error]; + object = [instanceProvider upsertObject:object error:&error]; if (error) ELog(@"Attempt to update existing instance failed with error '%@' for class (%@) and object %@", @@ -361,9 +375,21 @@ - (id)processDictionary:(NSDictionary *)source forClass:(Class)class return object; } +- (id )instanceProviderForClass:(Class)class +{ + for (id instanceProvider in self.instanceProviders) + { + if ([instanceProvider canHandleClass:class]) + return instanceProvider; + } + + return nil; +} + - (id)processArray:(NSArray *)value forClass:(Class)class { - id collection = [self.instanceProvider emptyCollectionInstance]; + id instanceProvider = [self instanceProviderForClass:class]; + id collection = [instanceProvider emptyCollectionInstance]; for (id objectInArray in value) { diff --git a/OCMapperTests/ManagedObjectMapperTest.m b/OCMapperTests/ManagedObjectMapperTest.m index e4e32a7..ec931df 100644 --- a/OCMapperTests/ManagedObjectMapperTest.m +++ b/OCMapperTests/ManagedObjectMapperTest.m @@ -26,6 +26,7 @@ // THE SOFTWARE. #import "ManagedObjectMapperTest.h" +#import "User.h" #import "CDUser.h" #import "CDAddress.h" #import "CDPost.h" @@ -47,7 +48,7 @@ - (void)setUp self.mapper = [[ObjectMapper alloc] init]; self.mapper.mappingProvider = self.mappingProvider; - self.mapper.instanceProvider = self.instanceProvider; + [self.mapper addInstanceProvider:self.instanceProvider]; } - (void)tearDown @@ -404,4 +405,14 @@ - (void)testNumberOfCreatedManagedObjectsOnNonUpdateForUpsertModePurgeExisting XCTAssertTrue(addresses.count == 2, @"Did Not update existing ManagedObject"); } +- (void)testManagedObjectInstanceProviderShouldReturnFalseForNSObjectSubclasses +{ + XCTAssertFalse([self.instanceProvider canHandleClass:User.class]); +} + +- (void)testManagedObjectInstanceProviderShouldReturnTrueForNSManagedObjectSubclasses +{ + XCTAssertTrue([self.instanceProvider canHandleClass:CDUser.class]); +} + @end diff --git a/OCMapperTests/ObjectMapperTests.m b/OCMapperTests/ObjectMapperTests.m index a30b31d..d229dac 100644 --- a/OCMapperTests/ObjectMapperTests.m +++ b/OCMapperTests/ObjectMapperTests.m @@ -28,6 +28,7 @@ #import "ObjectMapperTests.h" #import "ObjectMapper.h" #import "User.h" +#import "CDUser.h" #import "Comment.h" #import "SpecialUser.h" @@ -47,7 +48,6 @@ - (void)setUp self.mapper = [[ObjectMapper alloc] init]; self.mapper.mappingProvider = self.mappingProvider; - self.mapper.instanceProvider = self.instanceProvider; } - (void)tearDown @@ -361,6 +361,7 @@ - (void)testFlatDataToComplexObjectConversion [self.mappingProvider mapFromDictionaryKey:@"city" toPropertyKey:@"address.city" forClass:[User class]]; [self.mappingProvider mapFromDictionaryKey:@"country" toPropertyKey:@"address.country" forClass:[User class]]; + self.mapper.normalizeDictionary = YES; User *user = [self.mapper objectFromSource:userDictionary toInstanceOfClass:[User class]]; XCTAssertTrue([[userDictionary objectForKey:@"firstName"] isEqual:user.firstName], @"Did not populate dictionary correctly"); @@ -415,7 +416,8 @@ - (void)testShouldPopulateDictionaryWithPropertyInSuperClass XCTAssertTrue([user.power isEqual:[dictionary objectForKey:@"power"]], @"Did Not populate dictionary properly"); } -- (void)testInverseMappingShouldMapKeysWithCorrectName { +- (void)testInverseMappingShouldMapKeysWithCorrectName +{ User *user = [[User alloc] init]; user.firstName = @"Aryan"; user.address = [[Address alloc] init]; @@ -435,14 +437,16 @@ - (void)testInverseMappingShouldMapKeysWithCorrectName { XCTAssertTrue([[dictionary[@"location"] objectForKey:@"ct"] isEqualToString:user.address.city]); } -- (void)testShouldAutomaticallyGenerateInverseMapping { +- (void)testShouldAutomaticallyGenerateInverseMapping +{ [self.mappingProvider mapFromDictionaryKey:@"dateOfBirth" toPropertyKey:@"dob" forClass:[User class]]; ObjectMappingInfo *info = [self.mappingProvider mappingInfoForClass:[User class] andPropertyKey:@"dob"]; XCTAssertTrue([info.dictionaryKey isEqualToString:@"dateOfBirth"]); } -- (void)testShouldNotAutomaticallyGenerateInverseMapping { +- (void)testShouldNotAutomaticallyGenerateInverseMapping +{ self.mappingProvider.automaticallyGenerateInverseMapping = NO; [self.mappingProvider mapFromDictionaryKey:@"dateOfBirth" toPropertyKey:@"dob" forClass:[User class]]; ObjectMappingInfo *info = [self.mappingProvider mappingInfoForClass:[User class] andPropertyKey:@"dob"]; @@ -450,4 +454,14 @@ - (void)testShouldNotAutomaticallyGenerateInverseMapping { XCTAssertNil(info); } +- (void)testObjectInstanceProviderShouldReturnTrueForNSObjectSubclasses +{ + XCTAssertTrue([self.instanceProvider canHandleClass:User.class]); +} + +- (void)testObjectInstanceProviderShouldReturnFalseForNSManagedObjectSubclasses +{ + XCTAssertFalse([self.instanceProvider canHandleClass:CDUser.class]); +} + @end