Skip to content

Commit

Permalink
Implement new save methods
Browse files Browse the repository at this point in the history
  • Loading branch information
tonyarnold committed Dec 16, 2012
1 parent fb81b5b commit 4f35e4e
Show file tree
Hide file tree
Showing 4 changed files with 274 additions and 110 deletions.
Expand Up @@ -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;

// Synchronous saving
- (void) MR_saveOnlySelfAndWait;
- (void) MR_saveToPersistentStoreAndWait;

// 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;
- (void) MR_saveInBackgroundErrorHandler:(void (^)(NSError *))errorCallback;
- (void) MR_saveInBackgroundErrorHandler:(void (^)(NSError *))errorCallback completion:(void (^)(void))completion;
- (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;
- (void) MR_saveNestedContextsErrorHandler:(void (^)(NSError *))errorCallback;
- (void) MR_saveNestedContextsErrorHandler:(void (^)(NSError *))errorCallback completion:(void (^)(void))completion;
- (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
Expand Up @@ -11,115 +11,180 @@
#import "NSManagedObjectContext+MagicalRecord.h"
#import "MagicalRecord.h"

@interface NSManagedObjectContext (InternalMagicalSaves)
@implementation NSManagedObjectContext (MagicalSaves)

- (void) MR_saveWithErrorCallback:(void(^)(NSError *))errorCallback;
- (void)MR_saveOnlySelfWithCompletion:(MRSaveCompletionHandler)completion;
{
[self MR_saveWithOptions:0 completion:completion];
}

@end
- (void)MR_saveOnlySelfAndWait;
{
[self MR_saveWithOptions:MRSaveSynchronously completion:nil];
}

- (void) MR_saveToPersistentStoreWithCompletion:(MRSaveCompletionHandler)completion;
{
[self MR_saveWithOptions:MRSaveParentContexts completion:completion];
}

@implementation NSManagedObjectContext (MagicalSaves)
- (void) MR_saveToPersistentStoreAndWait;
{
[self MR_saveWithOptions:MRSaveParentContexts | MRSaveSynchronously completion:nil];
}

- (void) MR_saveWithErrorCallback:(void(^)(NSError *))errorCallback;
- (void)MR_saveWithOptions:(MRSaveContextOptions)mask completion:(MRSaveCompletionHandler)completion;
{
if (![self hasChanges])
{
MRLog(@"NO CHANGES IN CONTEXT %@ - NOT SAVING", [self MR_description]);
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:^{

MRLog(@"→ Saving %@", [self MR_description]);

id saveBlock = ^{
NSError *error = nil;
BOOL saved = NO;

@try
{
saved = [self save:&error];
}];
}
@catch (NSException *exception)
{
MRLog(@"Unable to perform save: %@", (id)[exception userInfo] ?: (id)[exception reason]);
}
@finally
{
if (!saved)
}
@catch(NSException *exception)
{
if (errorCallback)
{
errorCallback(error);
}
else
{
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;
- (void)MR_saveWithErrorCallback:(void (^)(NSError *))errorCallback __attribute__((deprecated));

{
[self MR_saveInBackgroundErrorHandler:nil completion:completion];
[self MR_saveWithOptions:MRSaveSynchronously completion:^(BOOL success, NSError *error) {
if (!success) {
if (errorCallback) {
errorCallback(error);
}
}
}];
}

- (void) MR_saveInBackgroundErrorHandler:(void (^)(NSError *))errorCallback;
- (void)MR_saveInBackgroundCompletion:(void (^)(void))completion;
{
[self MR_saveInBackgroundErrorHandler:errorCallback completion:nil];
[self MR_saveOnlySelfWithCompletion:^(BOOL success, NSError *error) {
if (success) {
if (completion) {
completion();
}
}
}];
}

- (void) MR_saveInBackgroundErrorHandler:(void (^)(NSError *))errorCallback completion:(void (^)(void))completion;
- (void)MR_saveInBackgroundErrorHandler:(void (^)(NSError *))errorCallback;
{
[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];
[self MR_saveOnlySelfWithCompletion:^(BOOL success, NSError *error) {
if (!success) {
if (errorCallback) {
errorCallback(error);
}
}
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);
}];
}

- (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
25 changes: 21 additions & 4 deletions MagicalRecord/Core/MagicalRecord+Actions.h
Expand Up @@ -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

0 comments on commit 4f35e4e

Please sign in to comment.