Skip to content

Commit 90de93d

Browse files
committed
Merge remote-tracking branch 'origin/Core-Data-Purge-And-Update'
* origin/Core-Data-Purge-And-Update: - check for an existing key before trying to find an existing managed object - initial checkin for core data update/purge support
2 parents 87011e6 + f5c156f commit 90de93d

File tree

13 files changed

+425
-33
lines changed

13 files changed

+425
-33
lines changed

OCMapper.xcodeproj/project.pbxproj

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -502,7 +502,7 @@
502502
15B554A2171B7B3B0058E159 /* Project object */ = {
503503
isa = PBXProject;
504504
attributes = {
505-
LastUpgradeCheck = 0450;
505+
LastUpgradeCheck = 0500;
506506
ORGANIZATIONNAME = "Aryan Ghassemi";
507507
};
508508
buildConfigurationList = 15B554A5171B7B3B0058E159 /* Build configuration list for PBXProject "OCMapper" */;
@@ -669,6 +669,7 @@
669669
GCC_WARN_UNINITIALIZED_AUTOS = YES;
670670
GCC_WARN_UNUSED_VARIABLE = YES;
671671
IPHONEOS_DEPLOYMENT_TARGET = 6.0;
672+
ONLY_ACTIVE_ARCH = YES;
672673
SDKROOT = iphoneos;
673674
TARGETED_DEVICE_FAMILY = "1,2";
674675
};

OCMapper/Models/CDUser.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,7 @@
3131

3232
@interface CDUser : NSManagedObject
3333

34+
@property (nonatomic, strong) NSNumber *userId;
3435
@property (nonatomic, strong) NSString *firstName;
3536
@property (nonatomic, strong) NSString *lastName;
3637
@property (nonatomic, strong) NSDate *dateOfBirth;

OCMapper/Models/CDUser.m

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@
2828
#import "CDUser.h"
2929

3030
@implementation CDUser
31+
@dynamic userId;
3132
@dynamic firstName;
3233
@dynamic lastName;
3334
@dynamic age;

OCMapper/Models/Core Data/CDAddress.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,7 @@
2929

3030
@interface CDAddress : NSManagedObject
3131

32+
@property (nonatomic, strong) NSNumber *addressId;
3233
@property (nonatomic, strong) NSString *city;
3334
@property (nonatomic, strong) NSString *country;
3435

OCMapper/Models/Core Data/CDAddress.m

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@
2828
#import "CDAddress.h"
2929

3030
@implementation CDAddress
31+
@dynamic addressId;
3132
@dynamic city;
3233
@dynamic country;
3334

OCMapper/Models/CoreDataManager.m

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -193,7 +193,7 @@ - (NSPersistentStoreCoordinator *)persistentStoreCoordinator
193193

194194
NSError *error = nil;
195195
_persistentStoreCoordinator = [[NSPersistentStoreCoordinator alloc] initWithManagedObjectModel:[self managedObjectModel]];
196-
if (![_persistentStoreCoordinator addPersistentStoreWithType:NSSQLiteStoreType configuration:nil URL:storeURL options:options error:&error])
196+
if (![_persistentStoreCoordinator addPersistentStoreWithType:NSInMemoryStoreType configuration:nil URL:storeURL options:options error:&error])
197197
{
198198
/*
199199
Replace this implementation with code to handle the error appropriately.

OCMapper/Models/OCMapper.xcdatamodeld/OCMapper.xcdatamodel/contents

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
22
<model userDefinedModelVersionIdentifier="" type="com.apple.IDECoreDataModeler.DataModel" documentVersion="1.0" lastSavedToolsVersion="3400" systemVersion="13A603" minimumToolsVersion="Xcode 4.3" macOSVersion="Automatic" iOSVersion="Automatic">
33
<entity name="CDAddress" representedClassName="CDAddress" syncable="YES">
4+
<attribute name="addressId" optional="YES" attributeType="Integer 32" defaultValueString="0" syncable="YES"/>
45
<attribute name="city" optional="YES" attributeType="String" syncable="YES"/>
56
<attribute name="country" optional="YES" attributeType="String" syncable="YES"/>
67
<relationship name="user" optional="YES" minCount="1" maxCount="1" deletionRule="Nullify" destinationEntity="CDUser" inverseName="address" inverseEntity="CDUser" syncable="YES"/>
@@ -18,13 +19,14 @@
1819
<attribute name="dateOfBirth" optional="YES" attributeType="Date" syncable="YES"/>
1920
<attribute name="firstName" optional="YES" attributeType="String" syncable="YES"/>
2021
<attribute name="lastName" optional="YES" attributeType="String" syncable="YES"/>
22+
<attribute name="userId" optional="YES" attributeType="Integer 32" defaultValueString="0" syncable="YES"/>
2123
<relationship name="address" optional="YES" minCount="1" maxCount="1" deletionRule="Nullify" destinationEntity="CDAddress" inverseName="user" inverseEntity="CDAddress" syncable="YES"/>
2224
<relationship name="posts" optional="YES" toMany="YES" deletionRule="Nullify" destinationEntity="CDPost" inverseName="user" inverseEntity="CDPost" syncable="YES"/>
2325
</entity>
2426
<elements>
2527
<element name="CDAddress" positionX="0" positionY="0" width="0" height="0"/>
2628
<element name="CDPost" positionX="0" positionY="0" width="0" height="0"/>
27-
<element name="CDUser" positionX="0" positionY="0" width="0" height="0"/>
2829
<element name="CDSpecialUser" positionX="0" positionY="0" width="0" height="0"/>
30+
<element name="CDUser" positionX="0" positionY="0" width="0" height="0"/>
2931
</elements>
3032
</model>

OCMapper/Source/Instance Provider/InstanceProvider.h

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -29,8 +29,9 @@
2929

3030
@protocol InstanceProvider <NSObject>
3131

32-
- (id)emptyInstanceFromClass:(Class)class;
33-
- (id)emptyInstanceOfCollectionObject;
32+
- (id)emptyInstanceForClass:(Class)class;
33+
- (id)emptyCollectionInstance;
34+
- (id)upsertObject:(NSObject *)object error:(NSError **)error;
3435
- (NSString *)propertyNameForObject:(NSObject *)object byCaseInsensitivePropertyName:(NSString *)caseInsensitivePropertyName;
3536

3637
@end

OCMapper/Source/Instance Provider/ManagedObjectInstanceProvider.h

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -29,10 +29,14 @@
2929
#import <CoreData/CoreData.h>
3030
#import "InstanceProvider.h"
3131

32-
@interface ManagedObjectInstanceProvider : NSObject <InstanceProvider>
32+
typedef enum {
33+
UpsertModeUpdateExistingObject,
34+
UpsertModePurgeExistingObject
35+
}UpsertMode;
3336

34-
@property (nonatomic, strong) NSManagedObjectContext *managedObjectContext;
37+
@interface ManagedObjectInstanceProvider : NSObject <InstanceProvider>
3538

36-
- (id)initWithManagedObjectContext:(NSManagedObjectContext *)managedObjectContext;
39+
- (id)initWithManagedObjectContext:(NSManagedObjectContext *)aManagedObjectContext;
40+
- (void)setUniqueKeys:(NSArray *)keys forClass:(Class)class withUpsertMode:(UpsertMode)upsertMode;
3741

3842
@end

OCMapper/Source/Instance Provider/ManagedObjectInstanceProvider.m

Lines changed: 119 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -27,8 +27,19 @@
2727

2828
#import "ManagedObjectInstanceProvider.h"
2929

30+
@interface UpsertInfo : NSObject
31+
@property (nonatomic, strong) NSArray *keys;
32+
@property (nonatomic, assign) UpsertMode upsertMode;
33+
@end
34+
@implementation UpsertInfo
35+
@end
36+
37+
@interface ManagedObjectInstanceProvider()
38+
@property (nonatomic, strong) NSManagedObjectContext *managedObjectContext;
39+
@property (nonatomic, strong) NSMutableDictionary *uniqueKeysDictionary;
40+
@end
41+
3042
@implementation ManagedObjectInstanceProvider
31-
@synthesize managedObjectContext;
3243

3344
#pragma mark - Initialization -
3445

@@ -37,24 +48,129 @@ - (id)initWithManagedObjectContext:(NSManagedObjectContext *)aManagedObjectConte
3748
if (self = [super init])
3849
{
3950
self.managedObjectContext = aManagedObjectContext;
51+
self.uniqueKeysDictionary = [NSMutableDictionary dictionary];
4052
}
4153

4254
return self;
4355
}
4456

57+
- (id)init
58+
{
59+
@throw ([NSException exceptionWithName:@"InvalidInitializer"
60+
reason:@"Use initWithManagedObjectContext to initialize this provider"
61+
userInfo:nil]);
62+
}
63+
64+
#pragma mark - Public Methods -
65+
66+
- (void)setUniqueKeys:(NSArray *)keys forClass:(Class)class withUpsertMode:(UpsertMode)upsertMode
67+
{
68+
for (id key in keys)
69+
{
70+
if (![key isKindOfClass:[NSString class]])
71+
@throw ([NSException exceptionWithName:@"InvalidArgumentException" reason:@"Method setUniqueKeys takes string only" userInfo:nil]);
72+
}
73+
74+
UpsertInfo *upsertInfo = [[UpsertInfo alloc] init];
75+
upsertInfo.keys = keys;
76+
upsertInfo.upsertMode = upsertMode;
77+
78+
[self.uniqueKeysDictionary setObject:upsertInfo forKey:NSStringFromClass(class)];
79+
}
80+
4581
#pragma mark - InstanceProvider Methods -
4682

47-
- (id)emptyInstanceFromClass:(Class)class
83+
- (id)emptyInstanceForClass:(Class)class
4884
{
4985
NSEntityDescription *entity = [NSEntityDescription entityForName:NSStringFromClass(class) inManagedObjectContext:self.managedObjectContext];
5086
return (entity) ? [[NSManagedObject alloc] initWithEntity:entity insertIntoManagedObjectContext:self.managedObjectContext] : nil;
5187
}
5288

53-
- (id)emptyInstanceOfCollectionObject
89+
- (id)emptyCollectionInstance
5490
{
5591
return [NSMutableSet set];
5692
}
5793

94+
- (id)upsertObject:(NSManagedObject *)object error:(NSError **)error
95+
{
96+
UpsertInfo *upsertInfo = [self.uniqueKeysDictionary objectForKey:NSStringFromClass([object class])];
97+
98+
if (!upsertInfo || !upsertInfo.keys.count)
99+
return object;
100+
101+
NSMutableArray *predicates = [NSMutableArray array];
102+
[predicates addObject:[NSPredicate predicateWithFormat:@"SELF != %@", object]];
103+
104+
for (int i=0 ; i<upsertInfo.keys.count ; i++)
105+
{
106+
NSString *key = [upsertInfo.keys objectAtIndex:i];
107+
id value = [object valueForKey:key];
108+
109+
if (key && value)
110+
{
111+
NSPredicate *predicate = [NSPredicate predicateWithFormat:@"%K == %@", key, value];
112+
[predicates addObject:predicate];
113+
}
114+
else
115+
{
116+
*error = [NSError errorWithDomain:[NSString stringWithFormat:@"Value for property '%@' is null. Keys should not be nullable", key] code:0 userInfo:nil];
117+
return object;
118+
}
119+
}
120+
121+
NSPredicate *compundPredicate = [NSCompoundPredicate andPredicateWithSubpredicates:predicates];
122+
NSFetchRequest *request = [[NSFetchRequest alloc] init];
123+
[request setEntity:[NSEntityDescription entityForName:NSStringFromClass([object class]) inManagedObjectContext:self.managedObjectContext]];
124+
[request setPredicate:compundPredicate];
125+
126+
NSError *fetchError;
127+
NSArray *existingObjects = [self.managedObjectContext executeFetchRequest:request error:&fetchError];
128+
129+
if (fetchError)
130+
{
131+
*error = fetchError;
132+
return object;
133+
}
134+
else
135+
{
136+
if (existingObjects.count == 0)
137+
{
138+
return object;
139+
}
140+
else if (existingObjects.count == 1)
141+
{
142+
if (upsertInfo.upsertMode == UpsertModeUpdateExistingObject)
143+
{
144+
NSManagedObject *existingObject = [existingObjects firstObject];
145+
146+
for (NSAttributeDescription *attributeDescription in existingObject.entity.properties)
147+
{
148+
[existingObject setValue:[object valueForKey:attributeDescription.name] forKey:attributeDescription.name];
149+
}
150+
151+
[self.managedObjectContext deleteObject:object];
152+
return existingObject;
153+
}
154+
else if (upsertInfo.upsertMode == UpsertModePurgeExistingObject)
155+
{
156+
NSManagedObject *existingObject = [existingObjects firstObject];
157+
[self.managedObjectContext deleteObject:existingObject];
158+
return object;
159+
}
160+
else
161+
{
162+
*error = [NSError errorWithDomain:[NSString stringWithFormat:@"Invalid upsertMode for class (%@)", NSStringFromClass([object class])] code:0 userInfo:nil];
163+
return object;
164+
}
165+
}
166+
else
167+
{
168+
*error = [NSError errorWithDomain:@"Multiple instances were found based on given key(s)" code:0 userInfo:nil];
169+
return object;
170+
}
171+
}
172+
}
173+
58174
- (NSString *)propertyNameForObject:(NSManagedObject *)object byCaseInsensitivePropertyName:(NSString *)caseInsensitivePropertyName
59175
{
60176
for (NSAttributeDescription *attributeDescription in object.entity.properties)

OCMapper/Source/Instance Provider/ObjectInstanceProvider.m

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -31,16 +31,24 @@ @implementation ObjectInstanceProvider
3131

3232
#pragma mark - InstanceProvider Methods -
3333

34-
- (id)emptyInstanceFromClass:(Class)class
34+
- (id)emptyInstanceForClass:(Class)class
3535
{
3636
return [[class alloc] init];
3737
}
3838

39-
- (id)emptyInstanceOfCollectionObject
39+
- (id)emptyCollectionInstance
4040
{
4141
return [NSMutableArray array];
4242
}
4343

44+
- (id)upsertObject:(NSObject *)object error:(NSError **)error;
45+
{
46+
// Object not stored anywhere and therefore no need to upsert
47+
// This is specifically made for NSManagedObjects used by ManagedObjectInstanceProvider
48+
49+
return object;
50+
}
51+
4452
- (NSString *)propertyNameForObject:(NSObject *)object byCaseInsensitivePropertyName:(NSString *)caseInsensitivePropertyName
4553
{
4654
NSString *result = nil;

OCMapper/Source/ObjectMapper.m

Lines changed: 22 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -44,11 +44,6 @@ @interface ObjectMapper()
4444
@end
4545

4646
@implementation ObjectMapper
47-
@synthesize defaultDateFormatter;
48-
@synthesize commonDateFormaters;
49-
@synthesize instanceProvider;
50-
@synthesize mappingProvider;
51-
@synthesize loggingProvider;
5247

5348
#pragma mark - initialization -
5449

@@ -78,10 +73,10 @@ - (id)init
7873

7974
- (id)objectFromSource:(id)source toInstanceOfClass:(Class)class
8075
{
81-
if (!mappingProvider)
76+
if (!_mappingProvider)
8277
@throw ([NSException exceptionWithName:@"MissingMappingProvider" reason:@"Mapping provider is not set" userInfo:nil]);
8378

84-
if (!instanceProvider)
79+
if (!_instanceProvider)
8580
@throw ([NSException exceptionWithName:@"MissingInstanceProvider" reason:@"Instance provider is not set" userInfo:nil]);
8681

8782
if ([source isKindOfClass:[NSDictionary class]])
@@ -244,7 +239,7 @@ - (id)processDictionary:(NSDictionary *)source forClass:(Class)class
244239
{
245240
NSDictionary *normalizedSource = [self normalizedDictionaryFromDictionary:source forClass:class];
246241

247-
id object = [self.instanceProvider emptyInstanceFromClass:class];
242+
id object = [self.instanceProvider emptyInstanceForClass:class];
248243

249244
for (NSString *key in normalizedSource)
250245
{
@@ -317,12 +312,21 @@ - (id)processDictionary:(NSDictionary *)source forClass:(Class)class
317312
}
318313
}
319314

315+
NSError *error;
316+
object = [self.instanceProvider upsertObject:object error:&error];
317+
318+
if (error)
319+
ELog(@"Attempt to update existing instance failed with error '%@' for class (%@) and object %@",
320+
error.localizedDescription,
321+
NSStringFromClass(class),
322+
object);
323+
320324
return object;
321325
}
322326

323327
- (id)processArray:(NSArray *)value forClass:(Class)class
324328
{
325-
id collection = [self.instanceProvider emptyInstanceOfCollectionObject];
329+
id collection = [self.instanceProvider emptyCollectionInstance];
326330

327331
for (id objectInArray in value)
328332
{
@@ -409,36 +413,36 @@ - (NSDate *)dateFromString:(NSString *)string forProperty:(NSString *)property a
409413

410414
- (NSMutableArray *)commonDateFormaters
411415
{
412-
if (!commonDateFormaters)
416+
if (!_commonDateFormaters)
413417
{
414-
commonDateFormaters = [NSMutableArray array];
418+
_commonDateFormaters = [NSMutableArray array];
415419

416420
NSDateFormatter *formatter1 = [[NSDateFormatter alloc] init];
417421
[formatter1 setDateFormat:@"yyyy-MM-dd"];
418-
[commonDateFormaters addObject:formatter1];
422+
[_commonDateFormaters addObject:formatter1];
419423

420424
NSDateFormatter *formatter2 = [[NSDateFormatter alloc] init];
421425
[formatter2 setDateFormat:@"MM/dd/yyyy"];
422-
[commonDateFormaters addObject:formatter2];
426+
[_commonDateFormaters addObject:formatter2];
423427

424428
NSDateFormatter *formatter3 = [[NSDateFormatter alloc] init];
425429
[formatter3 setDateFormat:@"yyyy-MM-dd'T'HH:mm:ss.SSSSSSSZ"];
426-
[commonDateFormaters addObject:formatter3];
430+
[_commonDateFormaters addObject:formatter3];
427431

428432
NSDateFormatter *formatter4 = [[NSDateFormatter alloc] init];
429433
[formatter4 setDateFormat:@"yyyy-MM-dd HH:mm:ss"];
430-
[commonDateFormaters addObject:formatter4];
434+
[_commonDateFormaters addObject:formatter4];
431435

432436
NSDateFormatter *formatter5 = [[NSDateFormatter alloc] init];
433437
[formatter5 setDateFormat:@"MM/dd/yyyy HH:mm:ss aaa"];
434-
[commonDateFormaters addObject:formatter5];
438+
[_commonDateFormaters addObject:formatter5];
435439

436440
NSDateFormatter *formatter6 = [[NSDateFormatter alloc] init];
437441
[formatter6 setDateFormat:@"yyyy-MM-dd'T'HH:mm:ss'Z'"];
438-
[commonDateFormaters addObject:formatter6];
442+
[_commonDateFormaters addObject:formatter6];
439443
}
440444

441-
return commonDateFormaters;
445+
return _commonDateFormaters;
442446
}
443447

444448
- (NSString *)typeForProperty:(NSString *)property andClass:(Class)class

0 commit comments

Comments
 (0)