mirror of
https://github.com/zhigang1992/MagicalRecord.git
synced 2026-01-12 17:32:18 +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)
|
||||
|
||||
- (void) MR_importValuesForKeysWithDictionary:(id)objectData;
|
||||
- (void) MR_updateValuesForKeysWithDictionary:(id)objectData;
|
||||
- (NSString *) MR_primaryKeyAttributeName;
|
||||
|
||||
- (BOOL) MR_importValuesForKeysWithObject:(id)objectData;
|
||||
- (BOOL) MR_updateValuesForKeysWithObject:(id)objectData;
|
||||
|
||||
+ (id) MR_importFromDictionary:(id)data;
|
||||
+ (id) MR_importFromDictionary:(id)data inContext:(NSManagedObjectContext *)context;
|
||||
|
||||
@@ -22,6 +22,11 @@ NSString * const kMagicalRecordImportRelationshipTypeKey = @"type";
|
||||
|
||||
@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 value = [objectData valueForKeyPath:keyPath];
|
||||
@@ -187,7 +192,12 @@ NSString * const kMagicalRecordImportRelationshipTypeKey = @"type";
|
||||
swizzle([objectData class], @selector(valueForUndefinedKey:), @selector(MR_valueForUndefinedKey:));
|
||||
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];
|
||||
|
||||
@@ -28,6 +28,10 @@
|
||||
|
||||
+ (id) MR_createEntity;
|
||||
+ (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_deleteInContext:(NSManagedObjectContext *)context;
|
||||
|
||||
|
||||
@@ -25,15 +25,20 @@ static NSUInteger defaultBatchSize = kMagicalRecordDefaultBatchSize;
|
||||
|
||||
+ (NSArray *) MR_executeFetchRequest:(NSFetchRequest *)request inContext:(NSManagedObjectContext *)context
|
||||
{
|
||||
NSError *error = nil;
|
||||
|
||||
NSArray *results = [context executeFetchRequest:request error:&error];
|
||||
|
||||
if (results == nil)
|
||||
{
|
||||
[MagicalRecordHelpers handleErrors:error];
|
||||
}
|
||||
return results;
|
||||
__block NSArray *results = nil;
|
||||
[context performBlockAndWait:^{
|
||||
|
||||
NSError *error = nil;
|
||||
|
||||
NSArray *innerResults = [context executeFetchRequest:request error:&error];
|
||||
|
||||
if (innerResults == nil)
|
||||
{
|
||||
[MagicalRecordHelpers handleErrors:error];
|
||||
}
|
||||
results = innerResults;
|
||||
}];
|
||||
return results;
|
||||
}
|
||||
|
||||
+ (NSArray *) MR_executeFetchRequest:(NSFetchRequest *)request
|
||||
@@ -189,11 +194,14 @@ static NSUInteger defaultBatchSize = kMagicalRecordDefaultBatchSize;
|
||||
|
||||
+ (NSUInteger) MR_countOfEntitiesWithContext:(NSManagedObjectContext *)context;
|
||||
{
|
||||
NSError *error = nil;
|
||||
NSUInteger count = [context countForFetchRequest:[self MR_createFetchRequestInContext:context] error:&error];
|
||||
[MagicalRecordHelpers handleErrors:error];
|
||||
|
||||
return count;
|
||||
__block NSUInteger blockCount = -1;
|
||||
[context performBlockAndWait:^{
|
||||
NSError *error = nil;
|
||||
blockCount = [context countForFetchRequest:[self MR_createFetchRequestInContext:context] error:&error];
|
||||
[MagicalRecordHelpers handleErrors:error];
|
||||
}];
|
||||
|
||||
return blockCount;
|
||||
}
|
||||
|
||||
+ (NSUInteger) MR_countOfEntitiesWithPredicate:(NSPredicate *)searchFilter;
|
||||
@@ -203,14 +211,17 @@ static NSUInteger defaultBatchSize = kMagicalRecordDefaultBatchSize;
|
||||
|
||||
+ (NSUInteger) MR_countOfEntitiesWithPredicate:(NSPredicate *)searchFilter inContext:(NSManagedObjectContext *)context;
|
||||
{
|
||||
NSError *error = nil;
|
||||
NSFetchRequest *request = [self MR_createFetchRequestInContext:context];
|
||||
[request setPredicate:searchFilter];
|
||||
|
||||
NSUInteger count = [context countForFetchRequest:request error:&error];
|
||||
[MagicalRecordHelpers handleErrors:error];
|
||||
|
||||
return count;
|
||||
__block NSUInteger blockCount = -1;
|
||||
[context performBlockAndWait:^{
|
||||
|
||||
NSError *error = nil;
|
||||
blockCount = [context countForFetchRequest:request error:&error];
|
||||
[MagicalRecordHelpers handleErrors:error];
|
||||
}];
|
||||
return blockCount;
|
||||
}
|
||||
|
||||
+ (BOOL) MR_hasAtLeastOneEntity
|
||||
@@ -500,6 +511,23 @@ static NSUInteger defaultBatchSize = kMagicalRecordDefaultBatchSize;
|
||||
|
||||
#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
|
||||
{
|
||||
NSFetchRequest *request = [self MR_createFetchRequestInContext:context];
|
||||
@@ -767,7 +795,10 @@ static NSUInteger defaultBatchSize = kMagicalRecordDefaultBatchSize;
|
||||
{
|
||||
NSError *error = nil;
|
||||
NSManagedObject *inContext = [otherContext existingObjectWithID:[self objectID] error:&error];
|
||||
[MagicalRecordHelpers handleErrors:error];
|
||||
if (inContext == nil)
|
||||
{
|
||||
[MagicalRecordHelpers handleErrors:error];
|
||||
}
|
||||
|
||||
return inContext;
|
||||
}
|
||||
|
||||
@@ -152,45 +152,35 @@ static void const * kMagicalRecordNotifiesMainContextAssociatedValueKey = @"kMag
|
||||
#ifdef NS_BLOCKS_AVAILABLE
|
||||
- (BOOL) MR_saveWithErrorHandler:(void (^)(NSError *))errorCallback;
|
||||
{
|
||||
__block BOOL outerSaved = NO;
|
||||
[self performBlockAndWait:^{
|
||||
NSError *error = nil;
|
||||
BOOL saved = NO;
|
||||
|
||||
@try
|
||||
{
|
||||
__block NSError *error = nil;
|
||||
__block BOOL saved = NO;
|
||||
|
||||
@try
|
||||
{
|
||||
[self performBlockAndWait:^{
|
||||
MRLog(@"Saving %@Context%@",
|
||||
self == [[self class] MR_defaultContext] ? @" *** Default *** ": @"",
|
||||
([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)
|
||||
{
|
||||
MRLog(@"Problem saving: %@", (id)[exception userInfo] ?: (id)[exception reason]);
|
||||
[MagicalRecordHelpers handleErrors:error callback:errorCallback];
|
||||
}
|
||||
@finally
|
||||
{
|
||||
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;
|
||||
return saved;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
@@ -55,7 +55,7 @@ void cleanup_save_queue()
|
||||
NSPersistentStoreCoordinator *localCoordinator = [NSPersistentStoreCoordinator coordinatorWithPersitentStore:[NSPersistentStore defaultPersistentStore]];
|
||||
localContext = [NSManagedObjectContext contextThatNotifiesDefaultContextOnMainThreadWithCoordinator:localCoordinator];
|
||||
#else
|
||||
localContext = [NSManagedObjectContext MR_contextThatNotifiesDefaultContextOnMainThread];
|
||||
localContext = [NSManagedObjectContext MR_contextForCurrentThread];
|
||||
[localContext MR_observeiCloudChangesInCoordinator:defaultCoordinator];
|
||||
#endif
|
||||
|
||||
|
||||
@@ -23,7 +23,8 @@ typedef void (^CoreDataBlock)(NSManagedObjectContext *context);
|
||||
+ (void) cleanUp;
|
||||
|
||||
+ (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;
|
||||
+ (SEL) errorHandlerAction;
|
||||
|
||||
@@ -51,7 +51,7 @@ void replaceSelectorForTargetWithSourceImpAndSwizzle(Class originalClass, SEL or
|
||||
return status;
|
||||
}
|
||||
|
||||
+ (void) defaultErrorHandler:(NSError *)error
|
||||
+ (void) defaultErrorHandler:(NSError *)error callback:(void(^)(NSError *))errorCallback;
|
||||
{
|
||||
NSDictionary *userInfo = [error userInfo];
|
||||
for (NSArray *detailedError in [userInfo allValues])
|
||||
@@ -77,9 +77,19 @@ void replaceSelectorForTargetWithSourceImpAndSwizzle(Class originalClass, SEL or
|
||||
}
|
||||
MRLog(@"Error Domain: %@", [error domain]);
|
||||
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)
|
||||
{
|
||||
@@ -90,15 +100,25 @@ void replaceSelectorForTargetWithSourceImpAndSwizzle(Class originalClass, SEL or
|
||||
#pragma clang diagnostic ignored "-Warc-performSelector-leaks"
|
||||
[errorHandlerTarget performSelector:errorHandlerAction withObject:error];
|
||||
#pragma clang diagnostic pop
|
||||
|
||||
if (callback)
|
||||
{
|
||||
callback(error);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// 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
|
||||
{
|
||||
return errorHandlerTarget;
|
||||
@@ -115,9 +135,9 @@ void replaceSelectorForTargetWithSourceImpAndSwizzle(Class originalClass, SEL or
|
||||
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;
|
||||
|
||||
Reference in New Issue
Block a user