mirror of
https://github.com/zhigang1992/MagicalRecord.git
synced 2026-01-12 09:13:42 +08:00
Implement new save methods
This commit is contained in:
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
Reference in New Issue
Block a user