diff --git a/.gitignore b/.gitignore index dba37da06..08227583a 100644 --- a/.gitignore +++ b/.gitignore @@ -16,4 +16,5 @@ build/ UserInterfaceState.xcuserstate /Magical Record.xcodeproj/project.xcworkspace/xcuserdata/saul.xcuserdatad/UserInterfaceState.xcuserstate -/Magical Record.xcodeproj/xcuserdata/saul.xcuserdatad/xcdebugger/Breakpoints.xcbkptlist \ No newline at end of file +/Magical Record.xcodeproj/xcuserdata/saul.xcuserdatad/xcdebugger/Breakpoints.xcbkptlist +/Magical Record.xcodeproj/xcuserdata/gfurman.xcuserdatad diff --git a/Magical Record.xcodeproj/project.pbxproj b/Magical Record.xcodeproj/project.pbxproj index 8a5935d3f..1bb1fc978 100644 --- a/Magical Record.xcodeproj/project.pbxproj +++ b/Magical Record.xcodeproj/project.pbxproj @@ -129,6 +129,11 @@ C7E736DF1402FE64005657C9 /* SingleEntityWithNoRelationships.json in Resources */ = {isa = PBXBuildFile; fileRef = C7E736DE1402FE64005657C9 /* SingleEntityWithNoRelationships.json */; }; C7F5EEB2148DC76700964607 /* NSObject+MagicalDataImport.m in Sources */ = {isa = PBXBuildFile; fileRef = C7F5EEB1148DC76700964607 /* NSObject+MagicalDataImport.m */; }; C7F5EEB3148DC76700964607 /* NSObject+MagicalDataImport.m in Sources */ = {isa = PBXBuildFile; fileRef = C7F5EEB1148DC76700964607 /* NSObject+MagicalDataImport.m */; }; + FD73E53F14AC462F00922CA4 /* OCMock.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = C721C84313D0C6460097AB6F /* OCMock.framework */; }; + FD73E54214AC484100922CA4 /* MappedEntity.m in Sources */ = {isa = PBXBuildFile; fileRef = FD73E54114AC484100922CA4 /* MappedEntity.m */; }; + FD73E54514AC485300922CA4 /* _MappedEntity.m in Sources */ = {isa = PBXBuildFile; fileRef = FD73E54414AC485300922CA4 /* _MappedEntity.m */; }; + FD73E54614AC4AC700922CA4 /* MagicalDataImportTestCase.m in Sources */ = {isa = PBXBuildFile; fileRef = C7913B9C13FAFC13007E09CC /* MagicalDataImportTestCase.m */; }; + FD73E54914AC4D9A00922CA4 /* OCMock.framework in CopyFiles */ = {isa = PBXBuildFile; fileRef = FD73E54814AC4D9A00922CA4 /* OCMock.framework */; }; /* End PBXBuildFile section */ /* Begin PBXBuildRule section */ @@ -177,6 +182,16 @@ ); runOnlyForDeploymentPostprocessing = 0; }; + FD73E54714AC4D5200922CA4 /* CopyFiles */ = { + isa = PBXCopyFilesBuildPhase; + buildActionMask = 2147483647; + dstPath = ""; + dstSubfolderSpec = 10; + files = ( + FD73E54914AC4D9A00922CA4 /* OCMock.framework in CopyFiles */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; /* End PBXCopyFilesBuildPhase section */ /* Begin PBXFileReference section */ @@ -350,6 +365,11 @@ C7E736DE1402FE64005657C9 /* SingleEntityWithNoRelationships.json */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.json; name = SingleEntityWithNoRelationships.json; path = "Unit Tests/Fixtures/SingleEntityWithNoRelationships.json"; sourceTree = ""; }; C7F5EEB0148DC76700964607 /* NSObject+MagicalDataImport.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = "NSObject+MagicalDataImport.h"; path = "DataImport/NSObject+MagicalDataImport.h"; sourceTree = ""; }; C7F5EEB1148DC76700964607 /* NSObject+MagicalDataImport.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = "NSObject+MagicalDataImport.m"; path = "DataImport/NSObject+MagicalDataImport.m"; sourceTree = ""; }; + FD73E54014AC484100922CA4 /* MappedEntity.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MappedEntity.h; sourceTree = ""; }; + FD73E54114AC484100922CA4 /* MappedEntity.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MappedEntity.m; sourceTree = ""; }; + FD73E54314AC485300922CA4 /* _MappedEntity.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = _MappedEntity.h; sourceTree = ""; }; + FD73E54414AC485300922CA4 /* _MappedEntity.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = _MappedEntity.m; sourceTree = ""; }; + FD73E54814AC4D9A00922CA4 /* OCMock.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = OCMock.framework; path = "Mac App Unit Tests/Frameworks/OCMock.framework"; sourceTree = ""; }; /* End PBXFileReference section */ /* Begin PBXFrameworksBuildPhase section */ @@ -361,6 +381,7 @@ C721C82413D0C45E0097AB6F /* Foundation.framework in Frameworks */, C76AF7F213DBC12500CE2E05 /* OCHamcrest.framework in Frameworks */, C721C84E13D0C6460097AB6F /* GHUnit.framework in Frameworks */, + FD73E53F14AC462F00922CA4 /* OCMock.framework in Frameworks */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -405,6 +426,7 @@ C721C7A013D0A3750097AB6F = { isa = PBXGroup; children = ( + FD73E54814AC4D9A00922CA4 /* OCMock.framework */, C75C7D69147220D300D0C2FE /* generateShorthandFile.rb */, C721C85513D0C7030097AB6F /* Source */, C77E5FA513D0CBA600298F87 /* Unit Tests */, @@ -718,6 +740,10 @@ C7BD885113DBF88F00274567 /* TestEntities */ = { isa = PBXGroup; children = ( + FD73E54314AC485300922CA4 /* _MappedEntity.h */, + FD73E54414AC485300922CA4 /* _MappedEntity.m */, + FD73E54014AC484100922CA4 /* MappedEntity.h */, + FD73E54114AC484100922CA4 /* MappedEntity.m */, C7BD885213DBF88F00274567 /* _AbstractRelatedEntity.h */, C7BD885313DBF88F00274567 /* _AbstractRelatedEntity.m */, C7BD885413DBF88F00274567 /* _ConcreteRelatedEntity.h */, @@ -796,6 +822,7 @@ C721C7DA13D0C3A00097AB6F /* Resources */, C753897513DB6310002B2F57 /* Copy GHUnit into App Bundle */, C76AF7F313DBC33100CE2E05 /* Copy OCHamcrest into App Bundle */, + FD73E54714AC4D5200922CA4 /* CopyFiles */, ); buildRules = ( ); @@ -902,7 +929,7 @@ ); runOnlyForDeploymentPostprocessing = 0; shellPath = /bin/sh; - shellScript = "cd \"Unit Tests/Fixtures/Mac\" && mogenerator -m TestModel.xcdatamodeld/TestModel.xcdatamodel -O TestEntities"; + shellScript = "cd \"Unit Tests/Fixtures/Mac\" && /usr/local/bin/mogenerator -m TestModel.xcdatamodeld/TestModel.xcdatamodel -O TestEntities"; }; C7B8733A1472CFA20046776C /* Generate Shorthand Headers */ = { isa = PBXShellScriptBuildPhase; @@ -946,6 +973,7 @@ C721C87213D0C7030097AB6F /* NSPersistentStore+MagicalRecord.m in Sources */, C721C87413D0C7030097AB6F /* NSPersistentStoreCoordinator+MagicalRecord.m in Sources */, C76AF7F713DBD63E00CE2E05 /* NSManagedObject+MagicalDataImport.m in Sources */, + FD73E54614AC4AC700922CA4 /* MagicalDataImportTestCase.m in Sources */, C721C87613D0C7030097AB6F /* MagicalRecordHelpers.m in Sources */, C753897413DB61CE002B2F57 /* GHUnitTestMain.m in Sources */, C76AF7E513DBC08F00CE2E05 /* FixtureHelpers.m in Sources */, @@ -974,6 +1002,8 @@ C7005F2214153A060061B9F4 /* NSEntityDescription+MagicalDataImport.m in Sources */, C7F5EEB2148DC76700964607 /* NSObject+MagicalDataImport.m in Sources */, C758AFD51493C6DC0051E570 /* NSString+MagicalDataImport.m in Sources */, + FD73E54214AC484100922CA4 /* MappedEntity.m in Sources */, + FD73E54514AC485300922CA4 /* _MappedEntity.m in Sources */, ); runOnlyForDeploymentPostprocessing = 0; }; diff --git a/Magical Record.xcodeproj/xcuserdata/gfurman.xcuserdatad/xcdebugger/Breakpoints.xcbkptlist b/Magical Record.xcodeproj/xcuserdata/gfurman.xcuserdatad/xcdebugger/Breakpoints.xcbkptlist new file mode 100644 index 000000000..05301bc25 --- /dev/null +++ b/Magical Record.xcodeproj/xcuserdata/gfurman.xcuserdatad/xcdebugger/Breakpoints.xcbkptlist @@ -0,0 +1,5 @@ + + + diff --git a/Magical Record.xcodeproj/xcuserdata/gfurman.xcuserdatad/xcschemes/xcschememanagement.plist b/Magical Record.xcodeproj/xcuserdata/gfurman.xcuserdatad/xcschemes/xcschememanagement.plist new file mode 100644 index 000000000..d9b2064b8 --- /dev/null +++ b/Magical Record.xcodeproj/xcuserdata/gfurman.xcuserdatad/xcschemes/xcschememanagement.plist @@ -0,0 +1,19 @@ + + + + + SuppressBuildableAutocreation + + C721C7DB13D0C3A00097AB6F + + primary + + + C721C7FC13D0C3CD0097AB6F + + primary + + + + + diff --git a/README.md b/README.md index 47fc570a4..183deb0df 100644 --- a/README.md +++ b/README.md @@ -41,6 +41,20 @@ Each call instantiates one of each piece of the Core Data stack, and provides ge And, before your app exits, you can use the clean up method: [MagicalRecordHelpers cleanUp]; + +## iCloud Support + + Apps built for iOS5+ and OSX Lion 10.7.2+ can take advantage of iCloud to sync Core Data stores. To implement this functionality with Magical Record, use **one** of the following setup calls instead of those listed in the previous section: + + + (void) setupCoreDataStackWithiCloudContainer:(NSString *)icloudBucket localStoreNamed:(NSString *)localStore; + + (void) setupCoreDataStackWithiCloudContainer:(NSString *)containerID contentNameKey:(NSString *)contentNameKey localStoreNamed:(NSString *)localStoreName cloudStorePathComponent:(NSString *)pathSubcomponent; + + (void) setupCoreDataStackWithiCloudContainer:(NSString *)containerID contentNameKey:(NSString *)contentNameKey localStoreNamed:(NSString *)localStoreName cloudStorePathComponent:(NSString *)pathSubcomponent completion:(void(^)(void))completion; + +For further details, and to ensure that your application is suitable for iCloud, please see [Apple's iCloud Notes](https://developer.apple.com/library/ios/#releasenotes/DataManagement/RN-iCloudCoreData/_index.html). + +In particular note that the first helper method, + (void) setupCoreDataStackWithiCloudContainer:(NSString *)icloudBucket localStoreNamed:(NSString *)localStore, automatically generates the **NSPersistentStoreUbiquitousContentNameKey** based on your application's Bundle Identifier. + +If you are managing multiple different iCloud stores it is highly recommended that you use one of the other helper methods to specify your own **contentNameKey** ### Default Managed Object Context diff --git a/Rakefile b/Rakefile new file mode 100644 index 000000000..330febd6c --- /dev/null +++ b/Rakefile @@ -0,0 +1,60 @@ +@ios_fixtures = "Unit Tests/Fixtures/iOS" + + +@target = "" +@project = "" +@fixtures = "" + +namespace :setup do + task :ios do + + end + + task :osx do + @target = "Mac App Unit Tests" + @project = "Magical Record.xcodeproj" + @fixtures = "Unit Tests/Fixtures/Mac" + end +end + +namespace :clean do + task :osx => ["setup:osx"] do + rm_rf "#{@fixtures}/TestEntities" + end +end + +namespace :build do + + task :run do + results = system("xcodebuild -project '#{@project}' -target '#{@target}'") + puts results + end + + namespace :db do + task :create do + Dir.chdir(@fixtures) do + puts `/usr/local/bin/mogenerator -m TestModel.xcdatamodeld/TestModel.xcdatamodel -O TestEntities` + end + end + end + + task :osx => ["setup:osx", "clean:osx", "build:db:create", "build:run"] + + task :ios => [] do + + end +end + +namespace :test do + task :osx => ["build:osx"] do + puts "testing osx" + end + + task :ios do + puts "testing ios" + end +end + +task :test => ["test:osx", "test:ios"] + +task :default => :test diff --git a/Source/MagicalRecordHelpers.m b/Source/MagicalRecordHelpers.m index a286ae04f..3899fe2fb 100644 --- a/Source/MagicalRecordHelpers.m +++ b/Source/MagicalRecordHelpers.m @@ -197,7 +197,8 @@ + (BOOL) isICloudEnabled; + (void) setupCoreDataStackWithiCloudContainer:(NSString *)icloudBucket localStoreNamed:(NSString *)localStore; { - [self setupCoreDataStackWithiCloudContainer:icloudBucket contentNameKey:nil localStoreNamed:localStore cloudStorePathComponent:nil]; + NSString *contentNameKey = [[[NSBundle mainBundle] infoDictionary] objectForKey:@"CFBundleIdentifier"]; + [self setupCoreDataStackWithiCloudContainer:icloudBucket contentNameKey:contentNameKey localStoreNamed:localStore cloudStorePathComponent:nil]; } + (void) setupCoreDataStackWithiCloudContainer:(NSString *)containerID contentNameKey:(NSString *)contentNameKey localStoreNamed:(NSString *)localStoreName cloudStorePathComponent:(NSString *)pathSubcomponent; diff --git a/Unit Tests/Fixtures/Mac/TestEntities/MappedEntity.h b/Unit Tests/Fixtures/Mac/TestEntities/MappedEntity.h new file mode 100644 index 000000000..1a10afa58 --- /dev/null +++ b/Unit Tests/Fixtures/Mac/TestEntities/MappedEntity.h @@ -0,0 +1,5 @@ +#import "_MappedEntity.h" + +@interface MappedEntity : _MappedEntity {} +// Custom logic goes here. +@end diff --git a/Unit Tests/Fixtures/Mac/TestEntities/MappedEntity.m b/Unit Tests/Fixtures/Mac/TestEntities/MappedEntity.m new file mode 100644 index 000000000..d472146e8 --- /dev/null +++ b/Unit Tests/Fixtures/Mac/TestEntities/MappedEntity.m @@ -0,0 +1,7 @@ +#import "MappedEntity.h" + +@implementation MappedEntity + +// Custom logic goes here. + +@end diff --git a/Unit Tests/Fixtures/Mac/TestEntities/_MappedEntity.h b/Unit Tests/Fixtures/Mac/TestEntities/_MappedEntity.h new file mode 100644 index 000000000..106ebc836 --- /dev/null +++ b/Unit Tests/Fixtures/Mac/TestEntities/_MappedEntity.h @@ -0,0 +1,105 @@ +// DO NOT EDIT. This file is machine-generated and constantly overwritten. +// Make changes to MappedEntity.h instead. + +#import + + + + + + + + +@interface MappedEntityID : NSManagedObjectID {} +@end + +@interface _MappedEntity : NSManagedObject {} ++ (id)insertInManagedObjectContext:(NSManagedObjectContext*)moc_; ++ (NSString*)entityName; ++ (NSEntityDescription*)entityInManagedObjectContext:(NSManagedObjectContext*)moc_; +- (MappedEntityID*)objectID; + + + + +@property (nonatomic, retain) NSNumber *mappedEntityID; + + +@property short mappedEntityIDValue; +- (short)mappedEntityIDValue; +- (void)setMappedEntityIDValue:(short)value_; + +//- (BOOL)validateMappedEntityID:(id*)value_ error:(NSError**)error_; + + + + +@property (nonatomic, retain) NSString *nestedAttribute; + + +//- (BOOL)validateNestedAttribute:(id*)value_ error:(NSError**)error_; + + + + +@property (nonatomic, retain) NSString *sampleAttribute; + + +//- (BOOL)validateSampleAttribute:(id*)value_ error:(NSError**)error_; + + + + +@property (nonatomic, retain) NSNumber *testMappedEntityID; + + +@property long long testMappedEntityIDValue; +- (long long)testMappedEntityIDValue; +- (void)setTestMappedEntityIDValue:(long long)value_; + +//- (BOOL)validateTestMappedEntityID:(id*)value_ error:(NSError**)error_; + + + + + +@end + +@interface _MappedEntity (CoreDataGeneratedAccessors) + +@end + +@interface _MappedEntity (CoreDataGeneratedPrimitiveAccessors) + + +- (NSNumber*)primitiveMappedEntityID; +- (void)setPrimitiveMappedEntityID:(NSNumber*)value; + +- (short)primitiveMappedEntityIDValue; +- (void)setPrimitiveMappedEntityIDValue:(short)value_; + + + + +- (NSString*)primitiveNestedAttribute; +- (void)setPrimitiveNestedAttribute:(NSString*)value; + + + + +- (NSString*)primitiveSampleAttribute; +- (void)setPrimitiveSampleAttribute:(NSString*)value; + + + + +- (NSNumber*)primitiveTestMappedEntityID; +- (void)setPrimitiveTestMappedEntityID:(NSNumber*)value; + +- (long long)primitiveTestMappedEntityIDValue; +- (void)setPrimitiveTestMappedEntityIDValue:(long long)value_; + + + + +@end diff --git a/Unit Tests/Fixtures/Mac/TestEntities/_MappedEntity.m b/Unit Tests/Fixtures/Mac/TestEntities/_MappedEntity.m new file mode 100644 index 000000000..927823b3f --- /dev/null +++ b/Unit Tests/Fixtures/Mac/TestEntities/_MappedEntity.m @@ -0,0 +1,117 @@ +// DO NOT EDIT. This file is machine-generated and constantly overwritten. +// Make changes to MappedEntity.m instead. + +#import "_MappedEntity.h" + +@implementation MappedEntityID +@end + +@implementation _MappedEntity + ++ (id)insertInManagedObjectContext:(NSManagedObjectContext*)moc_ { + NSParameterAssert(moc_); + return [NSEntityDescription insertNewObjectForEntityForName:@"MappedEntity" inManagedObjectContext:moc_]; +} + ++ (NSString*)entityName { + return @"MappedEntity"; +} + ++ (NSEntityDescription*)entityInManagedObjectContext:(NSManagedObjectContext*)moc_ { + NSParameterAssert(moc_); + return [NSEntityDescription entityForName:@"MappedEntity" inManagedObjectContext:moc_]; +} + +- (MappedEntityID*)objectID { + return (MappedEntityID*)[super objectID]; +} + ++ (NSSet *)keyPathsForValuesAffectingValueForKey:(NSString *)key { + NSSet *keyPaths = [super keyPathsForValuesAffectingValueForKey:key]; + + if ([key isEqualToString:@"mappedEntityIDValue"]) { + NSSet *affectingKey = [NSSet setWithObject:@"mappedEntityID"]; + keyPaths = [keyPaths setByAddingObjectsFromSet:affectingKey]; + } + if ([key isEqualToString:@"testMappedEntityIDValue"]) { + NSSet *affectingKey = [NSSet setWithObject:@"testMappedEntityID"]; + keyPaths = [keyPaths setByAddingObjectsFromSet:affectingKey]; + } + + return keyPaths; +} + + + + +@dynamic mappedEntityID; + + + +- (short)mappedEntityIDValue { + NSNumber *result = [self mappedEntityID]; + return [result shortValue]; +} + +- (void)setMappedEntityIDValue:(short)value_ { + [self setMappedEntityID:[NSNumber numberWithShort:value_]]; +} + +- (short)primitiveMappedEntityIDValue { + NSNumber *result = [self primitiveMappedEntityID]; + return [result shortValue]; +} + +- (void)setPrimitiveMappedEntityIDValue:(short)value_ { + [self setPrimitiveMappedEntityID:[NSNumber numberWithShort:value_]]; +} + + + + + +@dynamic nestedAttribute; + + + + + + +@dynamic sampleAttribute; + + + + + + +@dynamic testMappedEntityID; + + + +- (long long)testMappedEntityIDValue { + NSNumber *result = [self testMappedEntityID]; + return [result longLongValue]; +} + +- (void)setTestMappedEntityIDValue:(long long)value_ { + [self setTestMappedEntityID:[NSNumber numberWithLongLong:value_]]; +} + +- (long long)primitiveTestMappedEntityIDValue { + NSNumber *result = [self primitiveTestMappedEntityID]; + return [result longLongValue]; +} + +- (void)setPrimitiveTestMappedEntityIDValue:(long long)value_ { + [self setPrimitiveTestMappedEntityID:[NSNumber numberWithLongLong:value_]]; +} + + + + + + + + + +@end diff --git a/Unit Tests/Fixtures/Mac/TestModel.xcdatamodeld/TestModel.xcdatamodel/contents b/Unit Tests/Fixtures/Mac/TestModel.xcdatamodeld/TestModel.xcdatamodel/contents index d9f8581a3..13596bd5e 100644 --- a/Unit Tests/Fixtures/Mac/TestModel.xcdatamodeld/TestModel.xcdatamodel/contents +++ b/Unit Tests/Fixtures/Mac/TestModel.xcdatamodeld/TestModel.xcdatamodel/contents @@ -1,5 +1,5 @@ - + @@ -8,6 +8,23 @@ + + + + + + + + + + + + + + + + + @@ -33,5 +50,6 @@ + \ No newline at end of file diff --git a/Unit Tests/MagicalDataImportTestCase.h b/Unit Tests/MagicalDataImportTestCase.h index 5721c3909..32b90f0c2 100644 --- a/Unit Tests/MagicalDataImportTestCase.h +++ b/Unit Tests/MagicalDataImportTestCase.h @@ -6,8 +6,11 @@ // Copyright (c) 2011 Magical Panda Software LLC. All rights reserved. // +#ifdef MAC_PLATFORM_ONLY +#import +#else #import - +#endif @interface MagicalDataImportTestCase : GHTestCase @property (nonatomic, retain) id testEntityData; diff --git a/Unit Tests/MagicalRecordHelperTests.m b/Unit Tests/MagicalRecordHelperTests.m index 5c2038b63..c3e52d20e 100644 --- a/Unit Tests/MagicalRecordHelperTests.m +++ b/Unit Tests/MagicalRecordHelperTests.m @@ -7,6 +7,7 @@ // #import "MagicalRecordHelperTests.h" +#import "OCMockObject.h" @protocol MagicalRecordErrorHandlerProtocol