From e11f2e67b0865d22fc1eda6fe2d7940835b2ba48 Mon Sep 17 00:00:00 2001 From: Saul Mora Date: Fri, 9 Mar 2012 17:40:19 +0100 Subject: [PATCH] =?UTF-8?q?some=20changes=20to=20the=20background=20saving?= =?UTF-8?q?=20api=E2=80=A6=20getting=20things=20to=20compile=20for=20the?= =?UTF-8?q?=20time=20being?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../NSManagedObjectContext+MagicalRecord.h | 6 +- .../NSManagedObjectContext+MagicalRecord.m | 40 ++++-- .../NSManagedObjectContext+MagicalSaves.h | 13 +- .../NSManagedObjectContext+MagicalSaves.m | 82 +++++++------ MagicalRecord/CoreData+MagicalRecord.h | 5 + MagicalRecord/MagicalRecord+Actions.h | 8 +- MagicalRecord/MagicalRecord+Actions.m | 114 ++++++++---------- MagicalRecord/MagicalRecord.m | 1 - 8 files changed, 138 insertions(+), 131 deletions(-) diff --git a/MagicalRecord/Categories/NSManagedObjectContext+MagicalRecord.h b/MagicalRecord/Categories/NSManagedObjectContext+MagicalRecord.h index fd35b63..8f8059c 100644 --- a/MagicalRecord/Categories/NSManagedObjectContext+MagicalRecord.h +++ b/MagicalRecord/Categories/NSManagedObjectContext+MagicalRecord.h @@ -13,8 +13,10 @@ extern NSString * const kMagicalRecordDidMergeChangesFromiCloudNotification; + (void) MR_initializeDefaultContextWithCoordinator:(NSPersistentStoreCoordinator *)coordinator; -+ (NSManagedObjectContext *) MR_context; -+ (NSManagedObjectContext *) MR_contextWithStoreCoordinator:(NSPersistentStoreCoordinator *)coordinator; ++ (NSManagedObjectContext *) MR_context NS_RETURNS_RETAINED; ++ (NSManagedObjectContext *) MR_newMainQueueContext NS_RETURNS_RETAINED; ++ (NSManagedObjectContext *) MR_contextThatPushesChangesToDefaultContext NS_RETURNS_RETAINED; ++ (NSManagedObjectContext *) MR_contextWithStoreCoordinator:(NSPersistentStoreCoordinator *)coordinator NS_RETURNS_RETAINED; + (void) MR_resetDefaultContext; + (NSManagedObjectContext *) MR_defaultContext; diff --git a/MagicalRecord/Categories/NSManagedObjectContext+MagicalRecord.m b/MagicalRecord/Categories/NSManagedObjectContext+MagicalRecord.m index bc6a754..ad54c6f 100644 --- a/MagicalRecord/Categories/NSManagedObjectContext+MagicalRecord.m +++ b/MagicalRecord/Categories/NSManagedObjectContext+MagicalRecord.m @@ -21,7 +21,7 @@ static NSManagedObjectContext *defaultManageObjectContext_ = nil; @implementation NSManagedObjectContext (MagicalRecord) -+ (NSManagedObjectContext *)MR_defaultContext ++ (NSManagedObjectContext *) MR_defaultContext { @synchronized (self) { @@ -29,7 +29,7 @@ static NSManagedObjectContext *defaultManageObjectContext_ = nil; } } -+ (void)MR_setDefaultContext:(NSManagedObjectContext *)moc ++ (void) MR_setDefaultContext:(NSManagedObjectContext *)moc { NSPersistentStoreCoordinator *coordinator = [NSPersistentStoreCoordinator MR_defaultStoreCoordinator]; if ([MagicalRecord isICloudEnabled]) @@ -45,7 +45,21 @@ static NSManagedObjectContext *defaultManageObjectContext_ = nil; } } -+ (void)MR_resetDefaultContext ++ (void) MR_initializeDefaultContextWithCoordinator:(NSPersistentStoreCoordinator *)coordinator; +{ + if ([self MR_defaultContext] == nil) + { + NSManagedObjectContext *context = [self MR_context]; + + [context performBlockAndWait:^{ + [context setPersistentStoreCoordinator:coordinator]; + }]; + + [self MR_setDefaultContext:context]; + } +} + ++ (void) MR_resetDefaultContext { void (^resetBlock)(void) = ^{ [[NSManagedObjectContext MR_defaultContext] reset]; @@ -60,18 +74,18 @@ static NSManagedObjectContext *defaultManageObjectContext_ = nil; return context; } -+ (void) MR_initializeDefaultContextWithCoordinator:(NSPersistentStoreCoordinator *)coordinator; ++ (NSManagedObjectContext *) MR_newMainQueueContext; { - if ([self MR_defaultContext] == nil) - { - NSManagedObjectContext *context = [[NSManagedObjectContext alloc] initWithConcurrencyType:NSMainQueueConcurrencyType]; + NSManagedObjectContext *context = [[self alloc] initWithConcurrencyType:NSMainQueueConcurrencyType]; + return context; +} - [context performBlockAndWait:^{ - [context setPersistentStoreCoordinator:coordinator]; - }]; - - [self MR_setDefaultContext:context]; - } ++ (NSManagedObjectContext *) MR_contextThatPushesChangesToDefaultContext; +{ + NSManagedObjectContext *context = [self MR_defaultContext]; + NSManagedObjectContext *childContext = [[NSManagedObjectContext alloc] initWithConcurrencyType:NSPrivateQueueConcurrencyType]; + [childContext setParentContext:context]; + return childContext; } + (NSManagedObjectContext *) MR_contextWithStoreCoordinator:(NSPersistentStoreCoordinator *)coordinator; diff --git a/MagicalRecord/Categories/NSManagedObjectContext+MagicalSaves.h b/MagicalRecord/Categories/NSManagedObjectContext+MagicalSaves.h index a226054..45c258b 100644 --- a/MagicalRecord/Categories/NSManagedObjectContext+MagicalSaves.h +++ b/MagicalRecord/Categories/NSManagedObjectContext+MagicalSaves.h @@ -10,14 +10,13 @@ @interface NSManagedObjectContext (MagicalSaves) -- (BOOL) MR_save; +- (void) MR_save; +- (void) MR_saveErrorHandler:(void (^)(NSError *))errorCallback; -#ifdef NS_BLOCKS_AVAILABLE -- (BOOL) MR_saveWithErrorHandler:(void (^)(NSError *))errorCallback; -#endif - -- (BOOL) MR_saveOnMainThread; -- (BOOL) MR_saveOnBackgroundThread; +- (void) MR_saveInBackground; +- (void) MR_saveInBackgroundErrorHandler:(void (^)(NSError *))errorCallback; +- (void) MR_saveNestedContexts; +- (void) MR_saveNestedContextsErrorHandler:(void (^)(NSError *))errorCallback; @end diff --git a/MagicalRecord/Categories/NSManagedObjectContext+MagicalSaves.m b/MagicalRecord/Categories/NSManagedObjectContext+MagicalSaves.m index cd1a766..2ef9deb 100644 --- a/MagicalRecord/Categories/NSManagedObjectContext+MagicalSaves.m +++ b/MagicalRecord/Categories/NSManagedObjectContext+MagicalSaves.m @@ -8,74 +8,80 @@ #import "NSManagedObjectContext+MagicalSaves.h" +@interface NSManagedObjectContext (InternalMagicalSaves) + +- (void) MR_saveErrorCallback:(void(^)(NSError *))errorCallback; + +@end + + @implementation NSManagedObjectContext (MagicalSaves) -- (BOOL) MR_saveNestedContexts:(BOOL)saveParents errorHandler:(void(^)(NSError *))errorCallback; +- (void) MR_saveErrorCallback:(void(^)(NSError *))errorCallback; { - __block NSError *error = nil; - __block BOOL saved = NO; - + MRLog(@"Saving %@Context%@", self == [[self class] MR_defaultContext] ? @" *** Default *** ": @"", ([NSThread isMainThread] ? @" *** on Main Thread ***" : @"")); + + NSError *error = nil; + BOOL saved = NO; @try { - [self performBlockAndWait:^{ - MRLog(@"Saving %@Context%@", - self == [[self class] MR_defaultContext] ? @" *** Default *** ": @"", - ([NSThread isMainThread] ? @" *** on Main Thread ***" : @"")); - - saved = [self save:&error]; - }]; + saved = [self save:&error]; } @catch (NSException *exception) { - MRLog(@"Problem saving: %@", (id)[exception userInfo] ?: (id)[exception reason]); + MRLog(@"Unable to perform save: %@", (id)[exception userInfo] ?: (id)[exception reason]); } @finally { - NSManagedObjectContext *parentContext = [self parentContext]; - if (saved && saveParents) - { - return saved && [parentContext MR_saveNestedContexts:saveParents errorHandler:errorCallback]; - } if (!saved) { - [MagicalRecord handleErrors:error]; + if (errorCallback) + { + errorCallback(error); + } + else + { + [MagicalRecord handleErrors:error]; + } } - return saved; } } -- (BOOL) MR_saveNestedContextsErrorHandler:(void (^)(NSError *))errorCallback; +- (void) MR_saveNestedContexts; { - return [self MR_saveNestedContexts:YES errorHandler:errorCallback]; + [self MR_saveNestedContextsErrorHandler:nil]; } -- (BOOL) MR_saveWithErrorHandler:(void (^)(NSError *))errorCallback; +- (void) MR_saveNestedContextsErrorHandler:(void (^)(NSError *))errorCallback; { - return [self MR_saveNestedContexts:NO errorHandler:errorCallback]; + [self performBlockAndWait:^{ + [self MR_saveErrorCallback:errorCallback]; + }]; + [[self parentContext] MR_saveNestedContextsErrorHandler:errorCallback]; } -- (BOOL) MR_save; +- (void) MR_save; { - return [self MR_saveNestedContexts:NO errorHandler:nil]; + [self MR_saveErrorCallback:nil]; } -#pragma mark - Threading Save Helpers - -- (BOOL) MR_saveOnBackgroundThread; +- (void) MR_saveErrorHandler:(void (^)(NSError *))errorCallback; { - [self performSelectorInBackground:@selector(MR_save) withObject:nil]; - - return YES; + [self performBlockAndWait:^{ + [self MR_saveErrorCallback:errorCallback]; + }]; } -- (BOOL) MR_saveOnMainThread; +- (void) MR_saveInBackground; { - @synchronized(self) - { - [self performSelectorOnMainThread:@selector(MR_save) withObject:nil waitUntilDone:YES]; - } - - return YES; + [self MR_saveInBackgroundErrorHandler:nil]; +} + +- (void) MR_saveInBackgroundErrorHandler:(void (^)(NSError *))errorCallback; +{ + [self performBlock:^{ + [self MR_saveErrorCallback:errorCallback]; + }]; } @end diff --git a/MagicalRecord/CoreData+MagicalRecord.h b/MagicalRecord/CoreData+MagicalRecord.h index ad958b9..7d47290 100644 --- a/MagicalRecord/CoreData+MagicalRecord.h +++ b/MagicalRecord/CoreData+MagicalRecord.h @@ -24,6 +24,11 @@ #define MRLog(...) ((void)0) #endif + +#ifndef NS_BLOCKS_AVAILABLE +#warning MagicalRecord requires blocks +#endif + // #if !( __has_feature(objc_arc) && __has_feature(objc_arc_weak) ) // #error MagicalRecord now requires ARC to be enabled // #endif diff --git a/MagicalRecord/MagicalRecord+Actions.h b/MagicalRecord/MagicalRecord+Actions.h index 896fd03..b2bc462 100644 --- a/MagicalRecord/MagicalRecord+Actions.h +++ b/MagicalRecord/MagicalRecord+Actions.h @@ -11,15 +11,9 @@ @interface MagicalRecord (Actions) -#ifdef NS_BLOCKS_AVAILABLE - + (void) saveWithBlock:(void(^)(NSManagedObjectContext *localContext))block; + (void) saveInBackgroundWithBlock:(void(^)(NSManagedObjectContext *localContext))block; + (void) saveInBackgroundWithBlock:(void(^)(NSManagedObjectContext *localContext))block completion:(void(^)(void))callback; -#endif - -@end - -void cleanup_save_queue(); \ No newline at end of file +@end \ No newline at end of file diff --git a/MagicalRecord/MagicalRecord+Actions.m b/MagicalRecord/MagicalRecord+Actions.m index eb94f94..b376ef7 100644 --- a/MagicalRecord/MagicalRecord+Actions.m +++ b/MagicalRecord/MagicalRecord+Actions.m @@ -8,50 +8,17 @@ #import "CoreData+MagicalRecord.h" #import "NSManagedObjectContext+MagicalRecord.h" -#import - -dispatch_queue_t background_save_queue(void); -void cleanup_save_queue(void); - -static dispatch_queue_t coredata_background_save_queue; - -dispatch_queue_t background_save_queue() -{ - if (coredata_background_save_queue == NULL) - { - coredata_background_save_queue = dispatch_queue_create("com.magicalpanda.magicalrecord.backgroundsaves", 0); - } - return coredata_background_save_queue; -} - -void cleanup_save_queue() -{ - if (coredata_background_save_queue != NULL) - { - dispatch_release(coredata_background_save_queue); - coredata_background_save_queue = NULL; - } -} @implementation MagicalRecord (Actions) -#ifdef NS_BLOCKS_AVAILABLE - -+ (void) saveWithBlock:(void (^)(NSManagedObjectContext *localContext))block errorHandler:(void (^)(NSError *))errorHandler ++ (void) saveInBackgroundWithBlock:(void (^)(NSManagedObjectContext *))block completion:(void (^)(void))completion errorHandler:(void (^)(NSError *))errorHandler; { NSManagedObjectContext *mainContext = [NSManagedObjectContext MR_defaultContext]; NSManagedObjectContext *localContext = mainContext; - NSPersistentStoreCoordinator *defaultCoordinator = [NSPersistentStoreCoordinator MR_defaultStoreCoordinator]; + if (![NSThread isMainThread]) { - -#if kCreateNewCoordinatorOnBackgroundOperations == 1 - NSPersistentStoreCoordinator *localCoordinator = [NSPersistentStoreCoordinator coordinatorWithPersitentStore:[NSPersistentStore defaultPersistentStore]]; - localContext = [NSManagedObjectContext contextThatNotifiesDefaultContextOnMainThreadWithCoordinator:localCoordinator]; -#else - localContext = [NSManagedObjectContext MR_contextForCurrentThread]; - [localContext MR_observeiCloudChangesInCoordinator:defaultCoordinator]; -#endif + localContext = [NSManagedObjectContext MR_contextThatPushesChangesToDefaultContext]; [mainContext setMergePolicy:NSMergeByPropertyStoreTrumpMergePolicy]; [localContext setMergePolicy:NSOverwriteMergePolicy]; } @@ -60,49 +27,70 @@ void cleanup_save_queue() if ([localContext hasChanges]) { - [localContext MR_saveWithErrorHandler:errorHandler]; + [localContext MR_saveInBackgroundErrorHandler:errorHandler]; } - [localContext MR_stopObservingiCloudChangesInCoordinator:defaultCoordinator]; [mainContext setMergePolicy:NSMergeByPropertyObjectTrumpMergePolicy]; + + if (completion) + { + completion(); + } +} + ++ (void) saveWithBlock:(void (^)(NSManagedObjectContext *localContext))block completion:(void (^)(void))completion errorHandler:(void (^)(NSError *))errorHandler; +{ + NSManagedObjectContext *mainContext = [NSManagedObjectContext MR_defaultContext]; + NSManagedObjectContext *localContext = mainContext; + + if (![NSThread isMainThread]) + { + localContext = [NSManagedObjectContext MR_contextThatPushesChangesToDefaultContext]; + [mainContext setMergePolicy:NSMergeByPropertyStoreTrumpMergePolicy]; + [localContext setMergePolicy:NSOverwriteMergePolicy]; + } + + block(localContext); + + if ([localContext hasChanges]) + { + [localContext MR_saveErrorHandler:errorHandler]; + } + + [mainContext setMergePolicy:NSMergeByPropertyObjectTrumpMergePolicy]; + + if (completion) + { + completion(); + } } + (void) saveWithBlock:(void(^)(NSManagedObjectContext *localContext))block { - [self saveWithBlock:block errorHandler:NULL]; + [self saveWithBlock:block completion:nil errorHandler:nil]; } + (void) saveInBackgroundWithBlock:(void(^)(NSManagedObjectContext *localContext))block { - dispatch_async(background_save_queue(), ^{ - [self saveWithBlock:block]; - }); + [self saveInBackgroundWithBlock:block completion:nil errorHandler:nil]; } + (void) saveInBackgroundWithBlock:(void(^)(NSManagedObjectContext *localContext))block completion:(void(^)(void))callback { - dispatch_async(background_save_queue(), ^{ - [self saveWithBlock:block]; - - if (callback) - { - dispatch_async(dispatch_get_main_queue(), callback); - } - }); + [self saveInBackgroundWithBlock:block completion:callback errorHandler:nil]; } -+ (void) saveInBackgroundWithBlock:(void (^)(NSManagedObjectContext *localContext))block completion:(void (^)(void))callback errorHandler:(void (^)(NSError *))errorHandler -{ - dispatch_async(background_save_queue(), ^{ - [self saveWithBlock:block errorHandler:errorHandler]; - - if (callback) - { - dispatch_async(dispatch_get_main_queue(), callback); - } - }); -} - -#endif +// +//+ (void) saveInBackgroundWithBlock:(void (^)(NSManagedObjectContext *localContext))block completion:(void (^)(void))callback errorHandler:(void (^)(NSError *))errorHandler +//{ +// dispatch_async(background_save_queue(), ^{ +// [self saveWithBlock:block errorHandler:errorHandler]; +// +// if (callback) +// { +// dispatch_async(dispatch_get_main_queue(), callback); +// } +// }); +//} @end \ No newline at end of file diff --git a/MagicalRecord/MagicalRecord.m b/MagicalRecord/MagicalRecord.m index b1b37e9..4ae45c7 100644 --- a/MagicalRecord/MagicalRecord.m +++ b/MagicalRecord/MagicalRecord.m @@ -18,7 +18,6 @@ + (void) cleanUp { - cleanup_save_queue(); [self cleanUpErrorHanding]; [self cleanUpStack]; }