mirror of
https://github.com/JohnEstropia/CoreStore.git
synced 2026-01-15 05:33:31 +01:00
here we go
This commit is contained in:
1
.gitignore
vendored
Normal file
1
.gitignore
vendored
Normal file
@@ -0,0 +1 @@
|
||||
HardcoreData.xcodeproj/xcuserdata
|
||||
6
.gitmodules
vendored
Normal file
6
.gitmodules
vendored
Normal file
@@ -0,0 +1,6 @@
|
||||
[submodule "Libraries/JEToolkit"]
|
||||
path = Libraries/JEToolkit
|
||||
url = git@github.com:JohnEstropia/JEToolkit.git
|
||||
[submodule "Libraries/GCDKit"]
|
||||
path = Libraries/GCDKit
|
||||
url = git@github.com:JohnEstropia/GCDKit.git
|
||||
@@ -9,8 +9,54 @@
|
||||
/* Begin PBXBuildFile section */
|
||||
2F03A53619C5C6DA005002A5 /* HardcoreData.h in Headers */ = {isa = PBXBuildFile; fileRef = 2F03A53519C5C6DA005002A5 /* HardcoreData.h */; settings = {ATTRIBUTES = (Public, ); }; };
|
||||
2F03A54019C5C6DA005002A5 /* HardcoreDataTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2F03A53F19C5C6DA005002A5 /* HardcoreDataTests.swift */; };
|
||||
2F03A54D19C5C872005002A5 /* CoreData.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 2F03A54C19C5C872005002A5 /* CoreData.framework */; };
|
||||
2F291E2719C6D3CF007AF63F /* HardcoreData.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2F291E2619C6D3CF007AF63F /* HardcoreData.swift */; };
|
||||
B5CFD36E1A0775F000B7885F /* SaveResult.swift in Sources */ = {isa = PBXBuildFile; fileRef = B5CFD36D1A0775F000B7885F /* SaveResult.swift */; };
|
||||
B5CFF23E19FD1D1C00D6DFC4 /* NSManagedObjectContext+HardcoreData.swift in Sources */ = {isa = PBXBuildFile; fileRef = B5CFF23D19FD1D1C00D6DFC4 /* NSManagedObjectContext+HardcoreData.swift */; };
|
||||
B5CFF24019FD383100D6DFC4 /* DataTransaction.swift in Sources */ = {isa = PBXBuildFile; fileRef = B5CFF23F19FD383100D6DFC4 /* DataTransaction.swift */; };
|
||||
B5D1E22A19FA9E63003B2874 /* PersistentStoreResult.swift in Sources */ = {isa = PBXBuildFile; fileRef = B5D1E22919FA9E63003B2874 /* PersistentStoreResult.swift */; };
|
||||
B5D1E22C19FA9FBC003B2874 /* NSError+HardcoreData.swift in Sources */ = {isa = PBXBuildFile; fileRef = B5D1E22B19FA9FBC003B2874 /* NSError+HardcoreData.swift */; };
|
||||
B5D399F119FC818E000E91BB /* DataStack.swift in Sources */ = {isa = PBXBuildFile; fileRef = B5D399F019FC818E000E91BB /* DataStack.swift */; };
|
||||
B5D399F519FCF4E0000E91BB /* NSPersistentStoreCoordinator+HardcoreData.swift in Sources */ = {isa = PBXBuildFile; fileRef = B5D399F419FCF4E0000E91BB /* NSPersistentStoreCoordinator+HardcoreData.swift */; };
|
||||
B5D39A0219FD00C9000E91BB /* Foundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = B5D39A0119FD00C9000E91BB /* Foundation.framework */; };
|
||||
B5D39A0419FD00DE000E91BB /* UIKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = B5D39A0319FD00DE000E91BB /* UIKit.framework */; };
|
||||
B5D8080E1A3471A500A44484 /* GCDKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = B5D808021A34715700A44484 /* GCDKit.framework */; };
|
||||
B5D8080F1A3471A900A44484 /* JEToolkit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = B5D808081A34715700A44484 /* JEToolkit.framework */; };
|
||||
B5E209E01A0726460089C9D4 /* NSManagedObject+HardcoreData.swift in Sources */ = {isa = PBXBuildFile; fileRef = B5E209DF1A0726460089C9D4 /* NSManagedObject+HardcoreData.swift */; };
|
||||
B5F539901A17A6FC00EC763B /* QueryDescriptor.swift in Sources */ = {isa = PBXBuildFile; fileRef = B5F5398F1A17A6FC00EC763B /* QueryDescriptor.swift */; };
|
||||
/* End PBXBuildFile section */
|
||||
|
||||
/* Begin PBXContainerItemProxy section */
|
||||
B5D808011A34715700A44484 /* PBXContainerItemProxy */ = {
|
||||
isa = PBXContainerItemProxy;
|
||||
containerPortal = B5D806C51A34715700A44484 /* GCDKit.xcodeproj */;
|
||||
proxyType = 2;
|
||||
remoteGlobalIDString = 2FBBCACB19A9FE610070E4AB;
|
||||
remoteInfo = GCDKit;
|
||||
};
|
||||
B5D808031A34715700A44484 /* PBXContainerItemProxy */ = {
|
||||
isa = PBXContainerItemProxy;
|
||||
containerPortal = B5D806C51A34715700A44484 /* GCDKit.xcodeproj */;
|
||||
proxyType = 2;
|
||||
remoteGlobalIDString = 2FBBCAD619A9FE610070E4AB;
|
||||
remoteInfo = GCDKitTests;
|
||||
};
|
||||
B5D808071A34715700A44484 /* PBXContainerItemProxy */ = {
|
||||
isa = PBXContainerItemProxy;
|
||||
containerPortal = B5D8074E1A34715700A44484 /* JEToolkit.xcodeproj */;
|
||||
proxyType = 2;
|
||||
remoteGlobalIDString = 2F74E6F519DFCC7A00FB0C88;
|
||||
remoteInfo = JEToolkit;
|
||||
};
|
||||
B5D808091A34715700A44484 /* PBXContainerItemProxy */ = {
|
||||
isa = PBXContainerItemProxy;
|
||||
containerPortal = B5D8074E1A34715700A44484 /* JEToolkit.xcodeproj */;
|
||||
proxyType = 2;
|
||||
remoteGlobalIDString = 2F74E70019DFCC7A00FB0C88;
|
||||
remoteInfo = JEToolkitTests;
|
||||
};
|
||||
/* End PBXContainerItemProxy section */
|
||||
|
||||
/* Begin PBXFileReference section */
|
||||
2F03A53019C5C6DA005002A5 /* HardcoreData.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = HardcoreData.framework; sourceTree = BUILT_PRODUCTS_DIR; };
|
||||
2F03A53419C5C6DA005002A5 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = "<group>"; };
|
||||
@@ -18,6 +64,22 @@
|
||||
2F03A53B19C5C6DA005002A5 /* HardcoreDataTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = HardcoreDataTests.xctest; sourceTree = BUILT_PRODUCTS_DIR; };
|
||||
2F03A53E19C5C6DA005002A5 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = "<group>"; };
|
||||
2F03A53F19C5C6DA005002A5 /* HardcoreDataTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = HardcoreDataTests.swift; sourceTree = "<group>"; };
|
||||
2F03A54C19C5C872005002A5 /* CoreData.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = CoreData.framework; path = System/Library/Frameworks/CoreData.framework; sourceTree = SDKROOT; };
|
||||
2F291E2619C6D3CF007AF63F /* HardcoreData.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = HardcoreData.swift; sourceTree = "<group>"; };
|
||||
B5CFD36D1A0775F000B7885F /* SaveResult.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SaveResult.swift; sourceTree = "<group>"; };
|
||||
B5CFF23D19FD1D1C00D6DFC4 /* NSManagedObjectContext+HardcoreData.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "NSManagedObjectContext+HardcoreData.swift"; sourceTree = "<group>"; };
|
||||
B5CFF23F19FD383100D6DFC4 /* DataTransaction.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = DataTransaction.swift; sourceTree = "<group>"; };
|
||||
B5D1E22919FA9E63003B2874 /* PersistentStoreResult.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = PersistentStoreResult.swift; sourceTree = "<group>"; };
|
||||
B5D1E22B19FA9FBC003B2874 /* NSError+HardcoreData.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "NSError+HardcoreData.swift"; sourceTree = "<group>"; };
|
||||
B5D399F019FC818E000E91BB /* DataStack.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = DataStack.swift; sourceTree = "<group>"; };
|
||||
B5D399F419FCF4E0000E91BB /* NSPersistentStoreCoordinator+HardcoreData.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "NSPersistentStoreCoordinator+HardcoreData.swift"; sourceTree = "<group>"; };
|
||||
B5D39A0119FD00C9000E91BB /* Foundation.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Foundation.framework; path = System/Library/Frameworks/Foundation.framework; sourceTree = SDKROOT; };
|
||||
B5D39A0319FD00DE000E91BB /* UIKit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = UIKit.framework; path = System/Library/Frameworks/UIKit.framework; sourceTree = SDKROOT; };
|
||||
B5D806C51A34715700A44484 /* GCDKit.xcodeproj */ = {isa = PBXFileReference; lastKnownFileType = "wrapper.pb-project"; path = GCDKit.xcodeproj; sourceTree = "<group>"; };
|
||||
B5D8074E1A34715700A44484 /* JEToolkit.xcodeproj */ = {isa = PBXFileReference; lastKnownFileType = "wrapper.pb-project"; path = JEToolkit.xcodeproj; sourceTree = "<group>"; };
|
||||
B5E209DF1A0726460089C9D4 /* NSManagedObject+HardcoreData.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "NSManagedObject+HardcoreData.swift"; sourceTree = "<group>"; };
|
||||
B5F3D98419F3EB8E009690A6 /* LICENSE */ = {isa = PBXFileReference; lastKnownFileType = text; path = LICENSE; sourceTree = "<group>"; };
|
||||
B5F5398F1A17A6FC00EC763B /* QueryDescriptor.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = QueryDescriptor.swift; sourceTree = "<group>"; };
|
||||
/* End PBXFileReference section */
|
||||
|
||||
/* Begin PBXFrameworksBuildPhase section */
|
||||
@@ -25,6 +87,11 @@
|
||||
isa = PBXFrameworksBuildPhase;
|
||||
buildActionMask = 2147483647;
|
||||
files = (
|
||||
B5D8080F1A3471A900A44484 /* JEToolkit.framework in Frameworks */,
|
||||
B5D8080E1A3471A500A44484 /* GCDKit.framework in Frameworks */,
|
||||
B5D39A0419FD00DE000E91BB /* UIKit.framework in Frameworks */,
|
||||
B5D39A0219FD00C9000E91BB /* Foundation.framework in Frameworks */,
|
||||
2F03A54D19C5C872005002A5 /* CoreData.framework in Frameworks */,
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
};
|
||||
@@ -41,6 +108,8 @@
|
||||
2F03A52619C5C6DA005002A5 = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
B5D806BB1A34715700A44484 /* Libraries */,
|
||||
2F291E3119C6D4D3007AF63F /* Frameworks */,
|
||||
2F03A53219C5C6DA005002A5 /* HardcoreData */,
|
||||
2F03A53C19C5C6DA005002A5 /* HardcoreDataTests */,
|
||||
2F03A53119C5C6DA005002A5 /* Products */,
|
||||
@@ -59,7 +128,17 @@
|
||||
2F03A53219C5C6DA005002A5 /* HardcoreData */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
B5D399F019FC818E000E91BB /* DataStack.swift */,
|
||||
B5CFF23F19FD383100D6DFC4 /* DataTransaction.swift */,
|
||||
2F03A53519C5C6DA005002A5 /* HardcoreData.h */,
|
||||
2F291E2619C6D3CF007AF63F /* HardcoreData.swift */,
|
||||
B5D1E22B19FA9FBC003B2874 /* NSError+HardcoreData.swift */,
|
||||
B5E209DF1A0726460089C9D4 /* NSManagedObject+HardcoreData.swift */,
|
||||
B5CFF23D19FD1D1C00D6DFC4 /* NSManagedObjectContext+HardcoreData.swift */,
|
||||
B5D399F419FCF4E0000E91BB /* NSPersistentStoreCoordinator+HardcoreData.swift */,
|
||||
B5F5398F1A17A6FC00EC763B /* QueryDescriptor.swift */,
|
||||
B5D1E22919FA9E63003B2874 /* PersistentStoreResult.swift */,
|
||||
B5CFD36D1A0775F000B7885F /* SaveResult.swift */,
|
||||
2F03A53319C5C6DA005002A5 /* Supporting Files */,
|
||||
);
|
||||
path = HardcoreData;
|
||||
@@ -68,6 +147,7 @@
|
||||
2F03A53319C5C6DA005002A5 /* Supporting Files */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
B5F3D98419F3EB8E009690A6 /* LICENSE */,
|
||||
2F03A53419C5C6DA005002A5 /* Info.plist */,
|
||||
);
|
||||
name = "Supporting Files";
|
||||
@@ -90,6 +170,59 @@
|
||||
name = "Supporting Files";
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
2F291E3119C6D4D3007AF63F /* Frameworks */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
2F03A54C19C5C872005002A5 /* CoreData.framework */,
|
||||
B5D39A0119FD00C9000E91BB /* Foundation.framework */,
|
||||
B5D39A0319FD00DE000E91BB /* UIKit.framework */,
|
||||
);
|
||||
name = Frameworks;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
B5D806BB1A34715700A44484 /* Libraries */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
B5D806BC1A34715700A44484 /* GCDKit */,
|
||||
B5D806CD1A34715700A44484 /* JEToolkit */,
|
||||
);
|
||||
path = Libraries;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
B5D806BC1A34715700A44484 /* GCDKit */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
B5D806C51A34715700A44484 /* GCDKit.xcodeproj */,
|
||||
);
|
||||
path = GCDKit;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
B5D806C61A34715700A44484 /* Products */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
B5D808021A34715700A44484 /* GCDKit.framework */,
|
||||
B5D808041A34715700A44484 /* GCDKitTests.xctest */,
|
||||
);
|
||||
name = Products;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
B5D806CD1A34715700A44484 /* JEToolkit */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
B5D8074E1A34715700A44484 /* JEToolkit.xcodeproj */,
|
||||
);
|
||||
path = JEToolkit;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
B5D8074F1A34715700A44484 /* Products */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
B5D808081A34715700A44484 /* JEToolkit.framework */,
|
||||
B5D8080A1A34715700A44484 /* JEToolkitTests.xctest */,
|
||||
);
|
||||
name = Products;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
/* End PBXGroup section */
|
||||
|
||||
/* Begin PBXHeadersBuildPhase section */
|
||||
@@ -162,10 +295,21 @@
|
||||
hasScannedForEncodings = 0;
|
||||
knownRegions = (
|
||||
en,
|
||||
Base,
|
||||
);
|
||||
mainGroup = 2F03A52619C5C6DA005002A5;
|
||||
productRefGroup = 2F03A53119C5C6DA005002A5 /* Products */;
|
||||
projectDirPath = "";
|
||||
projectReferences = (
|
||||
{
|
||||
ProductGroup = B5D806C61A34715700A44484 /* Products */;
|
||||
ProjectRef = B5D806C51A34715700A44484 /* GCDKit.xcodeproj */;
|
||||
},
|
||||
{
|
||||
ProductGroup = B5D8074F1A34715700A44484 /* Products */;
|
||||
ProjectRef = B5D8074E1A34715700A44484 /* JEToolkit.xcodeproj */;
|
||||
},
|
||||
);
|
||||
projectRoot = "";
|
||||
targets = (
|
||||
2F03A52F19C5C6DA005002A5 /* HardcoreData */,
|
||||
@@ -174,6 +318,37 @@
|
||||
};
|
||||
/* End PBXProject section */
|
||||
|
||||
/* Begin PBXReferenceProxy section */
|
||||
B5D808021A34715700A44484 /* GCDKit.framework */ = {
|
||||
isa = PBXReferenceProxy;
|
||||
fileType = wrapper.framework;
|
||||
path = GCDKit.framework;
|
||||
remoteRef = B5D808011A34715700A44484 /* PBXContainerItemProxy */;
|
||||
sourceTree = BUILT_PRODUCTS_DIR;
|
||||
};
|
||||
B5D808041A34715700A44484 /* GCDKitTests.xctest */ = {
|
||||
isa = PBXReferenceProxy;
|
||||
fileType = wrapper.cfbundle;
|
||||
path = GCDKitTests.xctest;
|
||||
remoteRef = B5D808031A34715700A44484 /* PBXContainerItemProxy */;
|
||||
sourceTree = BUILT_PRODUCTS_DIR;
|
||||
};
|
||||
B5D808081A34715700A44484 /* JEToolkit.framework */ = {
|
||||
isa = PBXReferenceProxy;
|
||||
fileType = wrapper.framework;
|
||||
path = JEToolkit.framework;
|
||||
remoteRef = B5D808071A34715700A44484 /* PBXContainerItemProxy */;
|
||||
sourceTree = BUILT_PRODUCTS_DIR;
|
||||
};
|
||||
B5D8080A1A34715700A44484 /* JEToolkitTests.xctest */ = {
|
||||
isa = PBXReferenceProxy;
|
||||
fileType = wrapper.cfbundle;
|
||||
path = JEToolkitTests.xctest;
|
||||
remoteRef = B5D808091A34715700A44484 /* PBXContainerItemProxy */;
|
||||
sourceTree = BUILT_PRODUCTS_DIR;
|
||||
};
|
||||
/* End PBXReferenceProxy section */
|
||||
|
||||
/* Begin PBXResourcesBuildPhase section */
|
||||
2F03A52E19C5C6DA005002A5 /* Resources */ = {
|
||||
isa = PBXResourcesBuildPhase;
|
||||
@@ -196,6 +371,16 @@
|
||||
isa = PBXSourcesBuildPhase;
|
||||
buildActionMask = 2147483647;
|
||||
files = (
|
||||
B5F539901A17A6FC00EC763B /* QueryDescriptor.swift in Sources */,
|
||||
B5CFF24019FD383100D6DFC4 /* DataTransaction.swift in Sources */,
|
||||
B5D399F519FCF4E0000E91BB /* NSPersistentStoreCoordinator+HardcoreData.swift in Sources */,
|
||||
B5CFD36E1A0775F000B7885F /* SaveResult.swift in Sources */,
|
||||
B5D1E22C19FA9FBC003B2874 /* NSError+HardcoreData.swift in Sources */,
|
||||
B5CFF23E19FD1D1C00D6DFC4 /* NSManagedObjectContext+HardcoreData.swift in Sources */,
|
||||
2F291E2719C6D3CF007AF63F /* HardcoreData.swift in Sources */,
|
||||
B5E209E01A0726460089C9D4 /* NSManagedObject+HardcoreData.swift in Sources */,
|
||||
B5D1E22A19FA9E63003B2874 /* PersistentStoreResult.swift in Sources */,
|
||||
B5D399F119FC818E000E91BB /* DataStack.swift in Sources */,
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
};
|
||||
@@ -245,7 +430,7 @@
|
||||
GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
|
||||
GCC_WARN_UNUSED_FUNCTION = YES;
|
||||
GCC_WARN_UNUSED_VARIABLE = YES;
|
||||
IPHONEOS_DEPLOYMENT_TARGET = 8.0;
|
||||
IPHONEOS_DEPLOYMENT_TARGET = 8.1;
|
||||
MTL_ENABLE_DEBUG_INFO = YES;
|
||||
ONLY_ACTIVE_ARCH = YES;
|
||||
SDKROOT = iphoneos;
|
||||
@@ -285,7 +470,7 @@
|
||||
GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
|
||||
GCC_WARN_UNUSED_FUNCTION = YES;
|
||||
GCC_WARN_UNUSED_VARIABLE = YES;
|
||||
IPHONEOS_DEPLOYMENT_TARGET = 8.0;
|
||||
IPHONEOS_DEPLOYMENT_TARGET = 8.1;
|
||||
MTL_ENABLE_DEBUG_INFO = NO;
|
||||
SDKROOT = iphoneos;
|
||||
TARGETED_DEVICE_FAMILY = "1,2";
|
||||
@@ -298,25 +483,46 @@
|
||||
2F03A54419C5C6DA005002A5 /* Debug */ = {
|
||||
isa = XCBuildConfiguration;
|
||||
buildSettings = {
|
||||
CLANG_ENABLE_MODULES = YES;
|
||||
DEFINES_MODULE = YES;
|
||||
DYLIB_COMPATIBILITY_VERSION = 1;
|
||||
DYLIB_CURRENT_VERSION = 1;
|
||||
DYLIB_INSTALL_NAME_BASE = "@rpath";
|
||||
EMBEDDED_CONTENT_CONTAINS_SWIFT = YES;
|
||||
FRAMEWORK_SEARCH_PATHS = (
|
||||
"$(inherited)",
|
||||
/Users/johnestropia/Documents/XCode,
|
||||
"Projects/JEToolkit/build/Debug-iphoneos",
|
||||
"$(USER_LIBRARY_DIR)/Developer/Xcode/DerivedData/PhotoSearch-dzwflhandxxuvngptapvysfpcwdx/Build/Products/Debug-iphoneos",
|
||||
/Users/johnestropia/Documents/XCode,
|
||||
"Projects/JEToolkit/build/Debug-iphoneos",
|
||||
);
|
||||
INFOPLIST_FILE = HardcoreData/Info.plist;
|
||||
INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks";
|
||||
LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks";
|
||||
PRODUCT_NAME = "$(TARGET_NAME)";
|
||||
SKIP_INSTALL = YES;
|
||||
SWIFT_OPTIMIZATION_LEVEL = "-Onone";
|
||||
};
|
||||
name = Debug;
|
||||
};
|
||||
2F03A54519C5C6DA005002A5 /* Release */ = {
|
||||
isa = XCBuildConfiguration;
|
||||
buildSettings = {
|
||||
CLANG_ENABLE_MODULES = YES;
|
||||
DEFINES_MODULE = YES;
|
||||
DYLIB_COMPATIBILITY_VERSION = 1;
|
||||
DYLIB_CURRENT_VERSION = 1;
|
||||
DYLIB_INSTALL_NAME_BASE = "@rpath";
|
||||
EMBEDDED_CONTENT_CONTAINS_SWIFT = YES;
|
||||
FRAMEWORK_SEARCH_PATHS = (
|
||||
"$(inherited)",
|
||||
/Users/johnestropia/Documents/XCode,
|
||||
"Projects/JEToolkit/build/Debug-iphoneos",
|
||||
"$(USER_LIBRARY_DIR)/Developer/Xcode/DerivedData/PhotoSearch-dzwflhandxxuvngptapvysfpcwdx/Build/Products/Debug-iphoneos",
|
||||
/Users/johnestropia/Documents/XCode,
|
||||
"Projects/JEToolkit/build/Debug-iphoneos",
|
||||
);
|
||||
INFOPLIST_FILE = HardcoreData/Info.plist;
|
||||
INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks";
|
||||
LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks";
|
||||
@@ -374,6 +580,7 @@
|
||||
2F03A54519C5C6DA005002A5 /* Release */,
|
||||
);
|
||||
defaultConfigurationIsVisible = 0;
|
||||
defaultConfigurationName = Release;
|
||||
};
|
||||
2F03A54619C5C6DA005002A5 /* Build configuration list for PBXNativeTarget "HardcoreDataTests" */ = {
|
||||
isa = XCConfigurationList;
|
||||
@@ -382,6 +589,7 @@
|
||||
2F03A54819C5C6DA005002A5 /* Release */,
|
||||
);
|
||||
defaultConfigurationIsVisible = 0;
|
||||
defaultConfigurationName = Release;
|
||||
};
|
||||
/* End XCConfigurationList section */
|
||||
};
|
||||
|
||||
281
HardcoreData/DataStack.swift
Normal file
281
HardcoreData/DataStack.swift
Normal file
@@ -0,0 +1,281 @@
|
||||
//
|
||||
// DataStack.swift
|
||||
// HardcoreData
|
||||
//
|
||||
// Copyright (c) 2014 John Rommel Estropia
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
// of this software and associated documentation files (the "Software"), to deal
|
||||
// in the Software without restriction, including without limitation the rights
|
||||
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
// copies of the Software, and to permit persons to whom the Software is
|
||||
// furnished to do so, subject to the following conditions:
|
||||
//
|
||||
// The above copyright notice and this permission notice shall be included in all
|
||||
// copies or substantial portions of the Software.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
// SOFTWARE.
|
||||
//
|
||||
|
||||
import Foundation
|
||||
import CoreData
|
||||
import GCDKit
|
||||
|
||||
/**
|
||||
The DataStack encapsulates the data model for the Core Data stack. Each DataStack can have multiple data stores, usually specified as a "Configuration" in the model editor. Behind the scenes, the DataStack manages its own NSPersistentStoreCoordinator, a root NSManagedObjectContext for disk saves, and a shared NSManagedObjectContext acting as a model interface for NSManagedObjects.
|
||||
*/
|
||||
public class DataStack: NSObject {
|
||||
|
||||
// MARK: - Public
|
||||
|
||||
/**
|
||||
Initializes a DataStack from merged model in the app bundle.
|
||||
*/
|
||||
public convenience override init() {
|
||||
|
||||
self.init(managedObjectModel: NSManagedObjectModel.mergedModelFromBundles(nil)!)
|
||||
}
|
||||
|
||||
/**
|
||||
Initializes a DataStack from the specified model name.
|
||||
|
||||
:param: modelName the name of the (.xcdatamodeld) model file.
|
||||
*/
|
||||
public convenience init(modelName: String) {
|
||||
|
||||
let modelFilePath = NSBundle.mainBundle().pathForResource(modelName, ofType: "momd")!
|
||||
let managedObjectModel = NSManagedObjectModel(contentsOfURL: NSURL(fileURLWithPath: modelFilePath)!)!
|
||||
|
||||
self.init(managedObjectModel: managedObjectModel)
|
||||
}
|
||||
|
||||
/**
|
||||
Initializes a DataStack from an NSManagedObjectModel.
|
||||
|
||||
:param: modelName the name of the "momd" (or xcdatamodeld) file.
|
||||
*/
|
||||
public required init(managedObjectModel: NSManagedObjectModel) {
|
||||
|
||||
self.coordinator = NSPersistentStoreCoordinator(managedObjectModel: managedObjectModel)
|
||||
self.rootSavingContext = NSManagedObjectContext.rootSavingContextForCoordinator(self.coordinator)
|
||||
self.mainContext = NSManagedObjectContext.mainContextForRootContext(self.rootSavingContext)
|
||||
self.transactionQueue = .createSerial("com.hardcoredata.datastack.transactionqueue")
|
||||
|
||||
super.init()
|
||||
}
|
||||
|
||||
/**
|
||||
Adds an in-memory store to the stack.
|
||||
|
||||
:param: configuration an optional configuration name from the model file. If not specified, defaults to nil.
|
||||
:returns: a PersistentStoreResult indicating success or failure.
|
||||
*/
|
||||
public func addInMemoryStore(configuration: String? = nil) -> PersistentStoreResult {
|
||||
|
||||
let coordinator = self.coordinator;
|
||||
var persistentStoreError: NSError?
|
||||
|
||||
var store: NSPersistentStore?
|
||||
coordinator.performSynchronously {
|
||||
|
||||
store = coordinator.addPersistentStoreWithType(
|
||||
NSInMemoryStoreType,
|
||||
configuration: configuration,
|
||||
URL: nil,
|
||||
options: nil,
|
||||
error: &persistentStoreError)
|
||||
}
|
||||
|
||||
if let store = store {
|
||||
|
||||
return PersistentStoreResult(store)
|
||||
}
|
||||
|
||||
if let error = persistentStoreError {
|
||||
|
||||
HardcoreData.handleError(
|
||||
error,
|
||||
message: "Failed to add in-memory NSPersistentStore.")
|
||||
return PersistentStoreResult(error)
|
||||
}
|
||||
else {
|
||||
|
||||
HardcoreData.handleError(
|
||||
NSError(hardcoreDataErrorCode: .UnknownError),
|
||||
message: "Failed to add in-memory NSPersistentStore.")
|
||||
}
|
||||
return PersistentStoreResult(.UnknownError)
|
||||
}
|
||||
|
||||
/**
|
||||
Adds to the stack an SQLite store from the given SQLite file name.
|
||||
|
||||
:param: fileName the local filename for the SQLite persistent store in the "Application Support" directory. A new SQLite file will be created if it does not exist.
|
||||
:param: configuration an optional configuration name from the model file. If not specified, defaults to nil.
|
||||
:param: automigrating Set to true to configure Core Data auto-migration, or false to disable. If not specified, defaults to true.
|
||||
:param: resetStoreOnMigrationFailure Set to true to delete the store on migration failure; or set to false to throw exceptions on failure instead. Typically should only be set to true when debugging, or if the persistent store can be recreated easily. If not specified, defaults to false
|
||||
:returns: a PersistentStoreResult indicating success or failure.
|
||||
*/
|
||||
public func addSQLiteStore(fileName: String, configuration: String? = nil, automigrating: Bool = true, resetStoreOnMigrationFailure: Bool = false) -> PersistentStoreResult {
|
||||
|
||||
return self.addSQLiteStore(
|
||||
fileURL: NSURL.applicationSupportDirectory().URLByAppendingPathComponent(fileName, isDirectory: false),
|
||||
configuration: configuration,
|
||||
automigrating: automigrating,
|
||||
resetStoreOnMigrationFailure: resetStoreOnMigrationFailure)
|
||||
}
|
||||
|
||||
/**
|
||||
Adds to the stack an SQLite store from the given SQLite file URL.
|
||||
|
||||
:param: fileURL the local file URL for the SQLite persistent store. A new SQLite file will be created if it does not exist. If not specified, defaults to a file URL pointing to a "<Application name>.sqlite" file in the "Application Support" directory.
|
||||
:param: configuration an optional configuration name from the model file. If not specified, defaults to nil.
|
||||
:param: automigrating Set to true to configure Core Data auto-migration, or false to disable. If not specified, defaults to true.
|
||||
:param: resetStoreOnMigrationFailure Set to true to delete the store on migration failure; or set to false to throw exceptions on failure instead. Typically should only be set to true when debugging, or if the persistent store can be recreated easily. If not specified, defaults to false.
|
||||
:returns: a PersistentStoreResult indicating success or failure.
|
||||
*/
|
||||
public func addSQLiteStore(fileURL: NSURL = NSURL.applicationSupportDirectory().URLByAppendingPathComponent(NSString.applicationName(), isDirectory: true).URLByAppendingPathExtension("sqlite"), configuration: String? = nil, automigrating: Bool = true, resetStoreOnMigrationFailure: Bool = false) -> PersistentStoreResult {
|
||||
|
||||
let coordinator = self.coordinator;
|
||||
if let store = coordinator.persistentStoreForURL(fileURL) {
|
||||
|
||||
let isExistingStoreAutomigrating = ((store.options?[NSMigratePersistentStoresAutomaticallyOption] as? Bool) ?? false)
|
||||
|
||||
if store.type == NSSQLiteStoreType
|
||||
&& isExistingStoreAutomigrating == automigrating {
|
||||
|
||||
return PersistentStoreResult(store)
|
||||
}
|
||||
|
||||
HardcoreData.handleError(
|
||||
NSError(hardcoreDataErrorCode: .DifferentPersistentStoreExistsAtURL),
|
||||
message: "Failed to add SQLite NSPersistentStore at \"\(fileURL)\" because a different NSPersistentStore at that URL already exists.")
|
||||
return PersistentStoreResult(.DifferentPersistentStoreExistsAtURL)
|
||||
}
|
||||
|
||||
let fileManager = NSFileManager.defaultManager()
|
||||
var directoryError: NSError?
|
||||
if !fileManager.createDirectoryAtURL(
|
||||
fileURL.URLByDeletingLastPathComponent!,
|
||||
withIntermediateDirectories: true,
|
||||
attributes: nil,
|
||||
error: &directoryError) {
|
||||
|
||||
HardcoreData.handleError(
|
||||
directoryError!,
|
||||
message: "Failed to create directory for SQLite store at \"\(fileURL)\".")
|
||||
return PersistentStoreResult(directoryError!)
|
||||
}
|
||||
|
||||
var store: NSPersistentStore?
|
||||
var persistentStoreError: NSError?
|
||||
coordinator.performSynchronously {
|
||||
|
||||
store = coordinator.addPersistentStoreWithType(
|
||||
NSSQLiteStoreType,
|
||||
configuration: configuration,
|
||||
URL: fileURL,
|
||||
options: [NSSQLitePragmasOption: ["WAL": "journal_mode"],
|
||||
NSInferMappingModelAutomaticallyOption: true,
|
||||
NSMigratePersistentStoresAutomaticallyOption: automigrating],
|
||||
error: &persistentStoreError)
|
||||
}
|
||||
|
||||
if let store = store {
|
||||
|
||||
return PersistentStoreResult(store)
|
||||
}
|
||||
|
||||
if let error = persistentStoreError {
|
||||
|
||||
if resetStoreOnMigrationFailure
|
||||
&& (error.code == NSPersistentStoreIncompatibleVersionHashError
|
||||
|| error.code == NSMigrationMissingSourceModelError)
|
||||
&& error.domain == NSCocoaErrorDomain {
|
||||
|
||||
fileManager.removeItemAtURL(fileURL, error: nil)
|
||||
fileManager.removeItemAtPath(
|
||||
fileURL.absoluteString!.stringByAppendingString("-shm"),
|
||||
error: nil)
|
||||
fileManager.removeItemAtPath(
|
||||
fileURL.absoluteString!.stringByAppendingString("-wal"),
|
||||
error: nil)
|
||||
|
||||
var store: NSPersistentStore?
|
||||
coordinator.performSynchronously {
|
||||
|
||||
store = coordinator.addPersistentStoreWithType(
|
||||
NSSQLiteStoreType,
|
||||
configuration: configuration,
|
||||
URL: fileURL,
|
||||
options: [NSSQLitePragmasOption: ["WAL": "journal_mode"],
|
||||
NSInferMappingModelAutomaticallyOption: true,
|
||||
NSMigratePersistentStoresAutomaticallyOption: automigrating],
|
||||
error: &persistentStoreError)
|
||||
}
|
||||
|
||||
if let store = store {
|
||||
|
||||
return PersistentStoreResult(store)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if let error = persistentStoreError {
|
||||
|
||||
HardcoreData.handleError(
|
||||
error,
|
||||
message: "Failed to add SQLite NSPersistentStore at \"\(fileURL)\".")
|
||||
return PersistentStoreResult(error)
|
||||
}
|
||||
else {
|
||||
|
||||
HardcoreData.handleError(
|
||||
NSError(hardcoreDataErrorCode: .UnknownError),
|
||||
message: "Failed to add SQLite NSPersistentStore at \"\(fileURL)\".")
|
||||
}
|
||||
return PersistentStoreResult(.UnknownError)
|
||||
}
|
||||
|
||||
/**
|
||||
Begins a transaction asynchronously where NSManagedObject creates, updates, and deletes can be made.
|
||||
|
||||
:param: closure the block where creates, updates, and deletes can be made to the transaction. Transaction blocks are executed serially in a background queue, and all changes are made from a concurrent NSManagedObjectContext.
|
||||
*/
|
||||
public func performTransaction(closure: (transaction: DataTransaction) -> ()) {
|
||||
|
||||
let transaction = DataTransaction(
|
||||
mainContext: self.mainContext,
|
||||
queue: self.transactionQueue,
|
||||
closure: closure)
|
||||
transaction.perform()
|
||||
}
|
||||
|
||||
/**
|
||||
Begins a transaction synchronously where NSManagedObject creates, updates, and deletes can be made.
|
||||
|
||||
:param: closure the block where creates, updates, and deletes can be made to the transaction. Transaction blocks are executed serially in a background queue, and all changes are made from a concurrent NSManagedObjectContext.
|
||||
:returns: a SaveResult value indicating success or failure.
|
||||
*/
|
||||
public func performTransactionAndWait(closure: (transaction: DataTransaction) -> ()) -> SaveResult {
|
||||
|
||||
let transaction = DataTransaction(
|
||||
mainContext: self.mainContext,
|
||||
queue: self.transactionQueue,
|
||||
closure: closure)
|
||||
return transaction.performAndWait()
|
||||
}
|
||||
|
||||
// MARK: - Internal
|
||||
|
||||
private let coordinator: NSPersistentStoreCoordinator
|
||||
private let rootSavingContext: NSManagedObjectContext
|
||||
private let mainContext: NSManagedObjectContext
|
||||
private let transactionQueue: GCDQueue;
|
||||
}
|
||||
162
HardcoreData/DataTransaction.swift
Normal file
162
HardcoreData/DataTransaction.swift
Normal file
@@ -0,0 +1,162 @@
|
||||
//
|
||||
// DataTransaction.swift
|
||||
// HardcoreData
|
||||
//
|
||||
// Copyright (c) 2014 John Rommel Estropia
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
// of this software and associated documentation files (the "Software"), to deal
|
||||
// in the Software without restriction, including without limitation the rights
|
||||
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
// copies of the Software, and to permit persons to whom the Software is
|
||||
// furnished to do so, subject to the following conditions:
|
||||
//
|
||||
// The above copyright notice and this permission notice shall be included in all
|
||||
// copies or substantial portions of the Software.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
// SOFTWARE.
|
||||
//
|
||||
|
||||
import Foundation
|
||||
import CoreData
|
||||
import GCDKit
|
||||
|
||||
/**
|
||||
The DataTransaction provides an interface for NSManagedObject creates, updates, and deletes. A transaction object should typically be only used from within a transaction block initiated from DataStack.performTransaction(_:), or from HardcoreData.performTransaction(_:).
|
||||
*/
|
||||
public class DataTransaction {
|
||||
|
||||
// MARK: - Public
|
||||
|
||||
/**
|
||||
The background concurrent context managed by the transaction.
|
||||
*/
|
||||
public let context: NSManagedObjectContext
|
||||
|
||||
// MARK: Object management
|
||||
|
||||
/**
|
||||
Creates a new NSManagedObject with the specified entity type. Note that this method should not be used after either the commit(_:) or commitAndWait() method was already called once.
|
||||
|
||||
:param: entity the NSManagedObject type to be created
|
||||
:returns: a new NSManagedObject instance of the specified entity type.
|
||||
*/
|
||||
public func create<T: NSManagedObject>(entity: T.Type) -> T {
|
||||
|
||||
HardcoreData.assert(self.transactionQueue.isCurrentExecutionContext() == true, "Attempted to create an NSManagedObject outside a transaction queue.")
|
||||
HardcoreData.assert(!self.isTransactionCommited, "Attempted to create an NSManagedObject from an already commited DataTransaction.")
|
||||
return T.createInContext(self.context)
|
||||
}
|
||||
|
||||
/**
|
||||
Returns an editable proxy of a specified NSManagedObject. Note that this method should not be used after either the commit(_:) or commitAndWait() method was already called once.
|
||||
|
||||
:param: object the NSManagedObject type to be edited
|
||||
:returns: an editable proxy for the specified NSManagedObject.
|
||||
*/
|
||||
public func update<T: NSManagedObject>(object: T) -> T? {
|
||||
|
||||
HardcoreData.assert(self.transactionQueue.isCurrentExecutionContext() == true, "Attempted to update an NSManagedObject outside a transaction queue.")
|
||||
HardcoreData.assert(!self.isTransactionCommited, "Attempted to update an NSManagedObject from an already commited DataTransaction.")
|
||||
return object.inContext(self.context)
|
||||
}
|
||||
|
||||
/**
|
||||
Deletes a specified NSManagedObject. Note that this method should not be used after either the commit(_:) or commitAndWait() method was already called once.
|
||||
|
||||
:param: object the NSManagedObject type to be deleted
|
||||
*/
|
||||
public func delete(object: NSManagedObject) {
|
||||
|
||||
HardcoreData.assert(self.transactionQueue.isCurrentExecutionContext() == true, "Attempted to delete an NSManagedObject outside a transaction queue.")
|
||||
HardcoreData.assert(!self.isTransactionCommited, "Attempted to delete an NSManagedObject from an already commited DataTransaction.")
|
||||
object.deleteFromContext()
|
||||
}
|
||||
|
||||
// MARK: Saving changes
|
||||
|
||||
/**
|
||||
Saves the transaction changes asynchronously. Note that this method should not be used after either the commit(_:) or commitAndWait() method was already called once.
|
||||
|
||||
:param: completion the block executed after the save completes. Success or failure is reported by the SaveResult argument of the block.
|
||||
*/
|
||||
public func commit(completion: (result: SaveResult) -> ()) {
|
||||
|
||||
HardcoreData.assert(self.transactionQueue.isCurrentExecutionContext() == true, "Attempted to commit a DataTransaction outside a transaction queue.")
|
||||
HardcoreData.assert(!self.isTransactionCommited, "Attempted to commit a DataTransaction more than once.")
|
||||
|
||||
self.isTransactionCommited = true
|
||||
self.context.saveAsynchronouslyWithCompletion { [weak self] (result) -> () in
|
||||
|
||||
self?.result = result
|
||||
completion(result: result)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
Saves the transaction changes and waits for completion synchronously. Note that this method should not be used after either the commit(_:) or commitAndWait() method was already called once.
|
||||
|
||||
:returns: a SaveResult value indicating success or failure.
|
||||
*/
|
||||
public func commitAndWait() -> SaveResult {
|
||||
|
||||
HardcoreData.assert(self.transactionQueue.isCurrentExecutionContext() == true, "Attempted to commit a DataTransaction outside a transaction queue.")
|
||||
HardcoreData.assert(!self.isTransactionCommited, "Attempted to commit a DataTransaction more than once.")
|
||||
|
||||
self.isTransactionCommited = true
|
||||
let result = self.context.saveSynchronously()
|
||||
self.result = result
|
||||
return result
|
||||
}
|
||||
|
||||
|
||||
// MARK: - Internal
|
||||
|
||||
internal init(mainContext: NSManagedObjectContext, queue: GCDQueue, closure: (transaction: DataTransaction) -> ()) {
|
||||
|
||||
self.mainContext = mainContext
|
||||
self.transactionQueue = queue
|
||||
self.context = mainContext.temporaryContext()
|
||||
self.closure = closure
|
||||
}
|
||||
|
||||
internal func perform() {
|
||||
|
||||
self.transactionQueue.barrierAsync {
|
||||
|
||||
self.closure(transaction: self)
|
||||
if !self.isTransactionCommited {
|
||||
|
||||
self.commit { (result) -> () in }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
internal func performAndWait() -> SaveResult {
|
||||
|
||||
self.transactionQueue.barrierSync {
|
||||
|
||||
self.closure(transaction: self)
|
||||
if !self.isTransactionCommited {
|
||||
|
||||
self.commitAndWait()
|
||||
}
|
||||
}
|
||||
return self.result!
|
||||
}
|
||||
|
||||
|
||||
// MARK: - Private
|
||||
|
||||
private var isTransactionCommited = false
|
||||
private var result: SaveResult?
|
||||
private let mainContext: NSManagedObjectContext
|
||||
private let transactionQueue: GCDQueue
|
||||
private let closure: (transaction: DataTransaction) -> ()
|
||||
}
|
||||
@@ -2,18 +2,29 @@
|
||||
// HardcoreData.h
|
||||
// HardcoreData
|
||||
//
|
||||
// Created by John Rommel Estropia on 2014/09/14.
|
||||
// Copyright (c) 2014 John Rommel Estropia. All rights reserved.
|
||||
// Copyright (c) 2014 John Rommel Estropia
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
// of this software and associated documentation files (the "Software"), to deal
|
||||
// in the Software without restriction, including without limitation the rights
|
||||
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
// copies of the Software, and to permit persons to whom the Software is
|
||||
// furnished to do so, subject to the following conditions:
|
||||
//
|
||||
// The above copyright notice and this permission notice shall be included in all
|
||||
// copies or substantial portions of the Software.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
// SOFTWARE.
|
||||
//
|
||||
|
||||
#import <UIKit/UIKit.h>
|
||||
#import <CoreData/CoreData.h>
|
||||
|
||||
//! Project version number for HardcoreData.
|
||||
FOUNDATION_EXPORT double HardcoreDataVersionNumber;
|
||||
|
||||
//! Project version string for HardcoreData.
|
||||
FOUNDATION_EXPORT const unsigned char HardcoreDataVersionString[];
|
||||
|
||||
// In this header, you should import all the public headers of your framework using statements like #import <HardcoreData/PublicHeader.h>
|
||||
|
||||
|
||||
|
||||
102
HardcoreData/HardcoreData.swift
Normal file
102
HardcoreData/HardcoreData.swift
Normal file
@@ -0,0 +1,102 @@
|
||||
//
|
||||
// HardcoreData.swift
|
||||
// HardcoreData
|
||||
//
|
||||
// Copyright (c) 2014 John Rommel Estropia
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
// of this software and associated documentation files (the "Software"), to deal
|
||||
// in the Software without restriction, including without limitation the rights
|
||||
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
// copies of the Software, and to permit persons to whom the Software is
|
||||
// furnished to do so, subject to the following conditions:
|
||||
//
|
||||
// The above copyright notice and this permission notice shall be included in all
|
||||
// copies or substantial portions of the Software.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
// SOFTWARE.
|
||||
//
|
||||
|
||||
import CoreData
|
||||
import JEToolkit
|
||||
|
||||
/**
|
||||
HardcoreData - Simple, elegant, and smart Core Data management with Swift
|
||||
|
||||
The HardcoreData struct is the main entry point for all other APIs.
|
||||
*/
|
||||
public struct HardcoreData {
|
||||
|
||||
/**
|
||||
The default DataStack instance to be used. If defaultStack is not set before the first time accessed, a default-configured DataStack will be created.
|
||||
|
||||
Note that changing the defaultStack is not thread safe.
|
||||
*/
|
||||
public static var defaultStack = DataStack()
|
||||
|
||||
/**
|
||||
The closure that handles all errors that occur within HardcoreData. The default errorHandler logs errors via JEDumpAlert().
|
||||
*/
|
||||
public static var errorHandler = { (error: NSError, message: String, fileName: String, lineNumber: UWord, functionName: StaticString) -> () in
|
||||
|
||||
JEDumpAlert(
|
||||
error,
|
||||
message,
|
||||
fileName: fileName,
|
||||
lineNumber: lineNumber,
|
||||
functionName: functionName)
|
||||
}
|
||||
|
||||
public static var assertHandler = { (condition: @autoclosure() -> Bool, message: String, fileName: String, lineNumber: UWord, functionName: StaticString) -> () in
|
||||
|
||||
JEAssert(
|
||||
condition,
|
||||
message,
|
||||
fileName: fileName,
|
||||
lineNumber: lineNumber,
|
||||
functionName: functionName)
|
||||
}
|
||||
|
||||
public static var logHandler = { (message: String, fileName: String, lineNumber: Int32, functionName: String) -> () in
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
Using the defaultStack, begins a transaction asynchronously where NSManagedObject creates, updates, and deletes can be made.
|
||||
|
||||
:param: closure the block where creates, updates, and deletes can be made to the transaction. Transaction blocks are executed serially in a background queue, and all changes are made from a concurrent NSManagedObjectContext.
|
||||
*/
|
||||
public static func performTransaction(closure: (transaction: DataTransaction) -> ()) {
|
||||
|
||||
self.defaultStack.performTransaction(closure)
|
||||
}
|
||||
|
||||
/**
|
||||
Using the defaultStack, begins a transaction asynchronously where NSManagedObject creates, updates, and deletes can be made.
|
||||
|
||||
:param: closure the block where creates, updates, and deletes can be made to the transaction. Transaction blocks are executed serially in a background queue, and all changes are made from a concurrent NSManagedObjectContext.
|
||||
:returns: a SaveResult value indicating success or failure.
|
||||
*/
|
||||
public static func performTransactionAndWait(closure: (transaction: DataTransaction) -> ()) -> SaveResult {
|
||||
|
||||
return self.defaultStack.performTransactionAndWait(closure)
|
||||
}
|
||||
|
||||
internal static func handleError(error: NSError, _ message: String, fileName: String = __FILE__, lineNumber: UWord = __LINE__, functionName: StaticString = __FUNCTION__) {
|
||||
|
||||
self.errorHandler(error, message, fileName.lastPathComponent, lineNumber, functionName)
|
||||
}
|
||||
|
||||
internal static func assert(condition: @autoclosure() -> Bool, _ message: String, fileName: String = __FILE__, lineNumber: UWord = __LINE__, functionName: StaticString = __FUNCTION__) {
|
||||
|
||||
self.assertHandler(condition, message, fileName.lastPathComponent, lineNumber, functionName)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
21
HardcoreData/LICENSE
Normal file
21
HardcoreData/LICENSE
Normal file
@@ -0,0 +1,21 @@
|
||||
The MIT License (MIT)
|
||||
|
||||
Copyright (c) 2014 John Rommel Estropia
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
||||
73
HardcoreData/NSError+HardcoreData.swift
Normal file
73
HardcoreData/NSError+HardcoreData.swift
Normal file
@@ -0,0 +1,73 @@
|
||||
//
|
||||
// NSError+HardcoreData.swift
|
||||
// HardcoreData
|
||||
//
|
||||
// Copyright (c) 2014 John Rommel Estropia
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
// of this software and associated documentation files (the "Software"), to deal
|
||||
// in the Software without restriction, including without limitation the rights
|
||||
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
// copies of the Software, and to permit persons to whom the Software is
|
||||
// furnished to do so, subject to the following conditions:
|
||||
//
|
||||
// The above copyright notice and this permission notice shall be included in all
|
||||
// copies or substantial portions of the Software.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
// SOFTWARE.
|
||||
//
|
||||
|
||||
import Foundation
|
||||
|
||||
/**
|
||||
The NSError error domain for HardcoreData.
|
||||
*/
|
||||
public let HardcoreDataErrorDomain = "com.hardcoredata.error"
|
||||
|
||||
/**
|
||||
The NSError error codes for HardcoreDataErrorDomain.
|
||||
*/
|
||||
public enum HardcoreDataErrorCode: Int {
|
||||
|
||||
/**
|
||||
A failure occured because of an unknown error.
|
||||
*/
|
||||
case UnknownError
|
||||
|
||||
/**
|
||||
The NSPersistentStore could note be initialized because another store existed at the specified NSURL.
|
||||
*/
|
||||
case DifferentPersistentStoreExistsAtURL
|
||||
}
|
||||
|
||||
public extension NSError {
|
||||
|
||||
/**
|
||||
If the error's domain is HardcoreDataErrorDomain, returns the associated HardcoreDataErrorCode. For other domains, returns nil.
|
||||
*/
|
||||
public var hardcoreDataErrorCode: HardcoreDataErrorCode? {
|
||||
|
||||
return (self.domain == HardcoreDataErrorDomain
|
||||
? HardcoreDataErrorCode(rawValue: self.code)
|
||||
: nil)
|
||||
}
|
||||
|
||||
internal convenience init(hardcoreDataErrorCode: HardcoreDataErrorCode) {
|
||||
|
||||
self.init(hardcoreDataErrorCode: hardcoreDataErrorCode, userInfo: nil)
|
||||
}
|
||||
|
||||
internal convenience init(hardcoreDataErrorCode: HardcoreDataErrorCode, userInfo: [NSObject: AnyObject]?) {
|
||||
|
||||
self.init(
|
||||
domain: HardcoreDataErrorDomain,
|
||||
code: hardcoreDataErrorCode.rawValue,
|
||||
userInfo: userInfo)
|
||||
}
|
||||
}
|
||||
73
HardcoreData/NSManagedObject+HardcoreData.swift
Normal file
73
HardcoreData/NSManagedObject+HardcoreData.swift
Normal file
@@ -0,0 +1,73 @@
|
||||
//
|
||||
// NSManagedObject+HardcoreData.swift
|
||||
// HardcoreData
|
||||
//
|
||||
// Copyright (c) 2014 John Rommel Estropia
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
// of this software and associated documentation files (the "Software"), to deal
|
||||
// in the Software without restriction, including without limitation the rights
|
||||
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
// copies of the Software, and to permit persons to whom the Software is
|
||||
// furnished to do so, subject to the following conditions:
|
||||
//
|
||||
// The above copyright notice and this permission notice shall be included in all
|
||||
// copies or substantial portions of the Software.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
// SOFTWARE.
|
||||
//
|
||||
|
||||
import Foundation
|
||||
import CoreData
|
||||
|
||||
public extension NSManagedObject {
|
||||
|
||||
public class var entityName: String {
|
||||
|
||||
return self.className().componentsSeparatedByString(".").last!
|
||||
}
|
||||
|
||||
public class func createInContext(context: NSManagedObjectContext) -> Self {
|
||||
|
||||
return self(entity: NSEntityDescription.entityForName(self.entityName, inManagedObjectContext: context)!,
|
||||
insertIntoManagedObjectContext: context)
|
||||
}
|
||||
|
||||
public func inContext<T: NSManagedObject>(context: NSManagedObjectContext) -> T? {
|
||||
|
||||
let objectID = self.objectID
|
||||
if objectID.temporaryID {
|
||||
|
||||
var permanentIDError: NSError?
|
||||
if !context.obtainPermanentIDsForObjects([self], error: &permanentIDError) {
|
||||
|
||||
HardcoreData.handleError(
|
||||
permanentIDError!,
|
||||
message: "Failed to obtain permanent ID for object.")
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
var existingObjectError: NSError?
|
||||
if let existingObject = context.existingObjectWithID(objectID, error: &existingObjectError) {
|
||||
|
||||
return (existingObject as T)
|
||||
}
|
||||
|
||||
HardcoreData.handleError(
|
||||
existingObjectError!,
|
||||
message: "Failed to load existing NSManagedObject in context.")
|
||||
return nil;
|
||||
}
|
||||
|
||||
public func deleteFromContext() {
|
||||
|
||||
self.managedObjectContext?.deleteObject(self)
|
||||
}
|
||||
}
|
||||
302
HardcoreData/NSManagedObjectContext+HardcoreData.swift
Normal file
302
HardcoreData/NSManagedObjectContext+HardcoreData.swift
Normal file
@@ -0,0 +1,302 @@
|
||||
//
|
||||
// NSManagedObjectContext+HardcoreData.swift
|
||||
// HardcoreData
|
||||
//
|
||||
// Copyright (c) 2014 John Rommel Estropia
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
// of this software and associated documentation files (the "Software"), to deal
|
||||
// in the Software without restriction, including without limitation the rights
|
||||
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
// copies of the Software, and to permit persons to whom the Software is
|
||||
// furnished to do so, subject to the following conditions:
|
||||
//
|
||||
// The above copyright notice and this permission notice shall be included in all
|
||||
// copies or substantial portions of the Software.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
// SOFTWARE.
|
||||
//
|
||||
|
||||
import Foundation
|
||||
import CoreData
|
||||
import GCDKit
|
||||
|
||||
private var _HardcoreData_NSManagedObjectContext_shouldCascadeSavesToParent: Void?
|
||||
|
||||
public extension NSManagedObjectContext {
|
||||
|
||||
// MARK: - Public
|
||||
|
||||
// MARK: Transactions
|
||||
|
||||
public func temporaryContext() -> NSManagedObjectContext {
|
||||
|
||||
let context = NSManagedObjectContext(concurrencyType: .PrivateQueueConcurrencyType)
|
||||
context.parentContext = self
|
||||
context.setupForHardcoreDataWithContextName("com.hardcoredata.temporarycontext")
|
||||
context.shouldCascadeSavesToParent = true
|
||||
|
||||
return context
|
||||
}
|
||||
|
||||
|
||||
// MARK: Querying
|
||||
|
||||
public func findFirst<T: NSManagedObject>(entity: T.Type) -> T? {
|
||||
|
||||
return self.findFirst(T.self, predicate: NSPredicate(value: true))
|
||||
}
|
||||
|
||||
public func findFirst<T: NSManagedObject>(entity: T.Type, predicate: NSPredicate) -> T? {
|
||||
|
||||
let fetchRequest = NSFetchRequest()
|
||||
fetchRequest.entity = NSEntityDescription.entityForName(
|
||||
entity.entityName,
|
||||
inManagedObjectContext: self)
|
||||
fetchRequest.fetchLimit = 1
|
||||
|
||||
var fetchResults: [T]?
|
||||
self.performBlockAndWait {
|
||||
|
||||
var error: NSError?
|
||||
fetchResults = self.executeFetchRequest(fetchRequest, error: &error) as? [T]
|
||||
if fetchResults == nil {
|
||||
|
||||
HardcoreData.handleError(
|
||||
error!,
|
||||
message: "Failed executing fetch request.")
|
||||
}
|
||||
}
|
||||
|
||||
return fetchResults?.first
|
||||
}
|
||||
|
||||
public func findAll<T: NSManagedObject>(entity: T.Type) -> [T]? {
|
||||
|
||||
return self.findAll(QueryDescriptor<T>(entity: entity))
|
||||
}
|
||||
|
||||
public func findAll<T: NSManagedObject>(query: QueryDescriptor<T>) -> [T]? {
|
||||
|
||||
let fetchRequest = NSFetchRequest()
|
||||
fetchRequest.entity = NSEntityDescription.entityForName(
|
||||
query.entityName,
|
||||
inManagedObjectContext: self)
|
||||
|
||||
var fetchResults: [T]?
|
||||
self.performBlockAndWait {
|
||||
|
||||
var error: NSError?
|
||||
fetchResults = self.executeFetchRequest(fetchRequest, error: &error) as? [T]
|
||||
if fetchResults == nil {
|
||||
|
||||
HardcoreData.handleError(
|
||||
error!,
|
||||
message: "Failed executing fetch request.")
|
||||
}
|
||||
}
|
||||
|
||||
return fetchResults
|
||||
}
|
||||
|
||||
|
||||
// MARK: - Internal
|
||||
|
||||
internal func saveSynchronously() -> SaveResult {
|
||||
|
||||
var result: SaveResult = SaveResult(hasChanges: false)
|
||||
if !self.hasChanges {
|
||||
|
||||
self.reset()
|
||||
return result
|
||||
}
|
||||
|
||||
self.performBlockAndWait {
|
||||
[unowned self] () -> () in
|
||||
|
||||
var saveError: NSError?
|
||||
if self.save(&saveError) {
|
||||
|
||||
if self.shouldCascadeSavesToParent {
|
||||
|
||||
if let parentContext = self.parentContext {
|
||||
|
||||
switch parentContext.saveSynchronously() {
|
||||
|
||||
case .Success(let hasChanges):
|
||||
result = SaveResult(hasChanges: true)
|
||||
case .Failure(let error):
|
||||
result = SaveResult(error)
|
||||
}
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
result = SaveResult(hasChanges: true)
|
||||
}
|
||||
else if let error = saveError {
|
||||
|
||||
HardcoreData.handleError(
|
||||
error,
|
||||
message: "Failed to save NSManagedObjectContext.")
|
||||
result = SaveResult(error)
|
||||
}
|
||||
else {
|
||||
|
||||
result = SaveResult(hasChanges: false)
|
||||
}
|
||||
}
|
||||
|
||||
return result
|
||||
}
|
||||
|
||||
internal func saveAsynchronouslyWithCompletion(completion: ((result: SaveResult) -> ())?) {
|
||||
|
||||
if !self.hasChanges {
|
||||
|
||||
self.reset()
|
||||
if let completion = completion {
|
||||
|
||||
GCDBlock.async(.Main) {
|
||||
|
||||
completion(result: SaveResult(hasChanges: false))
|
||||
}
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
self.performBlock {
|
||||
[unowned self] () -> () in
|
||||
|
||||
var saveError: NSError?
|
||||
if self.save(&saveError) {
|
||||
|
||||
if self.shouldCascadeSavesToParent {
|
||||
|
||||
if let parentContext = self.parentContext {
|
||||
|
||||
parentContext.saveAsynchronouslyWithCompletion(completion)
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
if let completion = completion {
|
||||
|
||||
GCDBlock.async(.Main) {
|
||||
|
||||
completion(result: SaveResult(hasChanges: true))
|
||||
}
|
||||
}
|
||||
}
|
||||
else if let error = saveError {
|
||||
|
||||
HardcoreData.handleError(
|
||||
error,
|
||||
message: "Failed to save NSManagedObjectContext.")
|
||||
if let completion = completion {
|
||||
|
||||
GCDBlock.async(.Main) {
|
||||
|
||||
completion(result: SaveResult(error))
|
||||
}
|
||||
}
|
||||
}
|
||||
else if let completion = completion {
|
||||
|
||||
GCDBlock.async(.Main) {
|
||||
|
||||
completion(result: SaveResult(hasChanges: false))
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
internal class func rootSavingContextForCoordinator(coordinator: NSPersistentStoreCoordinator) -> NSManagedObjectContext {
|
||||
|
||||
let context = NSManagedObjectContext(concurrencyType: .PrivateQueueConcurrencyType)
|
||||
context.persistentStoreCoordinator = coordinator
|
||||
context.mergePolicy = NSMergeByPropertyObjectTrumpMergePolicy
|
||||
context.setupForHardcoreDataWithContextName("com.hardcoredata.rootcontext")
|
||||
|
||||
return context
|
||||
}
|
||||
|
||||
internal class func mainContextForRootContext(rootContext: NSManagedObjectContext) -> NSManagedObjectContext {
|
||||
|
||||
let context = NSManagedObjectContext(concurrencyType: .MainQueueConcurrencyType)
|
||||
context.parentContext = rootContext
|
||||
context.setupForHardcoreDataWithContextName("com.hardcoredata.maincontext")
|
||||
context.shouldCascadeSavesToParent = true
|
||||
context.registerForNotificationsWithName(
|
||||
NSManagedObjectContextDidSaveNotification,
|
||||
fromObject: rootContext,
|
||||
targetQueue: NSOperationQueue.mainQueue()) {
|
||||
[unowned context] (note) -> () in
|
||||
|
||||
context.mergeChangesFromContextDidSaveNotification(note)
|
||||
}
|
||||
|
||||
return context
|
||||
}
|
||||
|
||||
|
||||
// MARK: - Private
|
||||
|
||||
private var shouldCascadeSavesToParent: Bool {
|
||||
|
||||
get {
|
||||
|
||||
if let value = objc_getAssociatedObject(self, &_HardcoreData_NSManagedObjectContext_shouldCascadeSavesToParent) as? NSNumber {
|
||||
|
||||
return value.boolValue
|
||||
}
|
||||
return false
|
||||
}
|
||||
set {
|
||||
|
||||
objc_setAssociatedObject(
|
||||
self,
|
||||
&_HardcoreData_NSManagedObjectContext_shouldCascadeSavesToParent,
|
||||
newValue,
|
||||
objc_AssociationPolicy(OBJC_ASSOCIATION_ASSIGN))
|
||||
}
|
||||
}
|
||||
|
||||
private func setupForHardcoreDataWithContextName(contextName: String) {
|
||||
|
||||
if self.respondsToSelector("setName:") {
|
||||
|
||||
self.name = contextName
|
||||
}
|
||||
|
||||
self.registerForNotificationsWithName(NSManagedObjectContextWillSaveNotification, fromObject: self) {
|
||||
(note) -> () in
|
||||
|
||||
let context: NSManagedObjectContext = note.object as NSManagedObjectContext
|
||||
let insertedObjects = context.insertedObjects
|
||||
if insertedObjects.count <= 0 {
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
var permanentIDError: NSError?
|
||||
if context.obtainPermanentIDsForObjects(insertedObjects.allObjects, error: &permanentIDError) {
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
if let error = permanentIDError {
|
||||
|
||||
HardcoreData.handleError(
|
||||
error,
|
||||
message: "Failed to obtain permanent IDs for inserted objects.")
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
44
HardcoreData/NSPersistentStoreCoordinator+HardcoreData.swift
Normal file
44
HardcoreData/NSPersistentStoreCoordinator+HardcoreData.swift
Normal file
@@ -0,0 +1,44 @@
|
||||
//
|
||||
// NSPersistentStoreCoordinator+HardcoreData.swift
|
||||
// HardcoreData
|
||||
//
|
||||
// Copyright (c) 2014 John Rommel Estropia
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
// of this software and associated documentation files (the "Software"), to deal
|
||||
// in the Software without restriction, including without limitation the rights
|
||||
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
// copies of the Software, and to permit persons to whom the Software is
|
||||
// furnished to do so, subject to the following conditions:
|
||||
//
|
||||
// The above copyright notice and this permission notice shall be included in all
|
||||
// copies or substantial portions of the Software.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
// SOFTWARE.
|
||||
//
|
||||
|
||||
import Foundation
|
||||
import CoreData
|
||||
|
||||
public extension NSPersistentStoreCoordinator {
|
||||
|
||||
public func performSynchronously(closure: () -> ()) {
|
||||
|
||||
if self.respondsToSelector("performBlockAndWait:") {
|
||||
|
||||
self.performBlockAndWait(closure)
|
||||
}
|
||||
else {
|
||||
|
||||
self.lock()
|
||||
autoreleasepool(closure)
|
||||
self.unlock()
|
||||
}
|
||||
}
|
||||
}
|
||||
66
HardcoreData/PersistentStoreResult.swift
Normal file
66
HardcoreData/PersistentStoreResult.swift
Normal file
@@ -0,0 +1,66 @@
|
||||
//
|
||||
// PersistentStoreResult.swift
|
||||
// HardcoreData
|
||||
//
|
||||
// Copyright (c) 2014 John Rommel Estropia
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
// of this software and associated documentation files (the "Software"), to deal
|
||||
// in the Software without restriction, including without limitation the rights
|
||||
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
// copies of the Software, and to permit persons to whom the Software is
|
||||
// furnished to do so, subject to the following conditions:
|
||||
//
|
||||
// The above copyright notice and this permission notice shall be included in all
|
||||
// copies or substantial portions of the Software.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
// SOFTWARE.
|
||||
//
|
||||
|
||||
import Foundation
|
||||
import CoreData
|
||||
|
||||
public enum PersistentStoreResult {
|
||||
|
||||
case Success(NSPersistentStore)
|
||||
case Failure(NSError)
|
||||
|
||||
internal init(_ store: NSPersistentStore) {
|
||||
|
||||
self = .Success(store)
|
||||
}
|
||||
|
||||
internal init(_ error: NSError) {
|
||||
|
||||
self = .Failure(error)
|
||||
}
|
||||
|
||||
internal init(_ errorCode: HardcoreDataErrorCode) {
|
||||
|
||||
self.init(errorCode, userInfo: nil)
|
||||
}
|
||||
|
||||
internal init(_ errorCode: HardcoreDataErrorCode, userInfo: [NSObject: AnyObject]?) {
|
||||
|
||||
self.init(NSError(
|
||||
hardcoreDataErrorCode: errorCode,
|
||||
userInfo: userInfo))
|
||||
}
|
||||
}
|
||||
|
||||
extension PersistentStoreResult: BooleanType {
|
||||
|
||||
public var boolValue: Bool {
|
||||
|
||||
switch self {
|
||||
case .Success: return true
|
||||
case .Failure: return false
|
||||
}
|
||||
}
|
||||
}
|
||||
30
HardcoreData/QueryDescriptor.swift
Normal file
30
HardcoreData/QueryDescriptor.swift
Normal file
@@ -0,0 +1,30 @@
|
||||
//
|
||||
// QueryDescriptor.swift
|
||||
// HardcoreData
|
||||
//
|
||||
// Created by John Rommel Estropia on 14/11/16.
|
||||
// Copyright (c) 2014 John Rommel Estropia. All rights reserved.
|
||||
//
|
||||
|
||||
import Foundation
|
||||
import CoreData
|
||||
|
||||
public struct QueryDescriptor<T: NSManagedObject> {
|
||||
|
||||
public var entityName: String {
|
||||
|
||||
return self.entity.entityName
|
||||
}
|
||||
|
||||
// MARK: Internal
|
||||
|
||||
internal init(entity: T.Type) {
|
||||
self.entity = entity
|
||||
}
|
||||
|
||||
|
||||
// MARK: Private
|
||||
private let entity: T.Type
|
||||
private var predicate: NSPredicate?
|
||||
private var sortDescriptors: [NSSortDescriptor]?
|
||||
}
|
||||
65
HardcoreData/SaveResult.swift
Normal file
65
HardcoreData/SaveResult.swift
Normal file
@@ -0,0 +1,65 @@
|
||||
//
|
||||
// SaveResult.swift
|
||||
// HardcoreData
|
||||
//
|
||||
// Copyright (c) 2014 John Rommel Estropia
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
// of this software and associated documentation files (the "Software"), to deal
|
||||
// in the Software without restriction, including without limitation the rights
|
||||
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
// copies of the Software, and to permit persons to whom the Software is
|
||||
// furnished to do so, subject to the following conditions:
|
||||
//
|
||||
// The above copyright notice and this permission notice shall be included in all
|
||||
// copies or substantial portions of the Software.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
// SOFTWARE.
|
||||
//
|
||||
|
||||
import Foundation
|
||||
|
||||
public enum SaveResult {
|
||||
|
||||
case Success(hasChanges: Bool)
|
||||
case Failure(NSError)
|
||||
|
||||
internal init(hasChanges: Bool) {
|
||||
|
||||
self = .Success(hasChanges: hasChanges)
|
||||
}
|
||||
|
||||
internal init(_ error: NSError) {
|
||||
|
||||
self = .Failure(error)
|
||||
}
|
||||
|
||||
internal init(_ errorCode: HardcoreDataErrorCode) {
|
||||
|
||||
self.init(errorCode, userInfo: nil)
|
||||
}
|
||||
|
||||
internal init(_ errorCode: HardcoreDataErrorCode, userInfo: [NSObject: AnyObject]?) {
|
||||
|
||||
self.init(NSError(
|
||||
hardcoreDataErrorCode: errorCode,
|
||||
userInfo: userInfo))
|
||||
}
|
||||
}
|
||||
|
||||
extension SaveResult: BooleanType {
|
||||
|
||||
public var boolValue: Bool {
|
||||
|
||||
switch self {
|
||||
case .Success: return true
|
||||
case .Failure: return false
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -23,7 +23,38 @@ class HardcoreDataTests: XCTestCase {
|
||||
|
||||
func testExample() {
|
||||
// This is an example of a functional test case.
|
||||
XCTAssert(true, "Pass")
|
||||
|
||||
#if DEBUG
|
||||
let resetStoreOnMigrationFailure = true
|
||||
#else
|
||||
let resetStoreOnMigrationFailure = false
|
||||
#endif
|
||||
|
||||
switch HardcoreData.defaultStack.addSQLiteStore(resetStoreOnMigrationFailure: resetStoreOnMigrationFailure) {
|
||||
|
||||
case .Failure(let error):
|
||||
NSException(
|
||||
name: "CoreDataMigrationException",
|
||||
reason: error.localizedDescription,
|
||||
userInfo: error.userInfo).raise()
|
||||
|
||||
default: break
|
||||
}
|
||||
|
||||
HardcoreData.performTransaction { (transaction) -> () in
|
||||
|
||||
let obj = transaction.context.findFirst(FlickrPhoto)
|
||||
transaction.commit { (result) -> () in
|
||||
|
||||
switch result {
|
||||
|
||||
case .Success(let hasChanges):
|
||||
JEDump(hasChanges, "hasChanges")
|
||||
case .Failure(let error):
|
||||
JEDump(error, "error")
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func testPerformanceExample() {
|
||||
|
||||
1
Libraries/GCDKit
Submodule
1
Libraries/GCDKit
Submodule
Submodule Libraries/GCDKit added at 5a671ab641
1
Libraries/JEToolkit
Submodule
1
Libraries/JEToolkit
Submodule
Submodule Libraries/JEToolkit added at 5f2a2b3775
Reference in New Issue
Block a user