Skip to content

Commit ec21b6d

Browse files
committed
Allow multiple instance providers
Performance improvement
1 parent a3cbf8b commit ec21b6d

File tree

11 files changed

+138
-22
lines changed

11 files changed

+138
-22
lines changed
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
<?xml version="1.0" encoding="UTF-8"?>
2+
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
3+
<plist version="1.0">
4+
<dict>
5+
<key>classNames</key>
6+
<dict>
7+
<key>ObjectMapperTests</key>
8+
<dict>
9+
<key>testPerformance</key>
10+
<dict>
11+
<key>com.apple.XCTPerformanceMetric_WallClockTime</key>
12+
<dict>
13+
<key>baselineAverage</key>
14+
<real>0.01</real>
15+
<key>baselineIntegrationDisplayName</key>
16+
<string>Local Baseline</string>
17+
</dict>
18+
</dict>
19+
</dict>
20+
</dict>
21+
</dict>
22+
</plist>

OCMapper.xcodeproj/xcshareddata/xcbaselines/15B554CB171B7B3C0058E159.xcbaseline/Info.plist

+31
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,37 @@
3535
<string>com.apple.platform.iphonesimulator</string>
3636
</dict>
3737
</dict>
38+
<key>BC3A5B12-DE29-448A-856D-62B5380399B4</key>
39+
<dict>
40+
<key>localComputer</key>
41+
<dict>
42+
<key>busSpeedInMHz</key>
43+
<integer>100</integer>
44+
<key>cpuCount</key>
45+
<integer>1</integer>
46+
<key>cpuKind</key>
47+
<string>Intel Core i7</string>
48+
<key>cpuSpeedInMHz</key>
49+
<integer>2200</integer>
50+
<key>logicalCPUCoresPerPackage</key>
51+
<integer>8</integer>
52+
<key>modelCode</key>
53+
<string>MacBookPro11,2</string>
54+
<key>physicalCPUCoresPerPackage</key>
55+
<integer>4</integer>
56+
<key>platformIdentifier</key>
57+
<string>com.apple.platform.macosx</string>
58+
</dict>
59+
<key>targetArchitecture</key>
60+
<string>x86_64</string>
61+
<key>targetDevice</key>
62+
<dict>
63+
<key>modelCode</key>
64+
<string>iPhone7,2</string>
65+
<key>platformIdentifier</key>
66+
<string>com.apple.platform.iphonesimulator</string>
67+
</dict>
68+
</dict>
3869
</dict>
3970
</dict>
4071
</plist>

OCMapper/Sample/Service Layer/OCMapperConfig.m

-2
Original file line numberDiff line numberDiff line change
@@ -18,11 +18,9 @@ @implementation OCMapperConfig
1818

1919
+ (void)configure
2020
{
21-
ObjectInstanceProvider *instanceProvider = [[ObjectInstanceProvider alloc] init];
2221
InCodeMappingProvider *inCodeMappingProvider = [[InCodeMappingProvider alloc] init];
2322
CommonLoggingProvider *commonLoggingProvider = [[CommonLoggingProvider alloc] initWithLogLevel:LogLevelInfo];
2423

25-
[[ObjectMapper sharedInstance] setInstanceProvider:instanceProvider];
2624
[[ObjectMapper sharedInstance] setMappingProvider:inCodeMappingProvider];
2725
[[ObjectMapper sharedInstance] setLoggingProvider:commonLoggingProvider];
2826

OCMapper/Source/Instance Provider/InstanceProvider.h

+1
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,7 @@
2929

3030
@protocol InstanceProvider <NSObject>
3131

32+
- (BOOL)canHandleClass:(Class)class;
3233
- (id)emptyInstanceForClass:(Class)class;
3334
- (id)emptyCollectionInstance;
3435
- (id)upsertObject:(NSObject *)object error:(NSError **)error;

OCMapper/Source/Instance Provider/ManagedObjectInstanceProvider.m

+5
Original file line numberDiff line numberDiff line change
@@ -63,6 +63,11 @@ - (id)init
6363

6464
#pragma mark - Public Methods -
6565

66+
- (BOOL)canHandleClass:(Class)class
67+
{
68+
return ([class isSubclassOfClass:NSManagedObject.class]) ? YES : NO;
69+
}
70+
6671
- (void)setUniqueKeys:(NSArray *)keys forClass:(Class)class withUpsertMode:(UpsertMode)upsertMode
6772
{
6873
for (id key in keys)

OCMapper/Source/Instance Provider/ObjectInstanceProvider.m

+10
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,16 @@ - (id)init
4747

4848
#pragma mark - InstanceProvider Methods -
4949

50+
- (BOOL)canHandleClass:(Class)class
51+
{
52+
static Class managedObjectClass = nil;
53+
54+
if (!managedObjectClass)
55+
managedObjectClass = NSClassFromString(@"NSManagedObject");
56+
57+
return ([class isSubclassOfClass:managedObjectClass]) ? NO : YES;
58+
}
59+
5060
- (id)emptyInstanceForClass:(Class)class
5161
{
5262
return [[class alloc] init];

OCMapper/Source/ObjectMapper.h

+4-6
Original file line numberDiff line numberDiff line change
@@ -26,21 +26,19 @@
2626
// THE SOFTWARE.
2727

2828
#import <Foundation/Foundation.h>
29-
#import <objc/runtime.h>
30-
#import "ObjectMappingInfo.h"
31-
#import "InstanceProvider.h"
32-
#import "MappingProvider.h"
33-
#import "LoggingProvider.h"
29+
30+
@protocol MappingProvider, LoggingProvider, InstanceProvider;
3431

3532
@interface ObjectMapper : NSObject
3633

3734
@property (nonatomic, strong) NSDateFormatter *defaultDateFormatter;
38-
@property (nonatomic, strong) id <InstanceProvider> instanceProvider;
3935
@property (nonatomic, strong) id <MappingProvider> mappingProvider;
4036
@property (nonatomic, strong) id <LoggingProvider> loggingProvider;
37+
@property (nonatomic, assign) BOOL normalizeDictionary;
4138

4239
+ (ObjectMapper *)sharedInstance;
4340
- (id)objectFromSource:(id)source toInstanceOfClass:(Class)class;
4441
- (id)dictionaryFromObject:(NSObject *)object;
42+
- (void)addInstanceProvider:(id <InstanceProvider>)instanceProvider;
4543

4644
@end

OCMapper/Source/ObjectMapper.m

+35-9
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,12 @@
2626
// THE SOFTWARE.
2727

2828
#import "ObjectMapper.h"
29+
#import <objc/runtime.h>
30+
#import "ObjectMappingInfo.h"
31+
#import "InstanceProvider.h"
32+
#import "MappingProvider.h"
33+
#import "LoggingProvider.h"
34+
#import "ObjectInstanceProvider.h"
2935

3036
#ifdef DEBUG
3137
#define ILog(format, ...) [self.loggingProvider log:[NSString stringWithFormat:(format), ##__VA_ARGS__] withLevel:LogLevelInfo]
@@ -42,6 +48,7 @@ @interface ObjectMapper()
4248
@property (nonatomic, strong) NSMutableArray *classNamesInMainBundle;
4349
@property (nonatomic, strong) NSMutableDictionary *mappedClassNames;
4450
@property (nonatomic, strong) NSMutableDictionary *mappedPropertyNames;
51+
@property (nonatomic, strong) NSMutableArray *instanceProviders;
4552
@end
4653

4754
@implementation ObjectMapper
@@ -66,6 +73,10 @@ - (id)init
6673
{
6774
[self populateClassNamesFromMainBundle];
6875

76+
self.instanceProviders = [NSMutableArray array];
77+
ObjectInstanceProvider *objectInstanceProvider = [[ObjectInstanceProvider alloc] init];
78+
[self addInstanceProvider:objectInstanceProvider];
79+
6980
self.mappedClassNames = [NSMutableDictionary dictionary];
7081
self.mappedPropertyNames = [NSMutableDictionary dictionary];
7182
}
@@ -80,9 +91,6 @@ - (id)objectFromSource:(id)source toInstanceOfClass:(Class)class
8091
if (!_mappingProvider)
8192
@throw ([NSException exceptionWithName:@"MissingMappingProvider" reason:@"Mapping provider is not set" userInfo:nil]);
8293

83-
if (!_instanceProvider)
84-
@throw ([NSException exceptionWithName:@"MissingInstanceProvider" reason:@"Instance provider is not set" userInfo:nil]);
85-
8694
if ([source isKindOfClass:[NSDictionary class]])
8795
{
8896
ILog(@"____________________ Mapping Dictionary to instance [%@] ____________________", NSStringFromClass(class));
@@ -112,6 +120,11 @@ - (id)dictionaryFromObject:(NSObject *)object
112120
}
113121
}
114122

123+
- (void)addInstanceProvider:(id <InstanceProvider>)instanceProvider
124+
{
125+
[self.instanceProviders addObject:instanceProvider];
126+
}
127+
115128
#pragma mark - Private Methods -
116129

117130
- (void)populateClassNamesFromMainBundle
@@ -259,9 +272,10 @@ - (NSDictionary *)normalizedDictionaryFromDictionary:(NSDictionary *)source forC
259272

260273
- (id)processDictionary:(NSDictionary *)source forClass:(Class)class
261274
{
262-
NSDictionary *normalizedSource = [self normalizedDictionaryFromDictionary:source forClass:class];
275+
NSDictionary *normalizedSource = (self.normalizeDictionary) ? [self normalizedDictionaryFromDictionary:source forClass:class] : source;
263276

264-
id object = [self.instanceProvider emptyInstanceForClass:class];
277+
id <InstanceProvider> instanceProvider = [self instanceProviderForClass:class];
278+
id object = [instanceProvider emptyInstanceForClass:class];
265279

266280
for (NSString *key in normalizedSource)
267281
{
@@ -276,13 +290,13 @@ - (id)processDictionary:(NSDictionary *)source forClass:(Class)class
276290

277291
if (mappingInfo)
278292
{
279-
propertyName = [self.instanceProvider propertyNameForObject:object byCaseInsensitivePropertyName:mappingInfo.propertyKey];
293+
propertyName = [instanceProvider propertyNameForObject:object byCaseInsensitivePropertyName:mappingInfo.propertyKey];
280294
objectType = mappingInfo.objectType;
281295
mappingTransformer = mappingInfo.transformer;
282296
}
283297
else
284298
{
285-
propertyName = [self.instanceProvider propertyNameForObject:object byCaseInsensitivePropertyName:key];
299+
propertyName = [instanceProvider propertyNameForObject:object byCaseInsensitivePropertyName:key];
286300

287301
if (propertyName && ([value isKindOfClass:[NSDictionary class]] || [value isKindOfClass:[NSArray class]]))
288302
{
@@ -350,7 +364,7 @@ - (id)processDictionary:(NSDictionary *)source forClass:(Class)class
350364
}
351365

352366
NSError *error;
353-
object = [self.instanceProvider upsertObject:object error:&error];
367+
object = [instanceProvider upsertObject:object error:&error];
354368

355369
if (error)
356370
ELog(@"Attempt to update existing instance failed with error '%@' for class (%@) and object %@",
@@ -361,9 +375,21 @@ - (id)processDictionary:(NSDictionary *)source forClass:(Class)class
361375
return object;
362376
}
363377

378+
- (id <InstanceProvider>)instanceProviderForClass:(Class)class
379+
{
380+
for (id<InstanceProvider> instanceProvider in self.instanceProviders)
381+
{
382+
if ([instanceProvider canHandleClass:class])
383+
return instanceProvider;
384+
}
385+
386+
return nil;
387+
}
388+
364389
- (id)processArray:(NSArray *)value forClass:(Class)class
365390
{
366-
id collection = [self.instanceProvider emptyCollectionInstance];
391+
id <InstanceProvider> instanceProvider = [self instanceProviderForClass:class];
392+
id collection = [instanceProvider emptyCollectionInstance];
367393

368394
for (id objectInArray in value)
369395
{

OCMapperTests/ManagedObjectMapperTest.m

+12-1
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@
2626
// THE SOFTWARE.
2727

2828
#import "ManagedObjectMapperTest.h"
29+
#import "User.h"
2930
#import "CDUser.h"
3031
#import "CDAddress.h"
3132
#import "CDPost.h"
@@ -47,7 +48,7 @@ - (void)setUp
4748

4849
self.mapper = [[ObjectMapper alloc] init];
4950
self.mapper.mappingProvider = self.mappingProvider;
50-
self.mapper.instanceProvider = self.instanceProvider;
51+
[self.mapper addInstanceProvider:self.instanceProvider];
5152
}
5253

5354
- (void)tearDown
@@ -404,4 +405,14 @@ - (void)testNumberOfCreatedManagedObjectsOnNonUpdateForUpsertModePurgeExisting
404405
XCTAssertTrue(addresses.count == 2, @"Did Not update existing ManagedObject");
405406
}
406407

408+
- (void)testManagedObjectInstanceProviderShouldReturnFalseForNSObjectSubclasses
409+
{
410+
XCTAssertFalse([self.instanceProvider canHandleClass:User.class]);
411+
}
412+
413+
- (void)testManagedObjectInstanceProviderShouldReturnTrueForNSManagedObjectSubclasses
414+
{
415+
XCTAssertTrue([self.instanceProvider canHandleClass:CDUser.class]);
416+
}
417+
407418
@end

OCMapperTests/ObjectMapperTests.m

+18-4
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@
2828
#import "ObjectMapperTests.h"
2929
#import "ObjectMapper.h"
3030
#import "User.h"
31+
#import "CDUser.h"
3132
#import "Comment.h"
3233
#import "SpecialUser.h"
3334

@@ -47,7 +48,6 @@ - (void)setUp
4748

4849
self.mapper = [[ObjectMapper alloc] init];
4950
self.mapper.mappingProvider = self.mappingProvider;
50-
self.mapper.instanceProvider = self.instanceProvider;
5151
}
5252

5353
- (void)tearDown
@@ -361,6 +361,7 @@ - (void)testFlatDataToComplexObjectConversion
361361

362362
[self.mappingProvider mapFromDictionaryKey:@"city" toPropertyKey:@"address.city" forClass:[User class]];
363363
[self.mappingProvider mapFromDictionaryKey:@"country" toPropertyKey:@"address.country" forClass:[User class]];
364+
self.mapper.normalizeDictionary = YES;
364365

365366
User *user = [self.mapper objectFromSource:userDictionary toInstanceOfClass:[User class]];
366367
XCTAssertTrue([[userDictionary objectForKey:@"firstName"] isEqual:user.firstName], @"Did not populate dictionary correctly");
@@ -415,7 +416,8 @@ - (void)testShouldPopulateDictionaryWithPropertyInSuperClass
415416
XCTAssertTrue([user.power isEqual:[dictionary objectForKey:@"power"]], @"Did Not populate dictionary properly");
416417
}
417418

418-
- (void)testInverseMappingShouldMapKeysWithCorrectName {
419+
- (void)testInverseMappingShouldMapKeysWithCorrectName
420+
{
419421
User *user = [[User alloc] init];
420422
user.firstName = @"Aryan";
421423
user.address = [[Address alloc] init];
@@ -435,19 +437,31 @@ - (void)testInverseMappingShouldMapKeysWithCorrectName {
435437
XCTAssertTrue([[dictionary[@"location"] objectForKey:@"ct"] isEqualToString:user.address.city]);
436438
}
437439

438-
- (void)testShouldAutomaticallyGenerateInverseMapping {
440+
- (void)testShouldAutomaticallyGenerateInverseMapping
441+
{
439442
[self.mappingProvider mapFromDictionaryKey:@"dateOfBirth" toPropertyKey:@"dob" forClass:[User class]];
440443
ObjectMappingInfo *info = [self.mappingProvider mappingInfoForClass:[User class] andPropertyKey:@"dob"];
441444

442445
XCTAssertTrue([info.dictionaryKey isEqualToString:@"dateOfBirth"]);
443446
}
444447

445-
- (void)testShouldNotAutomaticallyGenerateInverseMapping {
448+
- (void)testShouldNotAutomaticallyGenerateInverseMapping
449+
{
446450
self.mappingProvider.automaticallyGenerateInverseMapping = NO;
447451
[self.mappingProvider mapFromDictionaryKey:@"dateOfBirth" toPropertyKey:@"dob" forClass:[User class]];
448452
ObjectMappingInfo *info = [self.mappingProvider mappingInfoForClass:[User class] andPropertyKey:@"dob"];
449453

450454
XCTAssertNil(info);
451455
}
452456

457+
- (void)testObjectInstanceProviderShouldReturnTrueForNSObjectSubclasses
458+
{
459+
XCTAssertTrue([self.instanceProvider canHandleClass:User.class]);
460+
}
461+
462+
- (void)testObjectInstanceProviderShouldReturnFalseForNSManagedObjectSubclasses
463+
{
464+
XCTAssertFalse([self.instanceProvider canHandleClass:CDUser.class]);
465+
}
466+
453467
@end

0 commit comments

Comments
 (0)