Implement new save methods

This commit is contained in:
Tony Arnold
2012-11-28 08:12:51 +11:00
parent fb81b5b737
commit 4f35e4e399
4 changed files with 288 additions and 124 deletions

View File

@@ -8,17 +8,38 @@
#import <CoreData/CoreData.h>
typedef NS_OPTIONS(NSUInteger, MRSaveContextOptions) {
MRSaveParentContexts = 1,
MRSaveSynchronously = 2
};
typedef void (^MRSaveCompletionHandler)(BOOL success, NSError *error);
@interface NSManagedObjectContext (MagicalSaves)
- (void) MR_save;
- (void) MR_saveWithErrorCallback:(void(^)(NSError *))errorCallback;
// Asynchronous saving
- (void) MR_saveOnlySelfWithCompletion:(MRSaveCompletionHandler)completion;
- (void) MR_saveToPersistentStoreWithCompletion:(MRSaveCompletionHandler)completion;
- (void) MR_saveInBackgroundCompletion:(void (^)(void))completion;
- (void) MR_saveInBackgroundErrorHandler:(void (^)(NSError *))errorCallback;
- (void) MR_saveInBackgroundErrorHandler:(void (^)(NSError *))errorCallback completion:(void (^)(void))completion;
// Synchronous saving
- (void) MR_saveOnlySelfAndWait;
- (void) MR_saveToPersistentStoreAndWait;
- (void) MR_saveNestedContexts;
- (void) MR_saveNestedContextsErrorHandler:(void (^)(NSError *))errorCallback;
- (void) MR_saveNestedContextsErrorHandler:(void (^)(NSError *))errorCallback completion:(void (^)(void))completion;
// Save with options
- (void) MR_saveWithOptions:(MRSaveContextOptions)mask completion:(MRSaveCompletionHandler)completion;
/* DEPRECATION NOTICE:
* The following methods are deprecated, but remain in place for backwards compatibility until the next major version (3.x)
*/
- (void) MR_save __attribute__((deprecated));
- (void) MR_saveWithErrorCallback:(void(^)(NSError *))errorCallback __attribute__((deprecated));
- (void) MR_saveInBackgroundCompletion:(void (^)(void))completion __attribute__((deprecated));
- (void) MR_saveInBackgroundErrorHandler:(void (^)(NSError *))errorCallback __attribute__((deprecated));
- (void) MR_saveInBackgroundErrorHandler:(void (^)(NSError *))errorCallback completion:(void (^)(void))completion __attribute__((deprecated));
- (void) MR_saveNestedContexts __attribute__((deprecated));
- (void) MR_saveNestedContextsErrorHandler:(void (^)(NSError *))errorCallback __attribute__((deprecated));
- (void) MR_saveNestedContextsErrorHandler:(void (^)(NSError *))errorCallback completion:(void (^)(void))completion __attribute__((deprecated));
@end

View File

@@ -11,115 +11,180 @@
#import "NSManagedObjectContext+MagicalRecord.h"
#import "MagicalRecord.h"
@interface NSManagedObjectContext (InternalMagicalSaves)
- (void) MR_saveWithErrorCallback:(void(^)(NSError *))errorCallback;
@end
@implementation NSManagedObjectContext (MagicalSaves)
- (void) MR_saveWithErrorCallback:(void(^)(NSError *))errorCallback;
- (void)MR_saveOnlySelfWithCompletion:(MRSaveCompletionHandler)completion;
{
if (![self hasChanges])
{
MRLog(@"NO CHANGES IN CONTEXT %@ - NOT SAVING", [self MR_description]);
[self MR_saveWithOptions:0 completion:completion];
}
- (void)MR_saveOnlySelfAndWait;
{
[self MR_saveWithOptions:MRSaveSynchronously completion:nil];
}
- (void) MR_saveToPersistentStoreWithCompletion:(MRSaveCompletionHandler)completion;
{
[self MR_saveWithOptions:MRSaveParentContexts completion:completion];
}
- (void) MR_saveToPersistentStoreAndWait;
{
[self MR_saveWithOptions:MRSaveParentContexts | MRSaveSynchronously completion:nil];
}
- (void)MR_saveWithOptions:(MRSaveContextOptions)mask completion:(MRSaveCompletionHandler)completion;
{
BOOL syncSave = ((mask & MRSaveSynchronously) == MRSaveSynchronously);
BOOL saveParentContexts = ((mask & MRSaveParentContexts) == MRSaveParentContexts);
if (![self hasChanges]) {
MRLog(@"NO CHANGES IN ** %@ ** CONTEXT - NOT SAVING", [self MR_workingName]);
if (completion)
{
completion(NO, nil);
}
return;
}
MRLog(@"-> Saving %@", [self MR_description]);
__block NSError *error = nil;
__block BOOL saved = NO;
@try
{
[self performBlockAndWait:^{
saved = [self save:&error];
}];
}
@catch (NSException *exception)
{
MRLog(@"Unable to perform save: %@", (id)[exception userInfo] ?: (id)[exception reason]);
}
@finally
{
if (!saved)
MRLog(@" Saving %@", [self MR_description]);
id saveBlock = ^{
NSError *error = nil;
BOOL saved = NO;
@try
{
if (errorCallback)
{
errorCallback(error);
}
else
{
saved = [self save:&error];
}
@catch(NSException *exception)
{
MRLog(@"Unable to perform save: %@", (id)[exception userInfo] ? : (id)[exception reason]);
}
@finally
{
if (!saved) {
[MagicalRecord handleErrors:error];
if (completion) {
completion(saved, error);
}
} else {
// If we're the default context, save to disk too (the user expects it to persist)
if (self == [[self class] MR_defaultContext]) {
[[[self class] MR_rootSavingContext] MR_saveWithOptions:MRSaveSynchronously completion:completion];
}
// If we're saving parent contexts, do so
else if ((YES == saveParentContexts) && [self parentContext]) {
[[self parentContext] MR_saveWithOptions:MRSaveSynchronously | MRSaveParentContexts completion:completion];
}
// If we are not the default context (And therefore need to save the root context, do the completion action if one was specified
else {
MRLog(@"→ Finished saving: %@", [self MR_description]);
if (completion) {
completion(saved, error);
}
}
}
}
};
if (YES == syncSave) {
[self performBlockAndWait:saveBlock];
} else {
[self performBlock:saveBlock];
}
}
- (void) MR_saveNestedContexts;
#pragma mark - Deprecated methods
// These methods will be removed in MagicalRecord 3.0
- (void)MR_saveNestedContexts;
{
[self MR_saveNestedContextsErrorHandler:nil];
[self MR_saveToPersistentStoreWithCompletion:nil];
}
- (void) MR_saveNestedContextsErrorHandler:(void (^)(NSError *))errorCallback;
- (void)MR_saveNestedContextsErrorHandler:(void (^)(NSError *))errorCallback;
{
[self MR_saveNestedContextsErrorHandler:nil completion:nil];
[self MR_saveToPersistentStoreWithCompletion:^(BOOL success, NSError *error) {
if (!success) {
if (errorCallback) {
errorCallback(error);
}
}
}];
}
- (void) MR_saveNestedContextsErrorHandler:(void (^)(NSError *))errorCallback completion:(void (^)(void))completion;
- (void)MR_saveNestedContextsErrorHandler:(void (^)(NSError *))errorCallback completion:(void (^)(void))completion;
{
[self performBlock:^{
[self MR_saveWithErrorCallback:errorCallback];
if (self.parentContext) {
[[self parentContext] performBlock:^{
[[self parentContext] MR_saveNestedContextsErrorHandler:errorCallback completion:completion];
}];
} else {
[self MR_saveToPersistentStoreWithCompletion:^(BOOL success, NSError *error) {
if (success) {
if (completion) {
dispatch_async(dispatch_get_main_queue(), ^{
completion();
});
completion();
}
} else {
if (errorCallback) {
errorCallback(error);
}
}
}];
}
- (void) MR_save;
- (void)MR_save;
{
[self MR_saveWithErrorCallback:nil];
[self MR_saveToPersistentStoreAndWait];
}
- (void) MR_saveInBackgroundCompletion:(void (^)(void))completion;
{
[self MR_saveInBackgroundErrorHandler:nil completion:completion];
}
- (void)MR_saveWithErrorCallback:(void (^)(NSError *))errorCallback __attribute__((deprecated));
- (void) MR_saveInBackgroundErrorHandler:(void (^)(NSError *))errorCallback;
{
[self MR_saveInBackgroundErrorHandler:errorCallback completion:nil];
}
- (void) MR_saveInBackgroundErrorHandler:(void (^)(NSError *))errorCallback completion:(void (^)(void))completion;
{
[self performBlock:^{
// Save the context
[self MR_saveWithErrorCallback:errorCallback];
// If we're the default context, save to disk too (the user expects it to persist)
if (self == [[self class] MR_defaultContext])
{
[[[self class] MR_rootSavingContext] MR_saveInBackgroundErrorHandler:errorCallback completion:completion];
}
else
{
// If we are not the default context (And therefore need to save the root context, do the completion action if one was specified
if (completion)
{
dispatch_async(dispatch_get_main_queue(), completion);
[self MR_saveWithOptions:MRSaveSynchronously completion:^(BOOL success, NSError *error) {
if (!success) {
if (errorCallback) {
errorCallback(error);
}
}
}];
}
- (void)MR_saveInBackgroundCompletion:(void (^)(void))completion;
{
[self MR_saveOnlySelfWithCompletion:^(BOOL success, NSError *error) {
if (success) {
if (completion) {
completion();
}
}
}];
}
- (void)MR_saveInBackgroundErrorHandler:(void (^)(NSError *))errorCallback;
{
[self MR_saveOnlySelfWithCompletion:^(BOOL success, NSError *error) {
if (!success) {
if (errorCallback) {
errorCallback(error);
}
}
}];
}
- (void)MR_saveInBackgroundErrorHandler:(void (^)(NSError *))errorCallback completion:(void (^)(void))completion;
{
[self MR_saveOnlySelfWithCompletion:^(BOOL success, NSError *error) {
if (success) {
if (completion) {
completion();
}
} else {
if (errorCallback) {
errorCallback(error);
}
}
}];
}
@end

View File

@@ -7,21 +7,38 @@
#import <Foundation/Foundation.h>
#import "NSManagedObjectContext+MagicalRecord.h"
#import "NSManagedObjectContext+MagicalSaves.h"
@interface MagicalRecord (Actions)
/* For saving on the current thread as the caller, only with a seperate context. Useful when you're managing your own threads/queues and need a serial call to create or change data
/* For all background saving operations. These calls will be sent to a different thread/queue.
*/
+ (void) saveWithBlock:(void(^)(NSManagedObjectContext *localContext))block;
+ (void) saveWithBlock:(void(^)(NSManagedObjectContext *localContext))block completion:(MRSaveCompletionHandler)completion;
/* For saving on the current thread as the caller, only with a seperate context. Useful when you're managing your own threads/queues and need a serial call to create or change data
*/
+ (void) saveWithBlockAndWait:(void(^)(NSManagedObjectContext *localContext))block;
/*
If you want to reuse the context on the current thread, use these methods.
*/
+ (void) saveUsingCurrentContextWithBlock:(void (^)(NSManagedObjectContext *localContext))block completion:(MRSaveCompletionHandler)completion;
+ (void) saveUsingCurrentContextWithBlockAndWait:(void (^)(NSManagedObjectContext *localContext))block;
/* DEPRECATION NOTICE:
* The following methods are deprecated, but remain in place for backwards compatibility until the next major version (3.x)
*/
/* For all background saving operations. These calls will be sent to a different thread/queue.
*/
+ (void) saveInBackgroundWithBlock:(void(^)(NSManagedObjectContext *localContext))block;
+ (void) saveInBackgroundWithBlock:(void(^)(NSManagedObjectContext *localContext))block completion:(void(^)(void))callback;
+ (void) saveInBackgroundWithBlock:(void(^)(NSManagedObjectContext *localContext))block __attribute__((deprecated));
+ (void) saveInBackgroundWithBlock:(void(^)(NSManagedObjectContext *localContext))block completion:(void(^)(void))completion __attribute__((deprecated));
/*
If you want to reuse the context on the current thread, use this method.
*/
+ (void) saveInBackgroundUsingCurrentContextWithBlock:(void (^)(NSManagedObjectContext *))block completion:(void (^)(void))completion errorHandler:(void (^)(NSError *))errorHandler;
+ (void) saveInBackgroundUsingCurrentContextWithBlock:(void (^)(NSManagedObjectContext *localContext))block completion:(void (^)(void))completion errorHandler:(void (^)(NSError *))errorHandler __attribute__((deprecated));
@end

View File

@@ -8,63 +8,124 @@
#import "CoreData+MagicalRecord.h"
#import "NSManagedObjectContext+MagicalRecord.h"
@implementation MagicalRecord (Actions)
+ (void) saveInBackgroundUsingContext:(NSManagedObjectContext *)localContext block:(void (^)(NSManagedObjectContext *))block completion:(void(^)(void))completion errorHandler:(void(^)(NSError *))errorHandler;
#pragma mark - Asynchronous saving
+ (void) saveWithBlock:(void(^)(NSManagedObjectContext *localContext))block;
{
[localContext performBlock: ^{
block(localContext);
[localContext MR_saveNestedContextsErrorHandler:errorHandler completion:completion];
[self saveWithBlock:block completion:nil];
}
+ (void) saveWithBlock:(void(^)(NSManagedObjectContext *localContext))block completion:(MRSaveCompletionHandler)completion;
{
NSManagedObjectContext *mainContext = [NSManagedObjectContext MR_defaultContext];
NSManagedObjectContext *localContext = [NSManagedObjectContext MR_contextWithParent:mainContext];
[localContext performBlock:^{
if (block) {
block(localContext);
}
[localContext MR_saveWithOptions:MRSaveParentContexts|MRSaveSynchronously completion:completion];
}];
}
+ (void) saveInBackgroundWithBlock:(void (^)(NSManagedObjectContext *))block completion:(void (^)(void))completion errorHandler:(void (^)(NSError *))errorHandler;
{
NSManagedObjectContext *mainContext = [NSManagedObjectContext MR_defaultContext];
NSManagedObjectContext *localContext = [NSManagedObjectContext MR_contextWithParent:mainContext];
[self saveInBackgroundUsingContext:localContext block:block completion:completion errorHandler:errorHandler];
}
+ (void) saveInBackgroundUsingCurrentContextWithBlock:(void (^)(NSManagedObjectContext *))block completion:(void (^)(void))completion errorHandler:(void (^)(NSError *))errorHandler;
+ (void) saveUsingCurrentContextWithBlock:(void (^)(NSManagedObjectContext *localContext))block completion:(MRSaveCompletionHandler)completion;
{
NSManagedObjectContext *localContext = [NSManagedObjectContext MR_contextForCurrentThread];
[self saveInBackgroundUsingContext:localContext block:block completion:completion errorHandler:errorHandler];
[localContext performBlock:^{
if (block) {
block(localContext);
}
[localContext MR_saveWithOptions:MRSaveParentContexts|MRSaveSynchronously completion:completion];
}];
}
+ (void) saveWithBlock:(void (^)(NSManagedObjectContext *localContext))block completion:(void (^)(void))completion errorHandler:(void (^)(NSError *))errorHandler;
#pragma mark - Synchronous saving
+ (void) saveWithBlockAndWait:(void(^)(NSManagedObjectContext *localContext))block;
{
NSManagedObjectContext *mainContext = [NSManagedObjectContext MR_defaultContext];
NSManagedObjectContext *localContext = [NSManagedObjectContext MR_contextWithParent:mainContext];
block(localContext);
if ([localContext hasChanges])
{
[localContext MR_saveWithErrorCallback:errorHandler];
}
if (completion)
{
dispatch_async(dispatch_get_main_queue(), completion);
}
[localContext performBlockAndWait:^{
if (block) {
block(localContext);
}
[localContext MR_saveWithOptions:MRSaveParentContexts|MRSaveSynchronously completion:nil];
}];
}
+ (void) saveWithBlock:(void(^)(NSManagedObjectContext *localContext))block
{
[self saveWithBlock:block completion:nil errorHandler:nil];
+ (void) saveUsingCurrentContextWithBlockAndWait:(void (^)(NSManagedObjectContext *localContext))block;
{
NSManagedObjectContext *localContext = [NSManagedObjectContext MR_contextForCurrentThread];
[localContext performBlockAndWait:^{
if (block) {
block(localContext);
}
[localContext MR_saveWithOptions:MRSaveParentContexts|MRSaveSynchronously completion:nil];
}];
}
#pragma mark - Deprecated methods
+ (void) saveInBackgroundWithBlock:(void(^)(NSManagedObjectContext *localContext))block
{
[self saveInBackgroundWithBlock:block completion:nil errorHandler:nil];
[[self class] saveWithBlock:block completion:nil];
}
+ (void) saveInBackgroundWithBlock:(void(^)(NSManagedObjectContext *localContext))block completion:(void(^)(void))callback
+ (void) saveInBackgroundWithBlock:(void(^)(NSManagedObjectContext *localContext))block completion:(void(^)(void))completion
{
[self saveInBackgroundWithBlock:block completion:callback errorHandler:nil];
NSManagedObjectContext *mainContext = [NSManagedObjectContext MR_defaultContext];
NSManagedObjectContext *localContext = [NSManagedObjectContext MR_contextWithParent:mainContext];
[localContext performBlock:^{
if (block)
{
block(localContext);
}
[localContext MR_saveToPersistentStoreAndWait];
if (completion)
{
completion();
}
}];
}
+ (void) saveInBackgroundUsingCurrentContextWithBlock:(void (^)(NSManagedObjectContext *localContext))block completion:(void (^)(void))completion errorHandler:(void (^)(NSError *))errorHandler;
{
NSManagedObjectContext *localContext = [NSManagedObjectContext MR_contextForCurrentThread];
[localContext performBlock:^{
if (block) {
block(localContext);
}
[localContext MR_saveToPersistentStoreWithCompletion:^(BOOL success, NSError *error) {
if (success) {
if (completion) {
completion();
}
}
else {
if (errorHandler) {
errorHandler(error);
}
}
}];
}];
}
@end