From 3d5bb4deff11b638fce0582d75b6a517fb25d8c9 Mon Sep 17 00:00:00 2001 From: Aryan Ghassemi Date: Sun, 29 Dec 2013 18:17:15 -0800 Subject: [PATCH 1/2] - initial checkin for core data update/purge support --- OCMapper.xcodeproj/project.pbxproj | 3 +- OCMapper/Models/CDUser.h | 1 + OCMapper/Models/CDUser.m | 1 + OCMapper/Models/Core Data/CDAddress.h | 1 + OCMapper/Models/Core Data/CDAddress.m | 1 + OCMapper/Models/CoreDataManager.m | 2 +- .../OCMapper.xcdatamodel/contents | 4 +- .../Instance Provider/InstanceProvider.h | 5 +- .../ManagedObjectInstanceProvider.h | 10 +- .../ManagedObjectInstanceProvider.m | 122 ++++++++- .../ObjectInstanceProvider.m | 12 +- OCMapper/Source/ObjectMapper.m | 40 +-- OCMapperTests/ManagedObjectMapperTest.m | 256 +++++++++++++++++- 13 files changed, 425 insertions(+), 33 deletions(-) diff --git a/OCMapper.xcodeproj/project.pbxproj b/OCMapper.xcodeproj/project.pbxproj index 492f8c4..e9b98ab 100644 --- a/OCMapper.xcodeproj/project.pbxproj +++ b/OCMapper.xcodeproj/project.pbxproj @@ -502,7 +502,7 @@ 15B554A2171B7B3B0058E159 /* Project object */ = { isa = PBXProject; attributes = { - LastUpgradeCheck = 0450; + LastUpgradeCheck = 0500; ORGANIZATIONNAME = "Aryan Ghassemi"; }; buildConfigurationList = 15B554A5171B7B3B0058E159 /* Build configuration list for PBXProject "OCMapper" */; @@ -669,6 +669,7 @@ GCC_WARN_UNINITIALIZED_AUTOS = YES; GCC_WARN_UNUSED_VARIABLE = YES; IPHONEOS_DEPLOYMENT_TARGET = 6.0; + ONLY_ACTIVE_ARCH = YES; SDKROOT = iphoneos; TARGETED_DEVICE_FAMILY = "1,2"; }; diff --git a/OCMapper/Models/CDUser.h b/OCMapper/Models/CDUser.h index 48d973c..5e17cd1 100644 --- a/OCMapper/Models/CDUser.h +++ b/OCMapper/Models/CDUser.h @@ -31,6 +31,7 @@ @interface CDUser : NSManagedObject +@property (nonatomic, strong) NSNumber *userId; @property (nonatomic, strong) NSString *firstName; @property (nonatomic, strong) NSString *lastName; @property (nonatomic, strong) NSDate *dateOfBirth; diff --git a/OCMapper/Models/CDUser.m b/OCMapper/Models/CDUser.m index 8902df8..8dfea55 100644 --- a/OCMapper/Models/CDUser.m +++ b/OCMapper/Models/CDUser.m @@ -28,6 +28,7 @@ #import "CDUser.h" @implementation CDUser +@dynamic userId; @dynamic firstName; @dynamic lastName; @dynamic age; diff --git a/OCMapper/Models/Core Data/CDAddress.h b/OCMapper/Models/Core Data/CDAddress.h index f725adf..4a7ff56 100644 --- a/OCMapper/Models/Core Data/CDAddress.h +++ b/OCMapper/Models/Core Data/CDAddress.h @@ -29,6 +29,7 @@ @interface CDAddress : NSManagedObject +@property (nonatomic, strong) NSNumber *addressId; @property (nonatomic, strong) NSString *city; @property (nonatomic, strong) NSString *country; diff --git a/OCMapper/Models/Core Data/CDAddress.m b/OCMapper/Models/Core Data/CDAddress.m index c6ed6fc..dc89ada 100644 --- a/OCMapper/Models/Core Data/CDAddress.m +++ b/OCMapper/Models/Core Data/CDAddress.m @@ -28,6 +28,7 @@ #import "CDAddress.h" @implementation CDAddress +@dynamic addressId; @dynamic city; @dynamic country; diff --git a/OCMapper/Models/CoreDataManager.m b/OCMapper/Models/CoreDataManager.m index 335502f..5440f9f 100644 --- a/OCMapper/Models/CoreDataManager.m +++ b/OCMapper/Models/CoreDataManager.m @@ -193,7 +193,7 @@ - (NSPersistentStoreCoordinator *)persistentStoreCoordinator NSError *error = nil; _persistentStoreCoordinator = [[NSPersistentStoreCoordinator alloc] initWithManagedObjectModel:[self managedObjectModel]]; - if (![_persistentStoreCoordinator addPersistentStoreWithType:NSSQLiteStoreType configuration:nil URL:storeURL options:options error:&error]) + if (![_persistentStoreCoordinator addPersistentStoreWithType:NSInMemoryStoreType configuration:nil URL:storeURL options:options error:&error]) { /* Replace this implementation with code to handle the error appropriately. diff --git a/OCMapper/Models/OCMapper.xcdatamodeld/OCMapper.xcdatamodel/contents b/OCMapper/Models/OCMapper.xcdatamodeld/OCMapper.xcdatamodel/contents index c21ffdf..ec910f2 100644 --- a/OCMapper/Models/OCMapper.xcdatamodeld/OCMapper.xcdatamodel/contents +++ b/OCMapper/Models/OCMapper.xcdatamodeld/OCMapper.xcdatamodel/contents @@ -1,6 +1,7 @@ + @@ -18,13 +19,14 @@ + - + \ No newline at end of file diff --git a/OCMapper/Source/Instance Provider/InstanceProvider.h b/OCMapper/Source/Instance Provider/InstanceProvider.h index 925119f..3abfa17 100644 --- a/OCMapper/Source/Instance Provider/InstanceProvider.h +++ b/OCMapper/Source/Instance Provider/InstanceProvider.h @@ -29,8 +29,9 @@ @protocol InstanceProvider -- (id)emptyInstanceFromClass:(Class)class; -- (id)emptyInstanceOfCollectionObject; +- (id)emptyInstanceForClass:(Class)class; +- (id)emptyCollectionInstance; +- (id)upsertObject:(NSObject *)object error:(NSError **)error; - (NSString *)propertyNameForObject:(NSObject *)object byCaseInsensitivePropertyName:(NSString *)caseInsensitivePropertyName; @end diff --git a/OCMapper/Source/Instance Provider/ManagedObjectInstanceProvider.h b/OCMapper/Source/Instance Provider/ManagedObjectInstanceProvider.h index b0825f6..323686c 100644 --- a/OCMapper/Source/Instance Provider/ManagedObjectInstanceProvider.h +++ b/OCMapper/Source/Instance Provider/ManagedObjectInstanceProvider.h @@ -29,10 +29,14 @@ #import #import "InstanceProvider.h" -@interface ManagedObjectInstanceProvider : NSObject +typedef enum { + UpsertModeUpdateExistingObject, + UpsertModePurgeExistingObject +}UpsertMode; -@property (nonatomic, strong) NSManagedObjectContext *managedObjectContext; +@interface ManagedObjectInstanceProvider : NSObject -- (id)initWithManagedObjectContext:(NSManagedObjectContext *)managedObjectContext; +- (id)initWithManagedObjectContext:(NSManagedObjectContext *)aManagedObjectContext; +- (void)setUniqueKeys:(NSArray *)keys forClass:(Class)class withUpsertMode:(UpsertMode)upsertMode; @end diff --git a/OCMapper/Source/Instance Provider/ManagedObjectInstanceProvider.m b/OCMapper/Source/Instance Provider/ManagedObjectInstanceProvider.m index 33a83af..650b13d 100644 --- a/OCMapper/Source/Instance Provider/ManagedObjectInstanceProvider.m +++ b/OCMapper/Source/Instance Provider/ManagedObjectInstanceProvider.m @@ -27,8 +27,19 @@ #import "ManagedObjectInstanceProvider.h" +@interface UpsertInfo : NSObject +@property (nonatomic, strong) NSArray *keys; +@property (nonatomic, assign) UpsertMode upsertMode; +@end +@implementation UpsertInfo +@end + +@interface ManagedObjectInstanceProvider() +@property (nonatomic, strong) NSManagedObjectContext *managedObjectContext; +@property (nonatomic, strong) NSMutableDictionary *uniqueKeysDictionary; +@end + @implementation ManagedObjectInstanceProvider -@synthesize managedObjectContext; #pragma mark - Initialization - @@ -37,24 +48,129 @@ - (id)initWithManagedObjectContext:(NSManagedObjectContext *)aManagedObjectConte if (self = [super init]) { self.managedObjectContext = aManagedObjectContext; + self.uniqueKeysDictionary = [NSMutableDictionary dictionary]; } return self; } +- (id)init +{ + @throw ([NSException exceptionWithName:@"InvalidInitializer" + reason:@"Use initWithManagedObjectContext to initialize this provider" + userInfo:nil]); +} + +#pragma mark - Public Methods - + +- (void)setUniqueKeys:(NSArray *)keys forClass:(Class)class withUpsertMode:(UpsertMode)upsertMode +{ + for (id key in keys) + { + if (![key isKindOfClass:[NSString class]]) + @throw ([NSException exceptionWithName:@"InvalidArgumentException" reason:@"Method setUniqueKeys takes string only" userInfo:nil]); + } + + UpsertInfo *upsertInfo = [[UpsertInfo alloc] init]; + upsertInfo.keys = keys; + upsertInfo.upsertMode = upsertMode; + + [self.uniqueKeysDictionary setObject:upsertInfo forKey:NSStringFromClass(class)]; +} + #pragma mark - InstanceProvider Methods - -- (id)emptyInstanceFromClass:(Class)class +- (id)emptyInstanceForClass:(Class)class { NSEntityDescription *entity = [NSEntityDescription entityForName:NSStringFromClass(class) inManagedObjectContext:self.managedObjectContext]; return (entity) ? [[NSManagedObject alloc] initWithEntity:entity insertIntoManagedObjectContext:self.managedObjectContext] : nil; } -- (id)emptyInstanceOfCollectionObject +- (id)emptyCollectionInstance { return [NSMutableSet set]; } +- (id)upsertObject:(NSManagedObject *)object error:(NSError **)error +{ + UpsertInfo *upsertInfo = [self.uniqueKeysDictionary objectForKey:NSStringFromClass([object class])]; + + if (!upsertInfo) + return object; + + NSMutableArray *predicates = [NSMutableArray array]; + [predicates addObject:[NSPredicate predicateWithFormat:@"SELF != %@", object]]; + + for (int i=0 ; i Date: Sun, 5 Jan 2014 16:08:13 -0800 Subject: [PATCH 2/2] - check for an existing key before trying to find an existing managed object --- .../Source/Instance Provider/ManagedObjectInstanceProvider.m | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/OCMapper/Source/Instance Provider/ManagedObjectInstanceProvider.m b/OCMapper/Source/Instance Provider/ManagedObjectInstanceProvider.m index 650b13d..fe6ea2a 100644 --- a/OCMapper/Source/Instance Provider/ManagedObjectInstanceProvider.m +++ b/OCMapper/Source/Instance Provider/ManagedObjectInstanceProvider.m @@ -95,7 +95,7 @@ - (id)upsertObject:(NSManagedObject *)object error:(NSError **)error { UpsertInfo *upsertInfo = [self.uniqueKeysDictionary objectForKey:NSStringFromClass([object class])]; - if (!upsertInfo) + if (!upsertInfo || !upsertInfo.keys.count) return object; NSMutableArray *predicates = [NSMutableArray array];