Merge branch 'master' of magicalpanda.github.com:magicalpanda/MagicalRecord

This commit is contained in:
Saul Mora
2011-12-04 13:31:10 -05:00
17 changed files with 473 additions and 165 deletions

19
MagicalRecord.podspec Normal file
View File

@@ -0,0 +1,19 @@
Pod::Spec.new do |s|
s.name = 'MagicalRecord'
s.version = '1.8'
s.license = 'MIT'
s.summary = 'Super Awesome Easy Fetching for Core Data 1!!!11!!!!1! '
s.homepage = 'http://github.com/magicalpanda/MagicalRecord'
s.author = { 'Saul Mora' => 'saul@magicalpanda.com' }
s.source = { :git => 'http://github.com/magicalpanda/MagicalRecord.git', :tag => '1.8' }
s.description = 'Handy fetching, threading and data import helpers to make Core Data a little easier to use.'
s.source_files = 'Source/**/*.{h,m}'
s.framework = 'CoreData'
def s.post_install(target)
prefix_header = config.project_pods_root + target.prefix_header_filename
prefix_header.open('a') do |file|
file.puts(%{#ifdef __OBJC__\n#define MR_SHORTHAND 1\n#import "CoreData+MagicalRecord.h"\n#endif})
end
end
end

View File

@@ -17,10 +17,7 @@ NSString * const kMagicalRecordImportPrimaryAttributeKey = @"primaryAttributeKey
NSString *lookupKey = [[self userInfo] valueForKey:kMagicalRecordImportPrimaryAttributeKey] ?: primaryKeyNameFromString([self name]);
NSAttributeDescription *primaryAttribute = [[self attributesByName] valueForKey:lookupKey];
if (primaryAttribute == nil)
{
NSAssert3(primaryAttribute != nil, @"Unable to determine primary attribute for %@. Specify either an attribute named %@ or the primary key in userInfo named '%@'", [self name], primaryKeyNameFromString([self name]), kMagicalRecordImportPrimaryAttributeKey);
}
NSAssert3(primaryAttribute != nil, @"Unable to determine primary attribute for %@. Specify either an attribute named %@ or the primary key in userInfo named '%@'", [self name], primaryKeyNameFromString([self name]), kMagicalRecordImportPrimaryAttributeKey);
return primaryAttribute;
}

View File

@@ -8,7 +8,7 @@
#import <Foundation/Foundation.h>
@interface NSDictionary (MagicalRecord_DataImport)
@interface NSObject (MagicalRecord_DataImport)
- (NSString *) MR_lookupKeyForAttribute:(NSAttributeDescription *)attributeInfo;
- (id) MR_valueForAttribute:(NSAttributeDescription *)attributeInfo;

View File

@@ -6,12 +6,22 @@
// Copyright 2011 Magical Panda Software LLC. All rights reserved.
//
#import "NSDictionary+MagicalDataImport.h"
#import "NSObject+MagicalDataImport.h"
NSUInteger const kMagicalRecordImportMaximumAttributeFailoverDepth = 10;
@implementation NSDictionary (MagicalRecord_DataImport)
@implementation NSObject (MagicalRecord_DataImport)
//#warning If you implement valueForUndefinedKey: in any NSObject in your code, this may be the problem if something broke
//TODO: This method needs to be:
// 1) Renamed to MR_valueForUndefinedKey:
// 2) swizzled in and out only when importing data.
// This will be done in a really short update...stay tuned
- (id) MR_valueForUndefinedKey:(NSString *)key
{
return nil;
}
- (NSString *) MR_lookupKeyForAttribute:(NSAttributeDescription *)attributeInfo;
{
@@ -45,7 +55,7 @@ NSUInteger const kMagicalRecordImportMaximumAttributeFailoverDepth = 10;
NSEntityDescription *destinationEntity = [relationshipInfo destinationEntity];
if (destinationEntity == nil)
{
ARLog(@"Unable to find entity for type '%@'", [self valueForKey:kMagicalRecordImportRelationshipTypeKey]);
MRLog(@"Unable to find entity for type '%@'", [self valueForKey:kMagicalRecordImportRelationshipTypeKey]);
return nil;
}

View File

@@ -19,16 +19,16 @@ extern NSString * const kMagicalRecordImportRelationshipTypeKey;
@interface NSManagedObject (NSManagedObject_DataImport)
- (void) MR_importValuesForKeysWithDictionary:(NSDictionary *)objectData;
- (void) MR_updateValuesForKeysWithDictionary:(NSDictionary *)objectData;
- (void) MR_importValuesForKeysWithDictionary:(id)objectData;
- (void) MR_updateValuesForKeysWithDictionary:(id)objectData;
+ (id) MR_importFromDictionary:(NSDictionary *)data;
+ (id) MR_importFromDictionary:(NSDictionary *)data inContext:(NSManagedObjectContext *)context;
+ (id) MR_importFromDictionary:(id)data;
+ (id) MR_importFromDictionary:(id)data inContext:(NSManagedObjectContext *)context;
+ (NSArray *) MR_importFromArray:(NSArray *)listOfObjectData;
+ (NSArray *) MR_importFromArray:(NSArray *)listOfObjectData inContext:(NSManagedObjectContext *)context;
+ (id) MR_updateFromDictionary:(NSDictionary *)objectData;
+ (id) MR_updateFromDictionary:(NSDictionary *)objectData inContext:(NSManagedObjectContext *)context;
+ (id) MR_updateFromDictionary:(id)objectData;
+ (id) MR_updateFromDictionary:(id)objectData inContext:(NSManagedObjectContext *)context;
@end

View File

@@ -7,6 +7,9 @@
//
#import "CoreData+MagicalRecord.h"
#import <objc/runtime.h>
void swizzle(Class c, SEL orig, SEL new);
NSString * const kMagicalRecordImportCustomDateFormatKey = @"dateFormat";
NSString * const kMagicalRecordImportDefaultDateFormatString = @"yyyy-MM-dd'T'HH:mm:ss'Z'";
@@ -17,7 +20,15 @@ NSString * const kMagicalRecordImportRelationshipMapKey = @"mappedKeyName";
NSString * const kMagicalRecordImportRelationshipPrimaryKey = @"primaryRelationshipKey";
NSString * const kMagicalRecordImportRelationshipTypeKey = @"type";
@implementation NSString (MagicalRecord_DataImport)
- (NSString *) MR_capitalizedFirstCharaterString;
{
NSString *firstChar = [[self substringToIndex:1] capitalizedString];
return [firstChar stringByAppendingString:[self substringFromIndex:1]];
}
@end
@implementation NSManagedObject (MagicalRecord_DataImport)
@@ -50,6 +61,18 @@ NSString * const kMagicalRecordImportRelationshipTypeKey = @"type";
return value == [NSNull null] ? nil : value;
}
- (BOOL) MR_importValue:(id)value forKey:(NSString *)key
{
NSString *selectorString = [NSString stringWithFormat:@"import%@:", [key MR_capitalizedFirstCharaterString]];
SEL selector = NSSelectorFromString(selectorString);
if ([self respondsToSelector:selector])
{
[self performSelector:selector withObject:value];
return YES;
}
return NO;
}
- (void) MR_setAttributes:(NSDictionary *)attributes forKeysWithDictionary:(NSDictionary *)objectData
{
for (NSString *attributeName in attributes)
@@ -60,7 +83,10 @@ NSString * const kMagicalRecordImportRelationshipTypeKey = @"type";
if (lookupKeyPath)
{
id value = [self MR_valueForAttribute:attributeInfo fromObjectData:objectData forKeyPath:lookupKeyPath];
[self setValue:value forKey:attributeName];
if (![self MR_importValue:value forKey:attributeName])
{
[self setValue:value forKey:attributeName];
}
}
}
}
@@ -89,7 +115,20 @@ NSString * const kMagicalRecordImportRelationshipTypeKey = @"type";
NSAssert2([relatedObject entity] == [relationshipInfo destinationEntity], @"related object entity %@ not same as destination entity %@", [relatedObject entity], [relationshipInfo destinationEntity]);
//add related object to set
NSString *addRelationMessageFormat = [relationshipInfo isToMany] ? @"add%@Object:" : @"set%@:";
NSString *addRelationMessageFormat = @"set%@:";
id relationshipSource = self;
if ([relationshipInfo isToMany])
{
addRelationMessageFormat = @"add%@Object:";
if ([relationshipInfo isOrdered])
{
//Need to get the ordered set
NSString *selectorName = [[relationshipInfo name] stringByAppendingString:@"Set"];
relationshipSource = [self performSelector:NSSelectorFromString(selectorName)];
addRelationMessageFormat = @"addObject:";
}
}
NSString *addRelatedObjectToSetMessage = [NSString stringWithFormat:addRelationMessageFormat, attributeNameFromString([relationshipInfo name])];
SEL selector = NSSelectorFromString(addRelatedObjectToSetMessage);
@@ -98,16 +137,16 @@ NSString * const kMagicalRecordImportRelationshipTypeKey = @"type";
{
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Warc-performSelector-leaks"
[self performSelector:selector withObject:relatedObject];
[relationshipSource performSelector:selector withObject:relatedObject];
#pragma clang diagnostic pop
}
@catch (NSException *exception)
{
ARLog(@"Adding object for relationship failed: %@\n", relationshipInfo);
ARLog(@"relatedObject.entity %@", [relatedObject entity]);
ARLog(@"relationshipInfo.destinationEntity %@", [relationshipInfo destinationEntity]);
ARLog(@"perform selector error: %@", exception);
MRLog(@"Adding object for relationship failed: %@\n", relationshipInfo);
MRLog(@"relatedObject.entity %@", [relatedObject entity]);
MRLog(@"relationshipInfo.destinationEntity %@", [relationshipInfo destinationEntity]);
MRLog(@"Add Relationship Selector: %@", addRelatedObjectToSetMessage);
MRLog(@"perform selector error: %@", exception);
}
}
@@ -125,31 +164,50 @@ NSString * const kMagicalRecordImportRelationshipTypeKey = @"type";
{
continue;
}
SEL shouldImportSelector = @selector(shouldImport:);
BOOL implementsShouldImport = [self respondsToSelector:shouldImportSelector];
if ([relationshipInfo isToMany])
if (![self MR_importValue:relatedObjectData forKey:relationshipName])
{
for (id singleRelatedObjectData in relatedObjectData)
if ([relationshipInfo isToMany])
{
setRelationshipBlock(relationshipInfo, singleRelatedObjectData);
for (id singleRelatedObjectData in relatedObjectData)
{
if (implementsShouldImport && !(BOOL)[self performSelector:shouldImportSelector withObject:singleRelatedObjectData])
{
continue;
}
setRelationshipBlock(relationshipInfo, singleRelatedObjectData);
}
}
else
{
if (!(implementsShouldImport && !(BOOL)[self performSelector:shouldImportSelector withObject:relatedObjectData]))
{
setRelationshipBlock(relationshipInfo, relatedObjectData);
}
}
}
else
{
setRelationshipBlock(relationshipInfo, relatedObjectData);
}
}
}
- (void) MR_importValuesForKeysWithDictionary:(NSDictionary *)objectData
- (void) MR_importValuesForKeysWithDictionary:(id)objectData
{
swizzle([objectData class], @selector(valueForUndefinedKey:), @selector(MR_valueForUndefinedKey:));
if ([self respondsToSelector:@selector(willImport)])
{
[self performSelector:@selector(willImport)];
}
NSDictionary *attributes = [[self entity] attributesByName];
[self MR_setAttributes:attributes forKeysWithDictionary:objectData];
NSDictionary *relationships = [[self entity] relationshipsByName];
[self MR_setRelationships:relationships
forKeysWithDictionary:objectData
withBlock:^(NSRelationshipDescription *relationshipInfo, id objectData)
{
withBlock:^(NSRelationshipDescription *relationshipInfo, id objectData){
NSManagedObject *relatedObject = nil;
if ([objectData isKindOfClass:[NSDictionary class]])
{
@@ -162,19 +220,31 @@ NSString * const kMagicalRecordImportRelationshipTypeKey = @"type";
[relatedObject MR_importValuesForKeysWithDictionary:objectData];
[self MR_addObject:relatedObject forRelationship:relationshipInfo];
}];
}];
swizzle([objectData class], @selector(valueForUndefinedKey:), @selector(MR_valueForUndefinedKey:));
if ([self respondsToSelector:@selector(didImport)])
{
[self performSelector:@selector(didImport)];
}
}
- (void) MR_updateValuesForKeysWithDictionary:(NSDictionary *)objectData
- (void) MR_updateValuesForKeysWithDictionary:(id)objectData
{
swizzle([objectData class], @selector(valueForUndefinedKey:), @selector(MR_valueForUndefinedKey:));
if ([self respondsToSelector:@selector(willImport)])
{
[self performSelector:@selector(willImport)];
}
NSDictionary *attributes = [[self entity] attributesByName];
[self MR_setAttributes:attributes forKeysWithDictionary:objectData];
NSDictionary *relationships = [[self entity] relationshipsByName];
[self MR_setRelationships:relationships
forKeysWithDictionary:objectData
withBlock:^(NSRelationshipDescription *relationshipInfo, id objectData)
{
withBlock:^(NSRelationshipDescription *relationshipInfo, id objectData) {
NSManagedObject *relatedObject = [self MR_findObjectForRelationship:relationshipInfo
withData:objectData];
if (relatedObject == nil)
@@ -187,22 +257,29 @@ NSString * const kMagicalRecordImportRelationshipTypeKey = @"type";
}
[self MR_addObject:relatedObject forRelationship:relationshipInfo];
}];
}];
swizzle([objectData class], @selector(valueForUndefinedKey:), @selector(MR_valueForUndefinedKey:));
if ([self respondsToSelector:@selector(didImport)])
{
[self performSelector:@selector(didImport)];
}
}
+ (id) MR_importFromDictionary:(NSDictionary *)objectData inContext:(NSManagedObjectContext *)context;
+ (id) MR_importFromDictionary:(id)objectData inContext:(NSManagedObjectContext *)context;
{
NSManagedObject *managedObject = [self MR_createInContext:context];
[managedObject MR_importValuesForKeysWithDictionary:objectData];
return managedObject;
}
+ (id) MR_importFromDictionary:(NSDictionary *)objectData
+ (id) MR_importFromDictionary:(id)objectData
{
return [self MR_importFromDictionary:objectData inContext:[NSManagedObjectContext MR_defaultContext]];
}
+ (id) MR_updateFromDictionary:(NSDictionary *)objectData inContext:(NSManagedObjectContext *)context
+ (id) MR_updateFromDictionary:(id)objectData inContext:(NSManagedObjectContext *)context
{
NSAttributeDescription *primaryAttribute = [[self MR_entityDescription] MR_primaryKeyAttribute];
@@ -221,7 +298,7 @@ NSString * const kMagicalRecordImportRelationshipTypeKey = @"type";
return managedObject;
}
+ (id) MR_updateFromDictionary:(NSDictionary *)objectData
+ (id) MR_updateFromDictionary:(id)objectData
{
return [self MR_updateFromDictionary:objectData inContext:[NSManagedObjectContext MR_defaultContext]];
}
@@ -253,3 +330,18 @@ NSString * const kMagicalRecordImportRelationshipTypeKey = @"type";
}
@end
void swizzle(Class c, SEL orig, SEL new)
{
Method origMethod = class_getInstanceMethod(c, orig);
Method newMethod = class_getInstanceMethod(c, new);
if (class_addMethod(c, orig, method_getImplementation(newMethod), method_getTypeEncoding(newMethod)))
{
class_replaceMethod(c, new, method_getImplementation(origMethod), method_getTypeEncoding(origMethod));
}
else
{
method_exchangeImplementations(origMethod, newMethod);
}
}

View File

@@ -71,7 +71,7 @@ static NSUInteger defaultBatchSize = kMagicalRecordDefaultBatchSize;
#endif
+ (NSString *) entityName
+ (NSString *) MR_entityName
{
return NSStringFromClass(self);
}
@@ -85,7 +85,7 @@ static NSUInteger defaultBatchSize = kMagicalRecordDefaultBatchSize;
}
else
{
NSString *entityName = [self entityName];
NSString *entityName = [self MR_entityName];
return [NSEntityDescription entityForName:entityName inManagedObjectContext:context];
}
}
@@ -113,7 +113,7 @@ static NSUInteger defaultBatchSize = kMagicalRecordDefaultBatchSize;
}
else
{
ARLog(@"Property '%@' not found in %@ properties for %@", propertyName, [propDict count], NSStringFromClass(self));
MRLog(@"Property '%@' not found in %@ properties for %@", propertyName, [propDict count], NSStringFromClass(self));
}
}
}
@@ -166,7 +166,7 @@ static NSUInteger defaultBatchSize = kMagicalRecordDefaultBatchSize;
return [NSNumber numberWithUnsignedInteger:[self MR_countOfEntitiesWithContext:context]];
}
+ (NSNumber *)MR_numberOfEntities
+ (NSNumber *) MR_numberOfEntities
{
return [self MR_numberOfEntitiesWithContext:[NSManagedObjectContext MR_contextForCurrentThread]];
}
@@ -224,8 +224,8 @@ static NSUInteger defaultBatchSize = kMagicalRecordDefaultBatchSize;
return [[self MR_numberOfEntitiesWithContext:context] intValue] > 0;
}
#pragma mark -
#pragma mark Reqest Helpers
#pragma mark - Reqest Helpers
+ (NSFetchRequest *) MR_requestAll
{
return [self MR_createFetchRequestInContext:[NSManagedObjectContext MR_contextForCurrentThread]];
@@ -418,7 +418,7 @@ static NSUInteger defaultBatchSize = kMagicalRecordDefaultBatchSize;
groupedBy:group
inContext:context];
[self performFetch:controller];
[self MR_performFetch:controller];
return controller;
}
@@ -653,7 +653,7 @@ static NSUInteger defaultBatchSize = kMagicalRecordDefaultBatchSize;
}
else
{
return [NSEntityDescription insertNewObjectForEntityForName:[self entityName] inManagedObjectContext:context];
return [NSEntityDescription insertNewObjectForEntityForName:[self MR_entityName] inManagedObjectContext:context];
}
}
@@ -747,16 +747,16 @@ static NSUInteger defaultBatchSize = kMagicalRecordDefaultBatchSize;
[ed setExpression:ex];
// determine the type of attribute, required to set the expression return type
NSAttributeDescription *attributeDescription = [[[self entityDescription] attributesByName] objectForKey:attributeName];
NSAttributeDescription *attributeDescription = [[[self MR_entityDescription] attributesByName] objectForKey:attributeName];
[ed setExpressionResultType:[attributeDescription attributeType]];
NSArray *properties = [NSArray arrayWithObject:ed];
MR_RELEASE(ed);
NSFetchRequest *request = [self requestAllWithPredicate:predicate inContext:context];
NSFetchRequest *request = [self MR_requestAllWithPredicate:predicate inContext:context];
[request setPropertiesToFetch:properties];
[request setResultType:NSDictionaryResultType];
NSDictionary *resultsDictionary = [self executeFetchRequestAndReturnFirstObject:request];
NSDictionary *resultsDictionary = [self MR_executeFetchRequestAndReturnFirstObject:request];
NSNumber *resultValue = [resultsDictionary objectForKey:@"result"];
return resultValue;
@@ -767,7 +767,7 @@ static NSUInteger defaultBatchSize = kMagicalRecordDefaultBatchSize;
return [self aggregateOperation:function
onAttribute:attributeName
withPredicate:predicate
inContext:[NSManagedObjectContext defaultContext]];
inContext:[NSManagedObjectContext MR_defaultContext]];
}
- (id) MR_inContext:(NSManagedObjectContext *)otherContext

View File

@@ -7,11 +7,14 @@
#import "MagicalRecordHelpers.h"
extern NSString * const kMagicalRecordDidMergeChangesFromiCloudNotification;
@interface NSManagedObjectContext (MagicalRecord)
- (void) MR_observeContext:(NSManagedObjectContext *)otherContext;
- (void) MR_stopObservingContext:(NSManagedObjectContext *)otherContext;
- (void) MR_observeContextOnMainThread:(NSManagedObjectContext *)otherContext;
- (void) MR_observeiCloudChangesInCoordinator:(NSPersistentStoreCoordinator *)coordinator;
- (BOOL) MR_save;
@@ -34,7 +37,7 @@
+ (NSManagedObjectContext *) MR_contextThatNotifiesDefaultContextOnMainThreadWithCoordinator:(NSPersistentStoreCoordinator *)coordinator;
+ (NSManagedObjectContext *) MR_contextWithStoreCoordinator:(NSPersistentStoreCoordinator *)coordinator;
@property (nonatomic, assign) BOOL MR_notifiesMainContextOnSave;
@property (nonatomic, assign, setter=MR_setNotifiesMainContextOnSave:) BOOL MR_notifiesMainContextOnSave;
@end

View File

@@ -10,11 +10,12 @@
static NSManagedObjectContext *defaultManageObjectContext_ = nil;
static NSString const * kMagicalRecordManagedObjectContextKey = @"MagicalRecord_NSManagedObjectContextForThreadKey";
NSString * const kMagicalRecordDidMergeChangesFromiCloudNotification = @"kMagicalRecordDidMergeChangesFromiCloudNotification";
@interface NSManagedObjectContext ()
@interface NSManagedObjectContext (MagicalRecordPrivate)
- (void) mergeChangesFromNotification:(NSNotification *)notification;
- (void) mergeChangesOnMainThread:(NSNotification *)notification;
- (void) MR_mergeChangesFromNotification:(NSNotification *)notification;
- (void) MR_mergeChangesOnMainThread:(NSNotification *)notification;
@end
@@ -51,85 +52,92 @@ static NSString const * kMagicalRecordManagedObjectContextKey = @"MagicalRecord_
[[NSManagedObjectContext MR_contextForCurrentThread] reset];
}
+ (NSManagedObjectContext *)MR_contextForCurrentThread
{
if ([NSThread isMainThread])
{
return [self MR_defaultContext];
}
else
{
NSMutableDictionary *threadDict = [[NSThread currentThread] threadDictionary];
NSManagedObjectContext *threadContext = [threadDict objectForKey:kMagicalRecordManagedObjectContextKey];
if (threadContext == nil)
{
threadContext = [self MR_contextThatNotifiesDefaultContextOnMainThread];
[threadDict setObject:threadContext forKey:kMagicalRecordManagedObjectContextKey];
}
return threadContext;
}
}
- (void) MR_observeContext:(NSManagedObjectContext *)otherContext
{
[[NSNotificationCenter defaultCenter] addObserver:self
selector:@selector(mergeChangesFromNotification:)
selector:@selector(MR_mergeChangesFromNotification:)
name:NSManagedObjectContextDidSaveNotification
object:otherContext];
}
- (void) MR_observeContextOnMainThread:(NSManagedObjectContext *)otherContext
{
// ARLog(@"Start Observing on Main Thread");
// MRLog(@"Start Observing on Main Thread");
[[NSNotificationCenter defaultCenter] addObserver:self
selector:@selector(mergeChangesOnMainThread:)
selector:@selector(MR_mergeChangesOnMainThread:)
name:NSManagedObjectContextDidSaveNotification
object:otherContext];
}
- (void) MR_stopObservingContext:(NSManagedObjectContext *)otherContext
{
// ARLog(@"Stop Observing Context");
// MRLog(@"Stop Observing Context");
[[NSNotificationCenter defaultCenter] removeObserver:self
name:NSManagedObjectContextDidSaveNotification
object:otherContext];
}
- (void) mergeChangesFromNotification:(NSNotification *)notification
#pragma mark - Merge Helpers
- (void) MR_observeiCloudChangesInCoordinator:(NSPersistentStoreCoordinator *)coordinator;
{
ARLog(@"Merging changes to %@context%@",
[[NSNotificationCenter defaultCenter] addObserver:self
selector:@selector(MR_mergeChangesFromiCloud:)
name:NSPersistentStoreDidImportUbiquitousContentChangesNotification
object:coordinator];
}
- (void) MR_mergeChangesFromiCloud:(NSNotification *)notification;
{
[self performBlock:^{
MRLog(@"Merging Changes from iCloud");
[self mergeChangesFromContextDidSaveNotification:notification];
[[NSNotificationCenter defaultCenter] postNotificationName:kMagicalRecordDidMergeChangesFromiCloudNotification
object:self
userInfo:[notification userInfo]];
}];
}
- (void) MR_mergeChangesFromNotification:(NSNotification *)notification;
{
MRLog(@"Merging changes to %@context%@",
self == [NSManagedObjectContext MR_defaultContext] ? @"*** DEFAULT *** " : @"",
([NSThread isMainThread] ? @" *** on Main Thread ***" : @""));
[self mergeChangesFromContextDidSaveNotification:notification];
}
- (void) mergeChangesOnMainThread:(NSNotification *)notification
- (void) MR_mergeChangesOnMainThread:(NSNotification *)notification;
{
if ([NSThread isMainThread])
{
[self mergeChangesFromNotification:notification];
[self MR_mergeChangesFromNotification:notification];
}
else
{
[self performSelectorOnMainThread:@selector(mergeChangesFromNotification:) withObject:notification waitUntilDone:YES];
[self performSelectorOnMainThread:@selector(MR_mergeChangesFromNotification:) withObject:notification waitUntilDone:YES];
}
}
- (BOOL)MR_save
#pragma mark - Save Helpers
- (BOOL) MR_save;
{
return [self MR_saveWithErrorHandler:nil];
}
#ifdef NS_BLOCKS_AVAILABLE
- (BOOL) MR_saveWithErrorHandler:(void (^)(NSError *))errorCallback
- (BOOL) MR_saveWithErrorHandler:(void (^)(NSError *))errorCallback;
{
NSError *error = nil;
BOOL saved = NO;
@try
{
ARLog(@"Saving %@Context%@",
MRLog(@"Saving %@Context%@",
self == [[self class] MR_defaultContext] ? @" *** Default *** ": @"",
([NSThread isMainThread] ? @" *** on Main Thread ***" : @""));
@@ -137,7 +145,7 @@ static NSString const * kMagicalRecordManagedObjectContextKey = @"MagicalRecord_
}
@catch (NSException *exception)
{
ARLog(@"Problem saving: %@", (id)[exception userInfo] ?: (id)[exception reason]);
MRLog(@"Problem saving: %@", (id)[exception userInfo] ?: (id)[exception reason]);
}
@finally
{
@@ -157,9 +165,9 @@ static NSString const * kMagicalRecordManagedObjectContextKey = @"MagicalRecord_
}
#endif
- (void) saveWrapper
- (void) MR_saveWrapper;
{
#if __IPHONE_OS_VERSION_MAX_ALLOWED == __IPHONE_5_0
#ifdef NS_AUTOMATED_REFCOUNT_UNAVAILABLE
@autoreleasepool
{
[self MR_save];
@@ -171,30 +179,32 @@ static NSString const * kMagicalRecordManagedObjectContextKey = @"MagicalRecord_
#endif
}
- (BOOL)MR_saveOnBackgroundThread
#pragma mark - Threading Helpers
- (BOOL) MR_saveOnBackgroundThread;
{
[self performSelectorInBackground:@selector(saveWrapper) withObject:nil];
[self performSelectorInBackground:@selector(MR_saveWrapper) withObject:nil];
return YES;
}
- (BOOL)MR_saveOnMainThread
- (BOOL) MR_saveOnMainThread;
{
@synchronized(self)
{
[self performSelectorOnMainThread:@selector(saveWrapper) withObject:nil waitUntilDone:YES];
[self performSelectorOnMainThread:@selector(MR_saveWrapper) withObject:nil waitUntilDone:YES];
}
return YES;
}
- (BOOL)MR_notifiesMainContextOnSave
- (BOOL) MR_notifiesMainContextOnSave;
{
NSNumber *notifies = objc_getAssociatedObject(self, @"notifiesMainContext");
return notifies ? [notifies boolValue] : NO;
}
- (void) setMR_notifiesMainContextOnSave:(BOOL)enabled
- (void) MR_setNotifiesMainContextOnSave:(BOOL)enabled;
{
NSManagedObjectContext *mainContext = [[self class] MR_defaultContext];
if (self != mainContext)
@@ -209,12 +219,33 @@ static NSString const * kMagicalRecordManagedObjectContextKey = @"MagicalRecord_
}
}
+ (NSManagedObjectContext *) MR_contextWithStoreCoordinator:(NSPersistentStoreCoordinator *)coordinator
#pragma mark - Creation Helpers
+ (NSManagedObjectContext *) MR_contextForCurrentThread;
{
if ([NSThread isMainThread])
{
return [self MR_defaultContext];
}
else
{
NSMutableDictionary *threadDict = [[NSThread currentThread] threadDictionary];
NSManagedObjectContext *threadContext = [threadDict objectForKey:kMagicalRecordManagedObjectContextKey];
if (threadContext == nil)
{
threadContext = [self MR_contextThatNotifiesDefaultContextOnMainThread];
[threadDict setObject:threadContext forKey:kMagicalRecordManagedObjectContextKey];
}
return threadContext;
}
}
+ (NSManagedObjectContext *) MR_contextWithStoreCoordinator:(NSPersistentStoreCoordinator *)coordinator;
{
NSManagedObjectContext *context = nil;
if (coordinator != nil)
{
ARLog(@"Creating MOContext %@", [NSThread isMainThread] ? @" *** On Main Thread ***" : @"");
MRLog(@"Creating MOContext %@", [NSThread isMainThread] ? @" *** On Main Thread ***" : @"");
context = [[NSManagedObjectContext alloc] init];
[context setPersistentStoreCoordinator:coordinator];
MR_AUTORELEASE(context);
@@ -229,12 +260,12 @@ static NSString const * kMagicalRecordManagedObjectContextKey = @"MagicalRecord_
return context;
}
+ (NSManagedObjectContext *)MR_context
+ (NSManagedObjectContext *) MR_context;
{
return [self MR_contextWithStoreCoordinator:[NSPersistentStoreCoordinator MR_defaultStoreCoordinator]];
}
+ (NSManagedObjectContext *)MR_contextThatNotifiesDefaultContextOnMainThread
+ (NSManagedObjectContext *) MR_contextThatNotifiesDefaultContextOnMainThread;
{
NSManagedObjectContext *context = [self MR_context];
context.MR_notifiesMainContextOnSave = YES;

View File

@@ -20,6 +20,7 @@ extern NSString * const kMagicalRecordDefaultStoreFileName;
+ (void) MR_setDefaultPersistentStore:(NSPersistentStore *) store;
+ (NSURL *) MR_urlForStoreName:(NSString *)storeFileName;
+ (NSURL *) MR_cloudURLForUbiqutiousContainer:(NSString *)bucketName;
@end

View File

@@ -64,6 +64,14 @@ static NSPersistentStore *defaultPersistentStore_ = nil;
return [NSURL fileURLWithPath:[[self MR_applicationStorageDirectory] stringByAppendingPathComponent:storeFileName]];
}
+ (NSURL *) MR_cloudURLForUbiqutiousContainer:(NSString *)bucketName;
{
NSFileManager *fileManager = [[NSFileManager alloc] init];
NSURL *cloudURL = [fileManager URLForUbiquityContainerIdentifier:bucketName];
return cloudURL;
}
+ (NSURL *) MR_defaultLocalStoreUrl
{
return [self MR_urlForStoreName:kMagicalRecordDefaultStoreFileName];

View File

@@ -8,6 +8,7 @@
#import "MagicalRecordHelpers.h"
#import "NSPersistentStore+MagicalRecord.h"
extern NSString * const kMagicalRecordPSCDidCompleteiCloudSetupNotification;
@interface NSPersistentStoreCoordinator (MagicalRecord)
@@ -19,10 +20,15 @@
+ (NSPersistentStoreCoordinator *) MR_newPersistentStoreCoordinator NS_RETURNS_RETAINED;
+ (NSPersistentStoreCoordinator *) MR_coordinatorWithSqliteStoreNamed:(NSString *)storeFileName;
+ (NSPersistentStoreCoordinator *) MR_coordinatorWithAutoMigratingSqliteStoreNamed:(NSString *) storeFileName;
+ (NSPersistentStoreCoordinator *) MR_coordinatorWithAutoMigratingSqliteStoreNamed:(NSString *)storeFileName;
+ (NSPersistentStoreCoordinator *) MR_coordinatorWithPersitentStore:(NSPersistentStore *)persistentStore;
+ (NSPersistentStoreCoordinator *) MR_coordinatorWithiCloudContainerID:(NSString *)containerID
contentNameKey:(NSString *)contentNameKey
localStoreNamed:(NSString *)localStoreName
cloudStorePathComponent:(NSString *)subPathComponent;
- (NSPersistentStore *) MR_addInMemoryStore;
- (void) MR_addAutoMigratingSqliteStoreNamed:(NSString *) storeFileName;
- (void) MR_addSqliteStoreNamed:(id)storeFileName withOptions:(__autoreleasing NSDictionary *)options;
- (void) MR_addiCloudContainerID:(NSString *)containerID contentNameKey:(NSString *)contentNameKey localStoreNamed:(NSString *)localStoreName cloudStorePathComponent:(NSString *)subPathComponent;
@end

View File

@@ -8,10 +8,16 @@
#import "CoreData+MagicalRecord.h"
static NSPersistentStoreCoordinator *defaultCoordinator_ = nil;
NSString * const kMagicalRecordPSCDidCompleteiCloudSetupNotification = @"kMagicalRecordPSCDidCompleteiCloudSetupNotification";
@interface NSDictionary (Merging)
- (NSMutableDictionary*) MR_dictionaryByMergingDictionary:(NSDictionary*)d;
@end
@implementation NSPersistentStoreCoordinator (MagicalRecord)
+ (NSPersistentStoreCoordinator *) MR_defaultStoreCoordinator
{
if (defaultCoordinator_ == nil && [MagicalRecordHelpers shouldAutoCreateDefaultPersistentStoreCoordinator])
@@ -29,10 +35,11 @@ static NSPersistentStoreCoordinator *defaultCoordinator_ = nil;
#endif
defaultCoordinator_ = coordinator;
if (defaultCoordinator_ != nil && [NSPersistentStore MR_defaultPersistentStore] == nil)
if (defaultCoordinator_ != nil)
{
NSArray *persistentStores = [defaultCoordinator_ persistentStores];
if ([persistentStores count])
if ([persistentStores count] && [NSPersistentStore MR_defaultPersistentStore] == nil)
{
[NSPersistentStore MR_setDefaultPersistentStore:[persistentStores objectAtIndex:0]];
}
@@ -53,7 +60,7 @@ static NSPersistentStoreCoordinator *defaultCoordinator_ = nil;
}
}
- (void) MR_setupSqliteStoreNamed:(id)storeFileName withOptions:(NSDictionary *)options
- (void) MR_addSqliteStoreNamed:(id)storeFileName withOptions:(__autoreleasing NSDictionary *)options
{
NSURL *url = [storeFileName isKindOfClass:[NSURL class]] ? storeFileName : [NSPersistentStore MR_urlForStoreName:storeFileName];
NSError *error = nil;
@@ -69,55 +76,56 @@ static NSPersistentStoreCoordinator *defaultCoordinator_ = nil;
{
[MagicalRecordHelpers handleErrors:error];
}
[NSPersistentStore MR_setDefaultPersistentStore:store];
}
+ (NSPersistentStoreCoordinator *) MR_coordinatorWithPersitentStore:(NSPersistentStore *)persistentStore;
#pragma mark - Public Instance Methods
- (NSPersistentStore *) MR_addInMemoryStore
{
NSManagedObjectModel *model = [NSManagedObjectModel MR_defaultManagedObjectModel];
NSPersistentStoreCoordinator *psc = [[NSPersistentStoreCoordinator alloc] initWithManagedObjectModel:model];
[psc MR_setupSqliteStoreNamed:[persistentStore URL] withOptions:nil];
MR_AUTORELEASE(psc);
return psc;
NSError *error = nil;
NSPersistentStore *store = [self addPersistentStoreWithType:NSInMemoryStoreType
configuration:nil
URL:nil
options:nil
error:&error];
if (!store)
{
[MagicalRecordHelpers handleErrors:error];
}
return store;
}
+ (NSPersistentStoreCoordinator *) MR_coordinatorWithSqliteStoreNamed:(NSString *)storeFileName withOptions:(NSDictionary *)options
{
NSManagedObjectModel *model = [NSManagedObjectModel MR_defaultManagedObjectModel];
NSPersistentStoreCoordinator *psc = [[NSPersistentStoreCoordinator alloc] initWithManagedObjectModel:model];
[psc MR_setupSqliteStoreNamed:storeFileName withOptions:options];
MR_AUTORELEASE(psc);
return psc;
}
+ (NSPersistentStoreCoordinator *) MR_coordinatorWithSqliteStoreNamed:(NSString *)storeFileName
{
return [self MR_coordinatorWithSqliteStoreNamed:storeFileName withOptions:nil];
}
- (void) MR_setupAutoMigratingSqliteStoreNamed:(NSString *) storeFileName
+ (NSDictionary *) MR_autoMigrationOptions;
{
NSDictionary *options = [NSDictionary dictionaryWithObjectsAndKeys:
[NSNumber numberWithBool:YES], NSMigratePersistentStoresAutomaticallyOption,
[NSNumber numberWithBool:YES], NSInferMappingModelAutomaticallyOption,
nil];
[self MR_setupSqliteStoreNamed:storeFileName withOptions:options];
return options;
}
- (void) MR_addAutoMigratingSqliteStoreNamed:(NSString *) storeFileName
{
NSDictionary *options = [[self class] MR_autoMigrationOptions];
[self MR_addSqliteStoreNamed:storeFileName withOptions:options];
}
#pragma mark - Public Class Methods
+ (NSPersistentStoreCoordinator *) MR_coordinatorWithAutoMigratingSqliteStoreNamed:(NSString *) storeFileName
{
NSManagedObjectModel *model = [NSManagedObjectModel MR_defaultManagedObjectModel];
NSPersistentStoreCoordinator *coordinator = [[NSPersistentStoreCoordinator alloc] initWithManagedObjectModel:model];
[coordinator MR_setupAutoMigratingSqliteStoreNamed:storeFileName];
[coordinator MR_addAutoMigratingSqliteStoreNamed:storeFileName];
//HACK: lame solution to fix automigration error "Migration failed after first pass"
if ([[coordinator persistentStores] count] == 0)
{
[coordinator performSelector:@selector(MR_setupAutoMigratingSqliteStoreNamed:) withObject:storeFileName afterDelay:0.5];
[coordinator performSelector:@selector(MR_addAutoMigratingSqliteStoreNamed:) withObject:storeFileName afterDelay:0.5];
}
MR_AUTORELEASE(coordinator);
return coordinator;
@@ -134,27 +142,98 @@ static NSPersistentStoreCoordinator *defaultCoordinator_ = nil;
return psc;
}
- (NSPersistentStore *) MR_addInMemoryStore
{
NSError *error = nil;
NSPersistentStore *store = [self addPersistentStoreWithType:NSInMemoryStoreType
configuration:nil
URL:nil
options:nil
error:&error];
if (!store)
{
[MagicalRecordHelpers handleErrors:error];
}
return store;
}
+ (NSPersistentStoreCoordinator *) MR_newPersistentStoreCoordinator
{
NSPersistentStoreCoordinator *coordinator = [self MR_coordinatorWithSqliteStoreNamed:kMagicalRecordDefaultStoreFileName];
NSPersistentStoreCoordinator *coordinator = [self MR_coordinatorWithSqliteStoreNamed:[MagicalRecordHelpers defaultStoreName]];
MR_RETAIN(coordinator);
return coordinator;
}
- (void) MR_addiCloudContainerID:(NSString *)containerID contentNameKey:(NSString *)contentNameKey localStoreNamed:(NSString *)localStoreName cloudStorePathComponent:(NSString *)subPathComponent;
{
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
NSURL *cloudURL = [NSPersistentStore MR_cloudURLForUbiqutiousContainer:containerID];
if (subPathComponent)
{
cloudURL = [cloudURL URLByAppendingPathComponent:subPathComponent];
}
NSDictionary *options = [[self class] MR_autoMigrationOptions];
if (cloudURL) //iCloud is available
{
NSDictionary *iCloudOptions = [NSDictionary dictionaryWithObjectsAndKeys:
contentNameKey, NSPersistentStoreUbiquitousContentNameKey,
cloudURL, NSPersistentStoreUbiquitousContentURLKey, nil];
options = [options MR_dictionaryByMergingDictionary:iCloudOptions];
}
else
{
MRLog(@"iCloud is not enabled");
}
[self lock];
[self MR_addSqliteStoreNamed:localStoreName withOptions:options];
[self unlock];
dispatch_async(dispatch_get_main_queue(), ^{
MRLog(@"iCloud Store Enabled: %@", [MagicalRecordHelpers currentStack]);
[[NSNotificationCenter defaultCenter] postNotificationName:kMagicalRecordPSCDidCompleteiCloudSetupNotification object:nil];
});
});
}
+ (NSPersistentStoreCoordinator *) MR_coordinatorWithiCloudContainerID:(NSString *)containerID
contentNameKey:(NSString *)contentNameKey
localStoreNamed:(NSString *)localStoreName
cloudStorePathComponent:(NSString *)subPathComponent;
{
NSManagedObjectModel *model = [NSManagedObjectModel MR_defaultManagedObjectModel];
NSPersistentStoreCoordinator *psc = [[NSPersistentStoreCoordinator alloc] initWithManagedObjectModel:model];
[psc MR_addiCloudContainerID:containerID
contentNameKey:contentNameKey
localStoreNamed:localStoreName
cloudStorePathComponent:subPathComponent];
MR_AUTORELEASE(psc);
return psc;
}
+ (NSPersistentStoreCoordinator *) MR_coordinatorWithPersitentStore:(NSPersistentStore *)persistentStore;
{
NSManagedObjectModel *model = [NSManagedObjectModel MR_defaultManagedObjectModel];
NSPersistentStoreCoordinator *psc = [[NSPersistentStoreCoordinator alloc] initWithManagedObjectModel:model];
[psc MR_addSqliteStoreNamed:[persistentStore URL] withOptions:nil];
MR_AUTORELEASE(psc);
return psc;
}
+ (NSPersistentStoreCoordinator *) MR_coordinatorWithSqliteStoreNamed:(NSString *)storeFileName withOptions:(NSDictionary *)options
{
NSManagedObjectModel *model = [NSManagedObjectModel MR_defaultManagedObjectModel];
NSPersistentStoreCoordinator *psc = [[NSPersistentStoreCoordinator alloc] initWithManagedObjectModel:model];
[psc MR_addSqliteStoreNamed:storeFileName withOptions:options];
MR_AUTORELEASE(psc);
return psc;
}
+ (NSPersistentStoreCoordinator *) MR_coordinatorWithSqliteStoreNamed:(NSString *)storeFileName
{
return [self MR_coordinatorWithSqliteStoreNamed:storeFileName withOptions:nil];
}
@end
@implementation NSDictionary (Merging)
- (NSMutableDictionary *) MR_dictionaryByMergingDictionary:(NSDictionary *)d;
{
NSMutableDictionary *mutDict = [self mutableCopy];
[mutDict addEntriesFromDictionary:d];
return mutDict;
}
@end

View File

@@ -7,9 +7,13 @@
#define ENABLE_ACTIVE_RECORD_LOGGING
#ifdef ENABLE_ACTIVE_RECORD_LOGGING
#define ARLog(...) NSLog(@"%s(%p) %@", __PRETTY_FUNCTION__, self, [NSString stringWithFormat:__VA_ARGS__])
#ifdef LOG_VERBOSE
#define MRLog(...) DDLogVerbose(__VA_ARGS__)
#else
#define ARLog(...) ((void)0)
#define MRLog(...) NSLog(@"%s(%p) %@", __PRETTY_FUNCTION__, self, [NSString stringWithFormat:__VA_ARGS__])
#endif
#else
#define MRLog(...) ((void)0)
#endif
#import <CoreData/CoreData.h>
@@ -39,7 +43,7 @@
#import "NSManagedObject+MagicalDataImport.h"
#import "NSNumber+MagicalDataImport.h"
#import "NSDictionary+MagicalDataImport.h"
#import "NSObject+MagicalDataImport.h"
#import "NSAttributeDescription+MagicalDataImport.h"
#import "NSRelationshipDescription+MagicalDataImport.h"
#import "NSEntityDescription+MagicalDataImport.h"

View File

@@ -30,6 +30,7 @@ typedef void (^CoreDataBlock)(NSManagedObjectContext *context);
+ (id) errorHandlerTarget;
+ (void) setDefaultModelNamed:(NSString *)modelName;
+ (NSString *) defaultStoreName;
//global options
// enable/disable logging
@@ -49,6 +50,12 @@ typedef void (^CoreDataBlock)(NSManagedObjectContext *context);
+ (void) setupCoreDataStackWithStoreNamed:(NSString *)storeName;
+ (void) setupCoreDataStackWithAutoMigratingSqliteStoreNamed:(NSString *)storeName;
#pragma mark - iCloud Support
+ (BOOL) isICloudEnabled;
+ (void) setupCoreDataStackWithiCloudContainer:(NSString *)icloudBucket localStoreNamed:(NSString *)localStore;
+ (void) setupCoreDataStackWithiCloudContainer:(NSString *)containerID contentNameKey:(NSString *)contentNameKey localStoreNamed:(NSString *)localStoreName cloudStorePathComponent:(NSString *)pathSubcomponent;
#ifdef NS_BLOCKS_AVAILABLE
#pragma mark DEPRECATED_METHOD
@@ -62,7 +69,6 @@ typedef void (^CoreDataBlock)(NSManagedObjectContext *context);
@end
//Helper Functions
NSDate * adjustDateForDST(NSDate *date);
NSDate * dateFromString(NSString *value, NSString *format);

View File

@@ -9,7 +9,9 @@
#import <objc/runtime.h>
static NSString * const kMagicalRecordCategoryPrefix = @"MR_";
#ifdef MR_SHORTHAND
static BOOL methodsHaveBeenSwizzled = NO;
#endif
static id errorHandlerTarget = nil;
static SEL errorHandlerAction = nil;
@@ -60,21 +62,21 @@ void replaceSelectorForTargetWithSourceImpAndSwizzle(Class originalClass, SEL or
{
if ([e respondsToSelector:@selector(userInfo)])
{
ARLog(@"Error Details: %@", [e userInfo]);
MRLog(@"Error Details: %@", [e userInfo]);
}
else
{
ARLog(@"Error Details: %@", e);
MRLog(@"Error Details: %@", e);
}
}
}
else
{
ARLog(@"Error: %@", detailedError);
MRLog(@"Error: %@", detailedError);
}
}
ARLog(@"Error Domain: %@", [error domain]);
ARLog(@"Recovery Suggestion: %@", [error localizedRecoverySuggestion]);
MRLog(@"Error Domain: %@", [error domain]);
MRLog(@"Recovery Suggestion: %@", [error localizedRecoverySuggestion]);
}
+ (void) handleErrors:(NSError *)error
@@ -124,6 +126,21 @@ void replaceSelectorForTargetWithSourceImpAndSwizzle(Class originalClass, SEL or
[NSManagedObjectModel MR_setDefaultManagedObjectModel:model];
}
+ (NSString *) defaultStoreName;
{
NSString *defaultName = [[[NSBundle mainBundle] infoDictionary] valueForKey:(id)kCFBundleNameKey];
if (defaultName == nil)
{
defaultName = kMagicalRecordDefaultStoreFileName;
}
if (![defaultName hasSuffix:@"sqlite"])
{
defaultName = [defaultName stringByAppendingPathExtension:@"sqlite"];
}
return defaultName;
}
+ (void) setupCoreDataStack
{
NSManagedObjectContext *context = [NSManagedObjectContext MR_context];
@@ -132,7 +149,7 @@ void replaceSelectorForTargetWithSourceImpAndSwizzle(Class originalClass, SEL or
+ (void) setupAutoMigratingCoreDataStack
{
[self setupCoreDataStackWithAutoMigratingSqliteStoreNamed:kMagicalRecordDefaultStoreFileName];
[self setupCoreDataStackWithAutoMigratingSqliteStoreNamed:[self defaultStoreName]];
}
+ (void) setupCoreDataStackWithStoreNamed:(NSString *)storeName
@@ -153,7 +170,7 @@ void replaceSelectorForTargetWithSourceImpAndSwizzle(Class originalClass, SEL or
[NSManagedObjectContext MR_setDefaultContext:context];
}
+ (void) setupCoreDataStackWithInMemoryStore
+ (void) setupCoreDataStackWithInMemoryStore;
{
NSPersistentStoreCoordinator *coordinator = [NSPersistentStoreCoordinator MR_coordinatorWithInMemoryStore];
[NSPersistentStoreCoordinator MR_setDefaultStoreCoordinator:coordinator];
@@ -162,6 +179,35 @@ void replaceSelectorForTargetWithSourceImpAndSwizzle(Class originalClass, SEL or
[NSManagedObjectContext MR_setDefaultContext:context];
}
#pragma mark - iCloud Methods
+ (BOOL) isICloudEnabled;
{
NSURL *cloudURL = [NSPersistentStore MR_cloudURLForUbiqutiousContainer:nil];
return cloudURL != nil;
}
+ (void) setupCoreDataStackWithiCloudContainer:(NSString *)icloudBucket localStoreNamed:(NSString *)localStore;
{
[self setupCoreDataStackWithiCloudContainer:icloudBucket contentNameKey:nil localStoreNamed:localStore cloudStorePathComponent:nil];
}
+ (void) setupCoreDataStackWithiCloudContainer:(NSString *)containerID contentNameKey:(NSString *)contentNameKey localStoreNamed:(NSString *)localStoreName cloudStorePathComponent:(NSString *)pathSubcomponent;
{
NSPersistentStoreCoordinator *coordinator = [NSPersistentStoreCoordinator MR_coordinatorWithiCloudContainerID:containerID
contentNameKey:contentNameKey
localStoreNamed:localStoreName
cloudStorePathComponent:pathSubcomponent];
[NSPersistentStoreCoordinator MR_setDefaultStoreCoordinator:coordinator];
NSManagedObjectContext *context = [NSManagedObjectContext MR_contextWithStoreCoordinator:coordinator];
[NSManagedObjectContext MR_setDefaultContext:context];
[context MR_observeiCloudChangesInCoordinator:coordinator];
}
#pragma mark - Options
+ (BOOL) shouldAutoCreateManagedObjectModel;
{
return shouldAutoCreateManagedObjectModel_;
@@ -210,6 +256,7 @@ void replaceSelectorForTargetWithSourceImpAndSwizzle(Class originalClass, SEL or
#pragma mark - Support methods for shorthand methods
#ifdef MR_SHORTHAND
+ (BOOL) MR_resolveClassMethod:(SEL)originalSelector
{
BOOL resolvedClassMethod = [self MR_resolveClassMethod:originalSelector];
@@ -255,6 +302,7 @@ void replaceSelectorForTargetWithSourceImpAndSwizzle(Class originalClass, SEL or
}];
methodsHaveBeenSwizzled = YES;
}
#endif
#pragma mark - initialize
@@ -262,7 +310,9 @@ void replaceSelectorForTargetWithSourceImpAndSwizzle(Class originalClass, SEL or
{
if (self == [MagicalRecordHelpers class])
{
#ifdef MR_SHORTHAND
[self swizzleShorthandMethods];
#endif
[self setShouldAutoCreateManagedObjectModel:YES];
[self setShouldAutoCreateDefaultPersistentStoreCoordinator:YES];
}

View File

@@ -6,8 +6,8 @@
@interface NSManagedObject (NSManagedObject_DataImportShortHand)
- (void) importValuesForKeysWithDictionary:(NSDictionary *)objectData;
- (void) updateValuesForKeysWithDictionary:(NSDictionary *)objectData;
- (void) importValuesForKeysWithDictionary:(id)objectData;
- (void) updateValuesForKeysWithDictionary:(id)objectData;
+ (id) importFromDictionary:(NSDictionary *)data;
+ (id) importFromDictionary:(NSDictionary *)data inContext:(NSManagedObjectContext *)context;
+ (NSArray *) importFromArray:(NSArray *)listOfObjectData;
@@ -89,6 +89,7 @@
+ (NSArray *) findByAttribute:(NSString *)attribute withValue:(id)searchValue andOrderBy:(NSString *)sortTerm ascending:(BOOL)ascending inContext:(NSManagedObjectContext *)context;
- (id) inContext:(NSManagedObjectContext *)otherContext;
- (id) inThreadContext;
#if TARGET_OS_IPHONE || TARGET_IPHONE_SIMULATOR
+ (void) performFetch:(NSFetchedResultsController *)controller;
+ (NSFetchedResultsController *) fetchAllSortedBy:(NSString *)sortTerm ascending:(BOOL)ascending withPredicate:(NSPredicate *)searchTerm groupBy:(NSString *)groupingKeyPath delegate:(id<NSFetchedResultsControllerDelegate>)delegate;
+ (NSFetchedResultsController *) fetchAllSortedBy:(NSString *)sortTerm ascending:(BOOL)ascending withPredicate:(NSPredicate *)searchTerm groupBy:(NSString *)groupingKeyPath delegate:(id<NSFetchedResultsControllerDelegate>)delegate inContext:(NSManagedObjectContext *)context;
@@ -96,6 +97,7 @@
+ (NSFetchedResultsController *) fetchAllGroupedBy:(NSString *)group withPredicate:(NSPredicate *)searchTerm sortedBy:(NSString *)sortTerm ascending:(BOOL)ascending inContext:(NSManagedObjectContext *)context;
+ (NSFetchedResultsController *) fetchAllGroupedBy:(NSString *)group withPredicate:(NSPredicate *)searchTerm sortedBy:(NSString *)sortTerm ascending:(BOOL)ascending delegate:(id<NSFetchedResultsControllerDelegate>)delegate;
+ (NSFetchedResultsController *) fetchAllGroupedBy:(NSString *)group withPredicate:(NSPredicate *)searchTerm sortedBy:(NSString *)sortTerm ascending:(BOOL)ascending delegate:(id<NSFetchedResultsControllerDelegate>)delegate inContext:(NSManagedObjectContext *)context;
#endif
@end
@interface NSManagedObjectContext (MagicalRecordShortHand)
- (void) observeContext:(NSManagedObjectContext *)otherContext;