mirror of
https://github.com/zhigang1992/MagicalRecord.git
synced 2026-04-30 21:12:46 +08:00
Use performBlockAndWait for all context interactions
Renamed import methods to reflect id parameter (objects, not just dictionaries) Added findOrCreate pattern method Added error callback in default error handler method
This commit is contained in:
@@ -19,8 +19,10 @@ extern NSString * const kMagicalRecordImportRelationshipTypeKey;
|
|||||||
|
|
||||||
@interface NSManagedObject (MagicalRecord_DataImport)
|
@interface NSManagedObject (MagicalRecord_DataImport)
|
||||||
|
|
||||||
- (void) MR_importValuesForKeysWithDictionary:(id)objectData;
|
- (NSString *) MR_primaryKeyAttributeName;
|
||||||
- (void) MR_updateValuesForKeysWithDictionary:(id)objectData;
|
|
||||||
|
- (BOOL) MR_importValuesForKeysWithObject:(id)objectData;
|
||||||
|
- (BOOL) MR_updateValuesForKeysWithObject:(id)objectData;
|
||||||
|
|
||||||
+ (id) MR_importFromDictionary:(id)data;
|
+ (id) MR_importFromDictionary:(id)data;
|
||||||
+ (id) MR_importFromDictionary:(id)data inContext:(NSManagedObjectContext *)context;
|
+ (id) MR_importFromDictionary:(id)data inContext:(NSManagedObjectContext *)context;
|
||||||
|
|||||||
@@ -22,6 +22,11 @@ NSString * const kMagicalRecordImportRelationshipTypeKey = @"type";
|
|||||||
|
|
||||||
@implementation NSManagedObject (MagicalRecord_DataImport)
|
@implementation NSManagedObject (MagicalRecord_DataImport)
|
||||||
|
|
||||||
|
- (NSString *) MR_primaryKeyAttributeName;
|
||||||
|
{
|
||||||
|
return [[[self entity] MR_primaryKeyAttribute] name];
|
||||||
|
}
|
||||||
|
|
||||||
- (id) MR_valueForAttribute:(NSAttributeDescription *)attributeInfo fromObjectData:(NSDictionary *)objectData forKeyPath:(NSString *)keyPath
|
- (id) MR_valueForAttribute:(NSAttributeDescription *)attributeInfo fromObjectData:(NSDictionary *)objectData forKeyPath:(NSString *)keyPath
|
||||||
{
|
{
|
||||||
id value = [objectData valueForKeyPath:keyPath];
|
id value = [objectData valueForKeyPath:keyPath];
|
||||||
@@ -187,7 +192,12 @@ NSString * const kMagicalRecordImportRelationshipTypeKey = @"type";
|
|||||||
swizzle([objectData class], @selector(valueForUndefinedKey:), @selector(MR_valueForUndefinedKey:));
|
swizzle([objectData class], @selector(valueForUndefinedKey:), @selector(MR_valueForUndefinedKey:));
|
||||||
if ([self respondsToSelector:@selector(willImport)])
|
if ([self respondsToSelector:@selector(willImport)])
|
||||||
{
|
{
|
||||||
[self performSelector:@selector(willImport)];
|
BOOL shouldImport = (BOOL)[self performSelector:@selector(shouldImport:) withObject:objectData];
|
||||||
|
if (!shouldImport)
|
||||||
|
{
|
||||||
|
// NSLog(@"Not importing: %@", objectData);
|
||||||
|
return NO;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
NSDictionary *attributes = [[self entity] attributesByName];
|
NSDictionary *attributes = [[self entity] attributesByName];
|
||||||
|
|||||||
@@ -28,6 +28,10 @@
|
|||||||
|
|
||||||
+ (id) MR_createEntity;
|
+ (id) MR_createEntity;
|
||||||
+ (id) MR_createInContext:(NSManagedObjectContext *)context;
|
+ (id) MR_createInContext:(NSManagedObjectContext *)context;
|
||||||
|
|
||||||
|
+ (id) MR_findOrCreateByAttribute:(NSString *)attribute withValue:(id)value;
|
||||||
|
+ (id) MR_findOrCreateByAttribute:(NSString *)attribute withValue:(id)value inContext:(NSManagedObjectContext *)context;
|
||||||
|
|
||||||
- (BOOL) MR_deleteEntity;
|
- (BOOL) MR_deleteEntity;
|
||||||
- (BOOL) MR_deleteInContext:(NSManagedObjectContext *)context;
|
- (BOOL) MR_deleteInContext:(NSManagedObjectContext *)context;
|
||||||
|
|
||||||
|
|||||||
@@ -25,15 +25,20 @@ static NSUInteger defaultBatchSize = kMagicalRecordDefaultBatchSize;
|
|||||||
|
|
||||||
+ (NSArray *) MR_executeFetchRequest:(NSFetchRequest *)request inContext:(NSManagedObjectContext *)context
|
+ (NSArray *) MR_executeFetchRequest:(NSFetchRequest *)request inContext:(NSManagedObjectContext *)context
|
||||||
{
|
{
|
||||||
NSError *error = nil;
|
__block NSArray *results = nil;
|
||||||
|
[context performBlockAndWait:^{
|
||||||
NSArray *results = [context executeFetchRequest:request error:&error];
|
|
||||||
|
NSError *error = nil;
|
||||||
if (results == nil)
|
|
||||||
{
|
NSArray *innerResults = [context executeFetchRequest:request error:&error];
|
||||||
[MagicalRecordHelpers handleErrors:error];
|
|
||||||
}
|
if (innerResults == nil)
|
||||||
return results;
|
{
|
||||||
|
[MagicalRecordHelpers handleErrors:error];
|
||||||
|
}
|
||||||
|
results = innerResults;
|
||||||
|
}];
|
||||||
|
return results;
|
||||||
}
|
}
|
||||||
|
|
||||||
+ (NSArray *) MR_executeFetchRequest:(NSFetchRequest *)request
|
+ (NSArray *) MR_executeFetchRequest:(NSFetchRequest *)request
|
||||||
@@ -189,11 +194,14 @@ static NSUInteger defaultBatchSize = kMagicalRecordDefaultBatchSize;
|
|||||||
|
|
||||||
+ (NSUInteger) MR_countOfEntitiesWithContext:(NSManagedObjectContext *)context;
|
+ (NSUInteger) MR_countOfEntitiesWithContext:(NSManagedObjectContext *)context;
|
||||||
{
|
{
|
||||||
NSError *error = nil;
|
__block NSUInteger blockCount = -1;
|
||||||
NSUInteger count = [context countForFetchRequest:[self MR_createFetchRequestInContext:context] error:&error];
|
[context performBlockAndWait:^{
|
||||||
[MagicalRecordHelpers handleErrors:error];
|
NSError *error = nil;
|
||||||
|
blockCount = [context countForFetchRequest:[self MR_createFetchRequestInContext:context] error:&error];
|
||||||
return count;
|
[MagicalRecordHelpers handleErrors:error];
|
||||||
|
}];
|
||||||
|
|
||||||
|
return blockCount;
|
||||||
}
|
}
|
||||||
|
|
||||||
+ (NSUInteger) MR_countOfEntitiesWithPredicate:(NSPredicate *)searchFilter;
|
+ (NSUInteger) MR_countOfEntitiesWithPredicate:(NSPredicate *)searchFilter;
|
||||||
@@ -203,14 +211,17 @@ static NSUInteger defaultBatchSize = kMagicalRecordDefaultBatchSize;
|
|||||||
|
|
||||||
+ (NSUInteger) MR_countOfEntitiesWithPredicate:(NSPredicate *)searchFilter inContext:(NSManagedObjectContext *)context;
|
+ (NSUInteger) MR_countOfEntitiesWithPredicate:(NSPredicate *)searchFilter inContext:(NSManagedObjectContext *)context;
|
||||||
{
|
{
|
||||||
NSError *error = nil;
|
|
||||||
NSFetchRequest *request = [self MR_createFetchRequestInContext:context];
|
NSFetchRequest *request = [self MR_createFetchRequestInContext:context];
|
||||||
[request setPredicate:searchFilter];
|
[request setPredicate:searchFilter];
|
||||||
|
|
||||||
NSUInteger count = [context countForFetchRequest:request error:&error];
|
__block NSUInteger blockCount = -1;
|
||||||
[MagicalRecordHelpers handleErrors:error];
|
[context performBlockAndWait:^{
|
||||||
|
|
||||||
return count;
|
NSError *error = nil;
|
||||||
|
blockCount = [context countForFetchRequest:request error:&error];
|
||||||
|
[MagicalRecordHelpers handleErrors:error];
|
||||||
|
}];
|
||||||
|
return blockCount;
|
||||||
}
|
}
|
||||||
|
|
||||||
+ (BOOL) MR_hasAtLeastOneEntity
|
+ (BOOL) MR_hasAtLeastOneEntity
|
||||||
@@ -500,6 +511,23 @@ static NSUInteger defaultBatchSize = kMagicalRecordDefaultBatchSize;
|
|||||||
|
|
||||||
#pragma mark -
|
#pragma mark -
|
||||||
|
|
||||||
|
+ (id) MR_findOrCreateByAttribute:(NSString *)attribute withValue:(id)value;
|
||||||
|
{
|
||||||
|
return [self MR_findOrCreateByAttribute:attribute withValue:attribute inContext:[NSManagedObjectContext MR_contextForCurrentThread]];
|
||||||
|
}
|
||||||
|
|
||||||
|
+ (id) MR_findOrCreateByAttribute:(NSString *)attribute withValue:(id)value inContext:(NSManagedObjectContext *)context;
|
||||||
|
{
|
||||||
|
NSAssert([attribute rangeOfString:@"."].location == NSNotFound, @"Cannot autocreate an object using Key Value Coding");
|
||||||
|
NSManagedObject *managedObject = [self findFirstByAttribute:attribute withValue:value inContext:context];
|
||||||
|
if (managedObject == nil)
|
||||||
|
{
|
||||||
|
managedObject = [self createInContext:context];
|
||||||
|
[managedObject setValue:value forKey:attribute];
|
||||||
|
}
|
||||||
|
return managedObject;
|
||||||
|
}
|
||||||
|
|
||||||
+ (NSArray *) MR_findAllWithPredicate:(NSPredicate *)searchTerm inContext:(NSManagedObjectContext *)context
|
+ (NSArray *) MR_findAllWithPredicate:(NSPredicate *)searchTerm inContext:(NSManagedObjectContext *)context
|
||||||
{
|
{
|
||||||
NSFetchRequest *request = [self MR_createFetchRequestInContext:context];
|
NSFetchRequest *request = [self MR_createFetchRequestInContext:context];
|
||||||
@@ -767,7 +795,10 @@ static NSUInteger defaultBatchSize = kMagicalRecordDefaultBatchSize;
|
|||||||
{
|
{
|
||||||
NSError *error = nil;
|
NSError *error = nil;
|
||||||
NSManagedObject *inContext = [otherContext existingObjectWithID:[self objectID] error:&error];
|
NSManagedObject *inContext = [otherContext existingObjectWithID:[self objectID] error:&error];
|
||||||
[MagicalRecordHelpers handleErrors:error];
|
if (inContext == nil)
|
||||||
|
{
|
||||||
|
[MagicalRecordHelpers handleErrors:error];
|
||||||
|
}
|
||||||
|
|
||||||
return inContext;
|
return inContext;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -152,45 +152,35 @@ static void const * kMagicalRecordNotifiesMainContextAssociatedValueKey = @"kMag
|
|||||||
#ifdef NS_BLOCKS_AVAILABLE
|
#ifdef NS_BLOCKS_AVAILABLE
|
||||||
- (BOOL) MR_saveWithErrorHandler:(void (^)(NSError *))errorCallback;
|
- (BOOL) MR_saveWithErrorHandler:(void (^)(NSError *))errorCallback;
|
||||||
{
|
{
|
||||||
__block BOOL outerSaved = NO;
|
__block NSError *error = nil;
|
||||||
[self performBlockAndWait:^{
|
__block BOOL saved = NO;
|
||||||
NSError *error = nil;
|
|
||||||
BOOL saved = NO;
|
@try
|
||||||
|
{
|
||||||
@try
|
[self performBlockAndWait:^{
|
||||||
{
|
|
||||||
MRLog(@"Saving %@Context%@",
|
MRLog(@"Saving %@Context%@",
|
||||||
self == [[self class] MR_defaultContext] ? @" *** Default *** ": @"",
|
self == [[self class] MR_defaultContext] ? @" *** Default *** ": @"",
|
||||||
([NSThread isMainThread] ? @" *** on Main Thread ***" : @""));
|
([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]);
|
||||||
|
}
|
||||||
|
@finally
|
||||||
|
{
|
||||||
|
if (saved && [self respondsToSelector:@selector(parentContext)] && [self performSelector:@selector(parentContext)])
|
||||||
|
{
|
||||||
|
return saved && [[self parentContext] MR_saveWithErrorHandler:errorCallback];
|
||||||
}
|
}
|
||||||
@catch (NSException *exception)
|
@catch (NSException *exception)
|
||||||
{
|
{
|
||||||
MRLog(@"Problem saving: %@", (id)[exception userInfo] ?: (id)[exception reason]);
|
[MagicalRecordHelpers handleErrors:error callback:errorCallback];
|
||||||
}
|
}
|
||||||
@finally
|
return saved;
|
||||||
{
|
}
|
||||||
if (saved && [self respondsToSelector:@selector(parentContext)] && [self performSelector:@selector(parentContext)])
|
|
||||||
{
|
|
||||||
saved &= [[self parentContext] MR_saveWithErrorHandler:errorCallback];
|
|
||||||
}
|
|
||||||
if (!saved)
|
|
||||||
{
|
|
||||||
if (errorCallback)
|
|
||||||
{
|
|
||||||
errorCallback(error);
|
|
||||||
}
|
|
||||||
else if (error)
|
|
||||||
{
|
|
||||||
[MagicalRecordHelpers handleErrors:error];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
outerSaved = saved;
|
|
||||||
}
|
|
||||||
}];
|
|
||||||
return outerSaved;
|
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
|||||||
@@ -55,7 +55,7 @@ void cleanup_save_queue()
|
|||||||
NSPersistentStoreCoordinator *localCoordinator = [NSPersistentStoreCoordinator coordinatorWithPersitentStore:[NSPersistentStore defaultPersistentStore]];
|
NSPersistentStoreCoordinator *localCoordinator = [NSPersistentStoreCoordinator coordinatorWithPersitentStore:[NSPersistentStore defaultPersistentStore]];
|
||||||
localContext = [NSManagedObjectContext contextThatNotifiesDefaultContextOnMainThreadWithCoordinator:localCoordinator];
|
localContext = [NSManagedObjectContext contextThatNotifiesDefaultContextOnMainThreadWithCoordinator:localCoordinator];
|
||||||
#else
|
#else
|
||||||
localContext = [NSManagedObjectContext MR_contextThatNotifiesDefaultContextOnMainThread];
|
localContext = [NSManagedObjectContext MR_contextForCurrentThread];
|
||||||
[localContext MR_observeiCloudChangesInCoordinator:defaultCoordinator];
|
[localContext MR_observeiCloudChangesInCoordinator:defaultCoordinator];
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
|||||||
@@ -23,7 +23,8 @@ typedef void (^CoreDataBlock)(NSManagedObjectContext *context);
|
|||||||
+ (void) cleanUp;
|
+ (void) cleanUp;
|
||||||
|
|
||||||
+ (void) handleErrors:(NSError *)error;
|
+ (void) handleErrors:(NSError *)error;
|
||||||
- (void) handleErrors:(NSError *)error;
|
+ (void) handleErrors:(NSError *)error callback:(void(^)(NSError *))callback;
|
||||||
|
- (void) handleErrors:(NSError *)error callback:(void(^)(NSError *))callback;
|
||||||
|
|
||||||
+ (void) setErrorHandlerTarget:(id)target action:(SEL)action;
|
+ (void) setErrorHandlerTarget:(id)target action:(SEL)action;
|
||||||
+ (SEL) errorHandlerAction;
|
+ (SEL) errorHandlerAction;
|
||||||
|
|||||||
@@ -51,7 +51,7 @@ void replaceSelectorForTargetWithSourceImpAndSwizzle(Class originalClass, SEL or
|
|||||||
return status;
|
return status;
|
||||||
}
|
}
|
||||||
|
|
||||||
+ (void) defaultErrorHandler:(NSError *)error
|
+ (void) defaultErrorHandler:(NSError *)error callback:(void(^)(NSError *))errorCallback;
|
||||||
{
|
{
|
||||||
NSDictionary *userInfo = [error userInfo];
|
NSDictionary *userInfo = [error userInfo];
|
||||||
for (NSArray *detailedError in [userInfo allValues])
|
for (NSArray *detailedError in [userInfo allValues])
|
||||||
@@ -77,9 +77,19 @@ void replaceSelectorForTargetWithSourceImpAndSwizzle(Class originalClass, SEL or
|
|||||||
}
|
}
|
||||||
MRLog(@"Error Domain: %@", [error domain]);
|
MRLog(@"Error Domain: %@", [error domain]);
|
||||||
MRLog(@"Recovery Suggestion: %@", [error localizedRecoverySuggestion]);
|
MRLog(@"Recovery Suggestion: %@", [error localizedRecoverySuggestion]);
|
||||||
|
|
||||||
|
if (errorCallback)
|
||||||
|
{
|
||||||
|
errorCallback(error);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
+ (void) handleErrors:(NSError *)error
|
+ (void) defaultErrorHandler:(NSError *)error;
|
||||||
|
{
|
||||||
|
[self defaultErrorHandler:error callback:NULL];
|
||||||
|
}
|
||||||
|
|
||||||
|
+ (void) handleErrors:(NSError *)error callback:(void(^)(NSError *))callback
|
||||||
{
|
{
|
||||||
if (error)
|
if (error)
|
||||||
{
|
{
|
||||||
@@ -90,15 +100,25 @@ void replaceSelectorForTargetWithSourceImpAndSwizzle(Class originalClass, SEL or
|
|||||||
#pragma clang diagnostic ignored "-Warc-performSelector-leaks"
|
#pragma clang diagnostic ignored "-Warc-performSelector-leaks"
|
||||||
[errorHandlerTarget performSelector:errorHandlerAction withObject:error];
|
[errorHandlerTarget performSelector:errorHandlerAction withObject:error];
|
||||||
#pragma clang diagnostic pop
|
#pragma clang diagnostic pop
|
||||||
|
|
||||||
|
if (callback)
|
||||||
|
{
|
||||||
|
callback(error);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
// Otherwise, fall back to the default error handling
|
// Otherwise, fall back to the default error handling
|
||||||
[self defaultErrorHandler:error];
|
[self defaultErrorHandler:error callback:callback];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
+ (void) handleErrors:(NSError *)error;
|
||||||
|
{
|
||||||
|
[self handleErrors:error callback:NULL];
|
||||||
|
}
|
||||||
|
|
||||||
+ (id) errorHandlerTarget
|
+ (id) errorHandlerTarget
|
||||||
{
|
{
|
||||||
return errorHandlerTarget;
|
return errorHandlerTarget;
|
||||||
@@ -115,9 +135,9 @@ void replaceSelectorForTargetWithSourceImpAndSwizzle(Class originalClass, SEL or
|
|||||||
errorHandlerAction = action;
|
errorHandlerAction = action;
|
||||||
}
|
}
|
||||||
|
|
||||||
- (void) handleErrors:(NSError *)error
|
- (void) handleErrors:(NSError *)error callback:(void (^)(NSError *))callback;
|
||||||
{
|
{
|
||||||
[[self class] handleErrors:error];
|
[[self class] handleErrors:error callback:callback];
|
||||||
}
|
}
|
||||||
|
|
||||||
+ (void) setDefaultModelNamed:(NSString *)modelName;
|
+ (void) setDefaultModelNamed:(NSString *)modelName;
|
||||||
|
|||||||
Reference in New Issue
Block a user