Skip to content

Commit

Permalink
Merge branch 'hotfix/save-changes-for-2.1' into develop
Browse files Browse the repository at this point in the history
Conflicts:
	MagicalRecord/Categories/NSManagedObjectContext/NSManagedObjectContext+MagicalSaves.m
	Project Files/Magical Record.xcodeproj/project.pbxproj
  • Loading branch information
tonyarnold committed Dec 16, 2012
2 parents f25a5bc + 1af1201 commit 8faae62
Show file tree
Hide file tree
Showing 30 changed files with 1,923 additions and 321 deletions.
30 changes: 13 additions & 17 deletions .gitignore
@@ -1,23 +1,19 @@
# Finder
.DS_Store
*.swp
*~.nib

build/

# Xcode
build/*
*.pbxuser
*.perspective
*.perspectivev3

.hg
.hgtags

!default.pbxuser
*.mode1v3
!default.mode1v3
*.mode2v3
!default.mode2v3
*.perspectivev3
!default.perspectivev3
*.xcworkspace
!default.xcworkspace
xcuserdata
profile
*.moved-aside

UserInterfaceState.xcuserstate
/Magical Record.xcodeproj/project.xcworkspace/xcuserdata/saul.xcuserdatad/UserInterfaceState.xcuserstate
/Magical Record.xcodeproj/xcuserdata/saul.xcuserdatad/xcdebugger/Breakpoints.xcbkptlist
/Magical Record.xcodeproj/xcuserdata/gfurman.xcuserdatad
Project Files/Magical Record.xcodeproj/xcuserdata
Project Files/MagicalRecord.xcodeproj/xcuserdata/saul.xcuserdatad/xcdebugger/Breakpoints.xcbkptlist
Project Files/MagicalRecord.xcodeproj/xcuserdata/saul.xcuserdatad/xcschemes/iOS Test Runner.xcscheme
3 changes: 3 additions & 0 deletions .gitmodules
@@ -0,0 +1,3 @@
[submodule "Project Files/Third Party/Kiwi"]
path = Project Files/Third Party/Kiwi
url = git://github.com/allending/Kiwi.git
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 *error))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 *error))errorCallback __attribute__((deprecated));
- (void) MR_saveInBackgroundErrorHandler:(void (^)(NSError *error))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 *error))errorCallback __attribute__((deprecated));
- (void) MR_saveNestedContextsErrorHandler:(void (^)(NSError *error))errorCallback completion:(void (^)(void))completion __attribute__((deprecated));

@end
Expand Up @@ -11,114 +11,186 @@
#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])
{
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]);
MRLog(@"→ Save Parents? %@", @(saveParentContexts));
MRLog(@"→ Save Synchronously? %@", @(syncSave));

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

#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Wdeprecated-implementations"

- (void)MR_save;
{
[self MR_saveNestedContextsErrorHandler:nil];
[self MR_saveToPersistentStoreAndWait];
}

- (void) MR_saveNestedContextsErrorHandler:(void (^)(NSError *))errorCallback;
- (void)MR_saveWithErrorCallback:(void (^)(NSError *error))errorCallback;
{
[self MR_saveNestedContextsErrorHandler:errorCallback completion:nil];
[self MR_saveWithOptions:MRSaveSynchronously|MRSaveParentContexts completion:^(BOOL success, NSError *error) {
if (!success) {
if (errorCallback) {
errorCallback(error);
}
}
}];
}

- (void) MR_saveNestedContextsErrorHandler:(void (^)(NSError *))errorCallback completion:(void (^)(void))completion;
- (void)MR_saveInBackgroundCompletion:(void (^)(void))completion;
{
[self performBlock:^{
[self MR_saveWithErrorCallback:errorCallback];
if ([self parentContext])
{
[[self parentContext] performBlock:^{
[[self parentContext] MR_saveNestedContextsErrorHandler:errorCallback completion:completion];
}];
}
else if (completion)
{
dispatch_async(dispatch_get_main_queue(), completion);
[self MR_saveOnlySelfWithCompletion:^(BOOL success, NSError *error) {
if (success) {
if (completion) {
completion();
}
}
}];
}

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

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

- (void) MR_saveInBackgroundErrorHandler:(void (^)(NSError *))errorCallback;
- (void)MR_saveNestedContexts;
{
[self MR_saveInBackgroundErrorHandler:errorCallback completion:nil];
[self MR_saveToPersistentStoreWithCompletion:nil];
}

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

#pragma clang diagnostic pop // ignored "-Wdeprecated-implementations"

@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) saveUsingCurrentThreadContextWithBlock:(void (^)(NSManagedObjectContext *localContext))block completion:(MRSaveCompletionHandler)completion;
+ (void) saveUsingCurrentThreadContextWithBlockAndWait:(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 *error))errorHandler __attribute__((deprecated));

@end

0 comments on commit 8faae62

Please sign in to comment.