Compare commits
391 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
f486ace437 | ||
|
|
edb2aa2463 | ||
|
|
7b48d825a3 | ||
|
|
921b85d91b | ||
|
|
4f46cbded9 | ||
|
|
a8af91b2f8 | ||
|
|
8a8b3fa0b1 | ||
|
|
4196ed8085 | ||
|
|
0458de5d65 | ||
|
|
90ae17e904 | ||
|
|
3c0d4d648d | ||
|
|
b60bcf8da6 | ||
|
|
f9014e65e0 | ||
|
|
82887b1dd2 | ||
|
|
11d428c05c | ||
|
|
0b48bb3347 | ||
|
|
aa5cd51da6 | ||
|
|
e50dd9881d | ||
|
|
3ccbce5c29 | ||
|
|
e5a199489c | ||
|
|
3d5c4f8121 | ||
|
|
2dc09289bf | ||
|
|
76a2bc1da2 | ||
|
|
8e5c7ec9b2 | ||
|
|
101ab69861 | ||
|
|
ea2a65cf57 | ||
|
|
f59b1b6320 | ||
|
|
141e977f9c | ||
|
|
788cce0df6 | ||
|
|
4304d8687e | ||
|
|
d25f751089 | ||
|
|
6df78a0595 | ||
|
|
c0ed2f23ce | ||
|
|
dcf562fb26 | ||
|
|
b9353238e8 | ||
|
|
b98805e489 | ||
|
|
02a89accc8 | ||
|
|
2e4c9a7a25 | ||
|
|
fcca6b205e | ||
|
|
b199f38b0c | ||
|
|
0c8731c610 | ||
|
|
ee4eb178ed | ||
|
|
f617f2cc53 | ||
|
|
f396b01043 | ||
|
|
7942cf411e | ||
|
|
02be72b0b7 | ||
|
|
e38093342d | ||
|
|
c15afcb381 | ||
|
|
a97001cdbb | ||
|
|
000a357808 | ||
|
|
c8ca16a982 | ||
|
|
9e0493a20d | ||
|
|
77236d66d5 | ||
|
|
8b95d337a3 | ||
|
|
57b66cff34 | ||
|
|
9dae291f62 | ||
|
|
0c2a3ac4e9 | ||
|
|
a6291e116c | ||
|
|
c990f7764a | ||
|
|
26ae6293ca | ||
|
|
b9a2f96d6e | ||
|
|
ae5f737baf | ||
|
|
4eecd80710 | ||
|
|
0073d038e0 | ||
|
|
099dcfab68 | ||
|
|
74fe81bfa7 | ||
|
|
0bbb4118a1 | ||
|
|
3fe9e4ee1d | ||
|
|
bd19326447 | ||
|
|
dccc958ef1 | ||
|
|
ab3095f078 | ||
|
|
1a86510045 | ||
|
|
aa32f5e158 | ||
|
|
b95aaf151d | ||
|
|
114bc71841 | ||
|
|
dff552b95f | ||
|
|
88cac73b20 | ||
|
|
83d0412cb9 | ||
|
|
26e4118355 | ||
|
|
0c564add46 | ||
|
|
784a315fb9 | ||
|
|
44cfbebedb | ||
|
|
0b24072259 | ||
|
|
28b7ba01dc | ||
|
|
b529735269 | ||
|
|
d23121d8ed | ||
|
|
633ab0a249 | ||
|
|
410feda5cd | ||
|
|
06e952af8a | ||
|
|
a4d3d0c0ed | ||
|
|
8b7af86526 | ||
|
|
48a8694720 | ||
|
|
09d844f5df | ||
|
|
e25e198bf8 | ||
|
|
e99d19d2ac | ||
|
|
9d7960e674 | ||
|
|
e9ac8629a1 | ||
|
|
b0b0df2861 | ||
|
|
eda398d758 | ||
|
|
40c320e1ca | ||
|
|
8508dd4f79 | ||
|
|
d3e0f576cf | ||
|
|
1d5cf5a4cc | ||
|
|
9fc0390b45 | ||
|
|
b8ea7ecf01 | ||
|
|
11ac362dcc | ||
|
|
10c20e0d62 | ||
|
|
789028bc58 | ||
|
|
a168ca577a | ||
|
|
781f3988d2 | ||
|
|
b914a4b5ed | ||
|
|
7de13131a4 | ||
|
|
0c1af09a8d | ||
|
|
1ff635d8b5 | ||
|
|
707445a169 | ||
|
|
90369cf994 | ||
|
|
09708e587c | ||
|
|
36e6e4a8b9 | ||
|
|
9f1a351311 | ||
|
|
6e202aa7ca | ||
|
|
783b933294 | ||
|
|
ca49ea3a81 | ||
|
|
ed8891a6d5 | ||
|
|
dd6c6abaf0 | ||
|
|
928585029d | ||
|
|
dc6d22b6ff | ||
|
|
5ca0f657cb | ||
|
|
2c65ac1834 | ||
|
|
24008d62b2 | ||
|
|
e8a9cc9d67 | ||
|
|
1507ac63f9 | ||
|
|
f2df8f7171 | ||
|
|
3ddfd3cccc | ||
|
|
21f57518c8 | ||
|
|
d9422f7f2e | ||
|
|
245ec25ad8 | ||
|
|
0ce89b8460 | ||
|
|
42a889a28e | ||
|
|
456977bf12 | ||
|
|
ea8412ab93 | ||
|
|
603dffffb0 | ||
|
|
8a1144b1be | ||
|
|
c323a28c19 | ||
|
|
4ff7b2d6d9 | ||
|
|
64ad7b3bfd | ||
|
|
df441c5d04 | ||
|
|
fa947faa57 | ||
|
|
6822a4579e | ||
|
|
a89dd76906 | ||
|
|
c85ef16ad0 | ||
|
|
67f1bd9a63 | ||
|
|
39540628df | ||
|
|
c86ca06bd4 | ||
|
|
40c27b9fcb | ||
|
|
2f8c100cb6 | ||
|
|
34495d7163 | ||
|
|
75a4ebb49b | ||
|
|
3c514830d9 | ||
|
|
b283fbf5ab | ||
|
|
c1e087b8c1 | ||
|
|
ad1ebb3501 | ||
|
|
99189d160f | ||
|
|
3c2fb28644 | ||
|
|
f71ad4c577 | ||
|
|
d05fcc5103 | ||
|
|
e9329fc93c | ||
|
|
1ea773f0ec | ||
|
|
c68c2bdc0a | ||
|
|
e66a13632a | ||
|
|
4c78a309bc | ||
|
|
9055daa58c | ||
|
|
3905423038 | ||
|
|
15353268e2 | ||
|
|
91dd4b6cb3 | ||
|
|
0800b706d6 | ||
|
|
2071ce722e | ||
|
|
df866718cf | ||
|
|
f19a0d29eb | ||
|
|
8f09f90294 | ||
|
|
7bddcaa4a2 | ||
|
|
c12331f403 | ||
|
|
a55a8d389c | ||
|
|
6e88b14237 | ||
|
|
53700a267f | ||
|
|
6c95b010e9 | ||
|
|
1af675e8b7 | ||
|
|
b85f16cf68 | ||
|
|
37bf4179c8 | ||
|
|
240dda6ad6 | ||
|
|
ffe73d0f66 | ||
|
|
43c4998e20 | ||
|
|
0c4e55f061 | ||
|
|
8c8953c507 | ||
|
|
66892f22a3 | ||
|
|
def105e73a | ||
|
|
57bf123fb2 | ||
|
|
8efd6572f0 | ||
|
|
405e861907 | ||
|
|
74c48c7486 | ||
|
|
e58b3b0131 | ||
|
|
b8fad66bfa | ||
|
|
ff1155dac3 | ||
|
|
5137649b78 | ||
|
|
7a95267a9c | ||
|
|
c07435e866 | ||
|
|
f5627f0855 | ||
|
|
d3ea655eb9 | ||
|
|
fc83180af8 | ||
|
|
0c6246475a | ||
|
|
087480a3a8 | ||
|
|
83a04e669e | ||
|
|
d05522bb20 | ||
|
|
9081b36cca | ||
|
|
9322371224 | ||
|
|
26ab6aacd7 | ||
|
|
3e601c1328 | ||
|
|
762b877879 | ||
|
|
084bdc431f | ||
|
|
c63bc389b2 | ||
|
|
71c3abc4f3 | ||
|
|
863d4d1d5a | ||
|
|
06d177e8bd | ||
|
|
c2bbd537cf | ||
|
|
761d349b97 | ||
|
|
6c28594e41 | ||
|
|
c229af19a2 | ||
|
|
8b8a7c7b08 | ||
|
|
eb828d8e42 | ||
|
|
88a24540c6 | ||
|
|
74ded8fb7d | ||
|
|
969f4cefb4 | ||
|
|
1d2947ad26 | ||
|
|
49274c3c94 | ||
|
|
c0fbb2655b | ||
|
|
cefd6f6cbc | ||
|
|
2653f7b977 | ||
|
|
c1163283f5 | ||
|
|
529347b6a2 | ||
|
|
eba7e99374 | ||
|
|
3c4350bd5d | ||
|
|
88b13189e5 | ||
|
|
03da3544f6 | ||
|
|
648b59e1ee | ||
|
|
ab3c8ca812 | ||
|
|
900a31c541 | ||
|
|
656a107767 | ||
|
|
4ce3d5de3c | ||
|
|
dec9757dc2 | ||
|
|
578e4966fc | ||
|
|
b741626574 | ||
|
|
f79a77ab78 | ||
|
|
1f2a70fd42 | ||
|
|
718d2c9b7d | ||
|
|
c5ff02335e | ||
|
|
66b57faa44 | ||
|
|
eef5a3d80b | ||
|
|
bc0757cf06 | ||
|
|
0c0a2a382c | ||
|
|
05b4a7092a | ||
|
|
6aed070e7c | ||
|
|
fcb1d7cbbc | ||
|
|
d074aad111 | ||
|
|
b7685dc747 | ||
|
|
a185bc96c0 | ||
|
|
91aef44803 | ||
|
|
dcfb09eda7 | ||
|
|
9ca83d9c5d | ||
|
|
b00eaf2d0b | ||
|
|
dc8bdf3bad | ||
|
|
4792c4462e | ||
|
|
524757a7cf | ||
|
|
0b6298a802 | ||
|
|
ae77558ae8 | ||
|
|
d33aa9c5cf | ||
|
|
d89319d324 | ||
|
|
cf9af6eef5 | ||
|
|
b9ec66f425 | ||
|
|
2a8df0596d | ||
|
|
83e6a41d88 | ||
|
|
c6fe494fe1 | ||
|
|
7771e047e2 | ||
|
|
5b0439835b | ||
|
|
622c5aa652 | ||
|
|
114b7ce605 | ||
|
|
7451fbe026 | ||
|
|
ee2398fcdf | ||
|
|
8d26501040 | ||
|
|
0709fe95cf | ||
|
|
656a99fe12 | ||
|
|
726e0eabe9 | ||
|
|
032764b9b7 | ||
|
|
5461bb0736 | ||
|
|
4c6bc4f494 | ||
|
|
63a43a6487 | ||
|
|
6a006d5d7c | ||
|
|
399517e357 | ||
|
|
f47adc12b3 | ||
|
|
0de1733efe | ||
|
|
e627cf8161 | ||
|
|
22943d2c76 | ||
|
|
56ea14d53c | ||
|
|
21a524d725 | ||
|
|
d5e769be6c | ||
|
|
ea6b6f2c37 | ||
|
|
c3ef8a4172 | ||
|
|
16aabe1f3b | ||
|
|
10e0cf8d2c | ||
|
|
3a0f53321a | ||
|
|
0da43d5132 | ||
|
|
69f902ef20 | ||
|
|
d04b4ca085 | ||
|
|
8ed6a78609 | ||
|
|
0c9e6afe0e | ||
|
|
ff4629908a | ||
|
|
d3ffe7a8fc | ||
|
|
3919ada428 | ||
|
|
682b13a8d3 | ||
|
|
2f935de04a | ||
|
|
006d5e1402 | ||
|
|
093c1d410f | ||
|
|
7555ff3ad0 | ||
|
|
4c16a961ba | ||
|
|
1121d44d7b | ||
|
|
ba4fb5e5cb | ||
|
|
d860da2507 | ||
|
|
2bcf8008c5 | ||
|
|
71477c0839 | ||
|
|
3348aa0bef | ||
|
|
2ed61fdb17 | ||
|
|
9cfad8a17a | ||
|
|
3bf34f33dc | ||
|
|
90bfaeaae8 | ||
|
|
a29a4b38fe | ||
|
|
5a96ef13f6 | ||
|
|
b92ee76907 | ||
|
|
67ccae4ef6 | ||
|
|
62b11309f3 | ||
|
|
8c6a7df731 | ||
|
|
b475afe79f | ||
|
|
a263851266 | ||
|
|
cbc3eb8887 | ||
|
|
2fb3263aa1 | ||
|
|
64aa97264e | ||
|
|
8066bf2a5a | ||
|
|
283104af3f | ||
|
|
83c724f584 | ||
|
|
59ad525786 | ||
|
|
b85d7521e1 | ||
|
|
4dbc4558e3 | ||
|
|
2a56c097f2 | ||
|
|
d4b95aed64 | ||
|
|
0d2650c54b | ||
|
|
6a3885edda | ||
|
|
1c6085ad82 | ||
|
|
2dae2ae39c | ||
|
|
a1e37975cc | ||
|
|
0c8a43c3b0 | ||
|
|
9676e3aca2 | ||
|
|
a34d2795af | ||
|
|
106789d592 | ||
|
|
edc51de030 | ||
|
|
f85eb2e057 | ||
|
|
f0161b50ed | ||
|
|
6c780c1282 | ||
|
|
b711ec9644 | ||
|
|
a581f91507 | ||
|
|
ebd4df5c2f | ||
|
|
2780fd7682 | ||
|
|
982e75a36e | ||
|
|
79d5598abe | ||
|
|
b88679c507 | ||
|
|
858dd0962d | ||
|
|
e7bcb501fd | ||
|
|
f99349f99d | ||
|
|
a64bcc474e | ||
|
|
8cfe8e2500 | ||
|
|
33268eeea1 | ||
|
|
b2a190ea33 | ||
|
|
35fbaf9513 | ||
|
|
450afb00fa | ||
|
|
7e0d3120e1 | ||
|
|
acfe5dd7a7 | ||
|
|
9da323b0b8 | ||
|
|
4f3e679aa1 | ||
|
|
5f04f4c496 | ||
|
|
5b85b0749e | ||
|
|
bf0eebe057 | ||
|
|
261c3a6001 | ||
|
|
91444b6dd3 | ||
|
|
e0b5da27f8 | ||
|
|
40f22761bf |
5
.gitignore
vendored
@@ -2,3 +2,8 @@ CoreStoreDemo/CoreStoreDemo.xcodeproj/project.xcworkspace/xcuserdata
|
||||
CoreStore.xcodeproj/project.xcworkspace/xcuserdata
|
||||
CoreStore.xcodeproj/xcuserdata
|
||||
CoreStoreDemo/CoreStoreDemo.xcodeproj/xcuserdata
|
||||
Carthage/Build
|
||||
CoreStore.xcworkspace/xcuserdata
|
||||
.DS_Store
|
||||
DerivedData
|
||||
*.orig
|
||||
|
||||
6
.gitmodules
vendored
@@ -1,3 +1,3 @@
|
||||
[submodule "Libraries/GCDKit"]
|
||||
path = Libraries/GCDKit
|
||||
url = git@github.com:JohnEstropia/GCDKit.git
|
||||
[submodule "Carthage/Checkouts/GCDKit"]
|
||||
path = Carthage/Checkouts/GCDKit
|
||||
url = https://github.com/JohnEstropia/GCDKit.git
|
||||
|
||||
43
.travis.yml
Normal file
@@ -0,0 +1,43 @@
|
||||
language: objective-c
|
||||
osx_image: xcode7.3
|
||||
sudo: false
|
||||
git:
|
||||
submodules: false
|
||||
notifications:
|
||||
email: false
|
||||
env:
|
||||
global:
|
||||
- LC_CTYPE=en_US.UTF-8
|
||||
- LANG=en_US.UTF-8
|
||||
matrix:
|
||||
- DESTINATION="OS=9.3,name=iPhone 6s" SCHEME="CoreStore iOS" SDK=iphonesimulator9.3 RUN_TESTS="YES" POD_LINT="NO"
|
||||
- DESTINATION="OS=9.0,name=iPhone 6 Plus" SCHEME="CoreStore iOS" SDK=iphonesimulator9.3 RUN_TESTS="YES" POD_LINT="NO"
|
||||
- DESTINATION="OS=8.4,name=iPhone 6" SCHEME="CoreStore iOS" SDK=iphonesimulator9.3 RUN_TESTS="YES" POD_LINT="NO"
|
||||
- DESTINATION="OS=8.3,name=iPhone 5S" SCHEME="CoreStore iOS" SDK=iphonesimulator9.3 RUN_TESTS="YES" POD_LINT="NO"
|
||||
- DESTINATION="OS=8.2,name=iPhone 5" SCHEME="CoreStore iOS" SDK=iphonesimulator9.3 RUN_TESTS="YES" POD_LINT="NO"
|
||||
- DESTINATION="OS=8.1,name=iPhone 4S" SCHEME="CoreStore iOS" SDK=iphonesimulator9.3 RUN_TESTS="YES" POD_LINT="YES"
|
||||
- DESTINATION="OS=8.1,name=iPhone 4S" SCHEME="CoreStore iOS7" SDK=iphonesimulator9.3 RUN_TESTS="YES" POD_LINT="YES"
|
||||
- DESTINATION="arch=x86_64" SCHEME="CoreStore OSX" SDK=macosx10.11 RUN_TESTS="YES" POD_LINT="NO"
|
||||
- DESTINATION="OS=2.2,name=Apple Watch - 42mm" SCHEME="CoreStore watchOS" SDK=watchsimulator2.2 RUN_TESTS="NO" POD_LINT="NO"
|
||||
- DESTINATION="OS=9.2,name=Apple TV 1080p" SCHEME="CoreStore tvOS" SDK=appletvsimulator9.2 RUN_TESTS="YES" POD_LINT="NO"
|
||||
before_install:
|
||||
- gem install cocoapods --no-rdoc --no-ri --no-document --quiet
|
||||
- gem install xcpretty --no-rdoc --no-ri --no-document --quiet
|
||||
- curl -OlL "https://github.com/Carthage/Carthage/releases/download/0.11/Carthage.pkg"
|
||||
- sudo installer -pkg "Carthage.pkg" -target /
|
||||
- rm "Carthage.pkg"
|
||||
before_script:
|
||||
- carthage update --use-submodules
|
||||
script:
|
||||
- set -o pipefail
|
||||
- xcodebuild -version
|
||||
- xcodebuild -showsdks
|
||||
- if [ $RUN_TESTS == "YES" ]; then
|
||||
xcodebuild -workspace CoreStore.xcworkspace -scheme "$SCHEME" -sdk "$SDK" -destination "$DESTINATION" -configuration Debug ONLY_ACTIVE_ARCH=NO clean test | xcpretty -c;
|
||||
xcodebuild -workspace CoreStore.xcworkspace -scheme "$SCHEME" -sdk "$SDK" -destination "$DESTINATION" -configuration Release ONLY_ACTIVE_ARCH=NO clean test | xcpretty -c;
|
||||
fi
|
||||
- xcodebuild -workspace "CoreStore.xcworkspace" -scheme "CoreStore iOS" -sdk "iphonesimulator9.3" -destination "OS=9.3,name=iPhone 6s" -configuration Debug ONLY_ACTIVE_ARCH=NO clean test | xcpretty -c;
|
||||
- xcodebuild -workspace "CoreStore.xcworkspace" -scheme "CoreStore iOS" -sdk "iphonesimulator9.3" -destination "OS=9.3,name=iPhone 6s" -configuration Release ONLY_ACTIVE_ARCH=NO clean test | xcpretty -c;
|
||||
- if [ $POD_LINT == "YES" ]; then
|
||||
pod lib lint --quick;
|
||||
fi
|
||||
1
Cartfile.resolved
Normal file
@@ -0,0 +1 @@
|
||||
github "JohnEstropia/GCDKit" "1.2.4"
|
||||
1
Carthage/Checkouts/GCDKit
vendored
Submodule
BIN
CoreStore.png
Normal file
|
After Width: | Height: | Size: 53 KiB |
@@ -1,16 +1,23 @@
|
||||
Pod::Spec.new do |s|
|
||||
s.name = "CoreStore"
|
||||
s.version = "0.2.1"
|
||||
s.version = "2.0.0"
|
||||
s.license = "MIT"
|
||||
s.summary = "Simple, elegant, and smart Core Data programming with Swift"
|
||||
s.summary = "Unleashing the real power of Core Data with the elegance and safety of Swift"
|
||||
s.homepage = "https://github.com/JohnEstropia/CoreStore"
|
||||
s.author = { "John Rommel Estropia" => "rommel.estropia@gmail.com" }
|
||||
s.source = { :git => "https://github.com/JohnEstropia/CoreStore.git", :tag => s.version.to_s }
|
||||
|
||||
s.ios.deployment_target = "8.0"
|
||||
s.osx.deployment_target = "10.10"
|
||||
s.watchos.deployment_target = "2.0"
|
||||
s.tvos.deployment_target = "9.0"
|
||||
|
||||
s.source_files = "CoreStore", "CoreStore/**/*.{swift}"
|
||||
s.frameworks = "Foundation", "UIKit", "CoreData"
|
||||
s.source_files = "Sources", "Sources/**/*.{swift,h,m}"
|
||||
s.public_header_files = "Sources/**/*.h"
|
||||
s.frameworks = "Foundation", "CoreData"
|
||||
s.requires_arc = true
|
||||
s.dependency "GCDKit", "1.0.1"
|
||||
s.pod_target_xcconfig = { 'OTHER_SWIFT_FLAGS' => '-D USE_FRAMEWORKS',
|
||||
'GCC_PREPROCESSOR_DEFINITIONS' => 'USE_FRAMEWORKS=1' }
|
||||
|
||||
s.dependency "GCDKit", "1.2.5"
|
||||
end
|
||||
BIN
CoreStore.sketch
Normal file
@@ -0,0 +1,30 @@
|
||||
{
|
||||
"DVTSourceControlWorkspaceBlueprintPrimaryRemoteRepositoryKey" : "4B60F1BCB491FF717C56441AE7783C74F417BE48",
|
||||
"DVTSourceControlWorkspaceBlueprintWorkingCopyRepositoryLocationsKey" : {
|
||||
|
||||
},
|
||||
"DVTSourceControlWorkspaceBlueprintWorkingCopyStatesKey" : {
|
||||
"8B2E522D57154DFA93A06982C36315ECBEA4FA97" : 0,
|
||||
"4B60F1BCB491FF717C56441AE7783C74F417BE48" : 0
|
||||
},
|
||||
"DVTSourceControlWorkspaceBlueprintIdentifierKey" : "F347F55F-7F5C-4476-9148-6E902F06E4AD",
|
||||
"DVTSourceControlWorkspaceBlueprintWorkingCopyPathsKey" : {
|
||||
"8B2E522D57154DFA93A06982C36315ECBEA4FA97" : "CoreStoreLibraries\/GCDKit",
|
||||
"4B60F1BCB491FF717C56441AE7783C74F417BE48" : "CoreStore"
|
||||
},
|
||||
"DVTSourceControlWorkspaceBlueprintNameKey" : "CoreStore",
|
||||
"DVTSourceControlWorkspaceBlueprintVersion" : 203,
|
||||
"DVTSourceControlWorkspaceBlueprintRelativePathToProjectKey" : "CoreStore.xcodeproj",
|
||||
"DVTSourceControlWorkspaceBlueprintRemoteRepositoriesKey" : [
|
||||
{
|
||||
"DVTSourceControlWorkspaceBlueprintRemoteRepositoryURLKey" : "github.com:JohnEstropia\/CoreStore.git",
|
||||
"DVTSourceControlWorkspaceBlueprintRemoteRepositorySystemKey" : "com.apple.dt.Xcode.sourcecontrol.Git",
|
||||
"DVTSourceControlWorkspaceBlueprintRemoteRepositoryIdentifierKey" : "4B60F1BCB491FF717C56441AE7783C74F417BE48"
|
||||
},
|
||||
{
|
||||
"DVTSourceControlWorkspaceBlueprintRemoteRepositoryURLKey" : "github.com:JohnEstropia\/GCDKit.git",
|
||||
"DVTSourceControlWorkspaceBlueprintRemoteRepositorySystemKey" : "com.apple.dt.Xcode.sourcecontrol.Git",
|
||||
"DVTSourceControlWorkspaceBlueprintRemoteRepositoryIdentifierKey" : "8B2E522D57154DFA93A06982C36315ECBEA4FA97"
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -0,0 +1,99 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<Scheme
|
||||
LastUpgradeVersion = "0710"
|
||||
version = "1.3">
|
||||
<BuildAction
|
||||
parallelizeBuildables = "YES"
|
||||
buildImplicitDependencies = "YES">
|
||||
<BuildActionEntries>
|
||||
<BuildActionEntry
|
||||
buildForTesting = "YES"
|
||||
buildForRunning = "YES"
|
||||
buildForProfiling = "YES"
|
||||
buildForArchiving = "YES"
|
||||
buildForAnalyzing = "YES">
|
||||
<BuildableReference
|
||||
BuildableIdentifier = "primary"
|
||||
BlueprintIdentifier = "B52DD1731BE1F8CC00949AFE"
|
||||
BuildableName = "CoreStore.framework"
|
||||
BlueprintName = "CoreStore OSX"
|
||||
ReferencedContainer = "container:CoreStore.xcodeproj">
|
||||
</BuildableReference>
|
||||
</BuildActionEntry>
|
||||
</BuildActionEntries>
|
||||
</BuildAction>
|
||||
<TestAction
|
||||
buildConfiguration = "Debug"
|
||||
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
|
||||
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
|
||||
shouldUseLaunchSchemeArgsEnv = "YES">
|
||||
<Testables>
|
||||
<TestableReference
|
||||
skipped = "NO">
|
||||
<BuildableReference
|
||||
BuildableIdentifier = "primary"
|
||||
BlueprintIdentifier = "B52DD17C1BE1F8CC00949AFE"
|
||||
BuildableName = "CoreStoreTests.xctest"
|
||||
BlueprintName = "CoreStoreTests OSX"
|
||||
ReferencedContainer = "container:CoreStore.xcodeproj">
|
||||
</BuildableReference>
|
||||
</TestableReference>
|
||||
</Testables>
|
||||
<MacroExpansion>
|
||||
<BuildableReference
|
||||
BuildableIdentifier = "primary"
|
||||
BlueprintIdentifier = "B52DD1731BE1F8CC00949AFE"
|
||||
BuildableName = "CoreStore.framework"
|
||||
BlueprintName = "CoreStore OSX"
|
||||
ReferencedContainer = "container:CoreStore.xcodeproj">
|
||||
</BuildableReference>
|
||||
</MacroExpansion>
|
||||
<AdditionalOptions>
|
||||
</AdditionalOptions>
|
||||
</TestAction>
|
||||
<LaunchAction
|
||||
buildConfiguration = "Debug"
|
||||
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
|
||||
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
|
||||
launchStyle = "0"
|
||||
useCustomWorkingDirectory = "NO"
|
||||
ignoresPersistentStateOnLaunch = "NO"
|
||||
debugDocumentVersioning = "YES"
|
||||
debugServiceExtension = "internal"
|
||||
allowLocationSimulation = "YES">
|
||||
<MacroExpansion>
|
||||
<BuildableReference
|
||||
BuildableIdentifier = "primary"
|
||||
BlueprintIdentifier = "B52DD1731BE1F8CC00949AFE"
|
||||
BuildableName = "CoreStore.framework"
|
||||
BlueprintName = "CoreStore OSX"
|
||||
ReferencedContainer = "container:CoreStore.xcodeproj">
|
||||
</BuildableReference>
|
||||
</MacroExpansion>
|
||||
<AdditionalOptions>
|
||||
</AdditionalOptions>
|
||||
</LaunchAction>
|
||||
<ProfileAction
|
||||
buildConfiguration = "Release"
|
||||
shouldUseLaunchSchemeArgsEnv = "YES"
|
||||
savedToolIdentifier = ""
|
||||
useCustomWorkingDirectory = "NO"
|
||||
debugDocumentVersioning = "YES">
|
||||
<MacroExpansion>
|
||||
<BuildableReference
|
||||
BuildableIdentifier = "primary"
|
||||
BlueprintIdentifier = "B52DD1731BE1F8CC00949AFE"
|
||||
BuildableName = "CoreStore.framework"
|
||||
BlueprintName = "CoreStore OSX"
|
||||
ReferencedContainer = "container:CoreStore.xcodeproj">
|
||||
</BuildableReference>
|
||||
</MacroExpansion>
|
||||
</ProfileAction>
|
||||
<AnalyzeAction
|
||||
buildConfiguration = "Debug">
|
||||
</AnalyzeAction>
|
||||
<ArchiveAction
|
||||
buildConfiguration = "Release"
|
||||
revealArchiveInOrganizer = "YES">
|
||||
</ArchiveAction>
|
||||
</Scheme>
|
||||
@@ -1,6 +1,6 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<Scheme
|
||||
LastUpgradeVersion = "0630"
|
||||
LastUpgradeVersion = "0700"
|
||||
version = "1.3">
|
||||
<BuildAction
|
||||
parallelizeBuildables = "YES"
|
||||
@@ -11,36 +11,38 @@
|
||||
buildForRunning = "YES"
|
||||
buildForProfiling = "YES"
|
||||
buildForArchiving = "YES"
|
||||
buildForAnalyzing = "YES">
|
||||
buildForAnalyzing = "YES"
|
||||
hideIssues = "NO">
|
||||
<BuildableReference
|
||||
BuildableIdentifier = "primary"
|
||||
BlueprintIdentifier = "2F03A52F19C5C6DA005002A5"
|
||||
BuildableName = "CoreStore.framework"
|
||||
BlueprintName = "CoreStore"
|
||||
BlueprintName = "CoreStore iOS"
|
||||
ReferencedContainer = "container:CoreStore.xcodeproj">
|
||||
</BuildableReference>
|
||||
</BuildActionEntry>
|
||||
<BuildActionEntry
|
||||
buildForTesting = "YES"
|
||||
buildForRunning = "YES"
|
||||
buildForRunning = "NO"
|
||||
buildForProfiling = "NO"
|
||||
buildForArchiving = "NO"
|
||||
buildForAnalyzing = "YES">
|
||||
buildForAnalyzing = "NO"
|
||||
hideIssues = "NO">
|
||||
<BuildableReference
|
||||
BuildableIdentifier = "primary"
|
||||
BlueprintIdentifier = "2F03A53A19C5C6DA005002A5"
|
||||
BuildableName = "CoreStoreTests.xctest"
|
||||
BlueprintName = "CoreStoreTests"
|
||||
BlueprintName = "CoreStoreTests iOS"
|
||||
ReferencedContainer = "container:CoreStore.xcodeproj">
|
||||
</BuildableReference>
|
||||
</BuildActionEntry>
|
||||
</BuildActionEntries>
|
||||
</BuildAction>
|
||||
<TestAction
|
||||
buildConfiguration = "Debug"
|
||||
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
|
||||
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
|
||||
shouldUseLaunchSchemeArgsEnv = "YES"
|
||||
buildConfiguration = "Debug">
|
||||
shouldUseLaunchSchemeArgsEnv = "YES">
|
||||
<Testables>
|
||||
<TestableReference
|
||||
skipped = "NO">
|
||||
@@ -48,7 +50,7 @@
|
||||
BuildableIdentifier = "primary"
|
||||
BlueprintIdentifier = "2F03A53A19C5C6DA005002A5"
|
||||
BuildableName = "CoreStoreTests.xctest"
|
||||
BlueprintName = "CoreStoreTests"
|
||||
BlueprintName = "CoreStoreTests iOS"
|
||||
ReferencedContainer = "container:CoreStore.xcodeproj">
|
||||
</BuildableReference>
|
||||
</TestableReference>
|
||||
@@ -58,26 +60,29 @@
|
||||
BuildableIdentifier = "primary"
|
||||
BlueprintIdentifier = "2F03A52F19C5C6DA005002A5"
|
||||
BuildableName = "CoreStore.framework"
|
||||
BlueprintName = "CoreStore"
|
||||
BlueprintName = "CoreStore iOS"
|
||||
ReferencedContainer = "container:CoreStore.xcodeproj">
|
||||
</BuildableReference>
|
||||
</MacroExpansion>
|
||||
<AdditionalOptions>
|
||||
</AdditionalOptions>
|
||||
</TestAction>
|
||||
<LaunchAction
|
||||
buildConfiguration = "Debug"
|
||||
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
|
||||
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
|
||||
launchStyle = "0"
|
||||
useCustomWorkingDirectory = "NO"
|
||||
buildConfiguration = "Debug"
|
||||
ignoresPersistentStateOnLaunch = "NO"
|
||||
debugDocumentVersioning = "YES"
|
||||
debugServiceExtension = "internal"
|
||||
allowLocationSimulation = "YES">
|
||||
<MacroExpansion>
|
||||
<BuildableReference
|
||||
BuildableIdentifier = "primary"
|
||||
BlueprintIdentifier = "2F03A52F19C5C6DA005002A5"
|
||||
BuildableName = "CoreStore.framework"
|
||||
BlueprintName = "CoreStore"
|
||||
BlueprintName = "CoreStore iOS"
|
||||
ReferencedContainer = "container:CoreStore.xcodeproj">
|
||||
</BuildableReference>
|
||||
</MacroExpansion>
|
||||
@@ -85,17 +90,17 @@
|
||||
</AdditionalOptions>
|
||||
</LaunchAction>
|
||||
<ProfileAction
|
||||
buildConfiguration = "Release"
|
||||
shouldUseLaunchSchemeArgsEnv = "YES"
|
||||
savedToolIdentifier = ""
|
||||
useCustomWorkingDirectory = "NO"
|
||||
buildConfiguration = "Release"
|
||||
debugDocumentVersioning = "YES">
|
||||
<MacroExpansion>
|
||||
<BuildableReference
|
||||
BuildableIdentifier = "primary"
|
||||
BlueprintIdentifier = "2F03A52F19C5C6DA005002A5"
|
||||
BuildableName = "CoreStore.framework"
|
||||
BlueprintName = "CoreStore"
|
||||
BlueprintName = "CoreStore iOS"
|
||||
ReferencedContainer = "container:CoreStore.xcodeproj">
|
||||
</BuildableReference>
|
||||
</MacroExpansion>
|
||||
@@ -0,0 +1,104 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<Scheme
|
||||
LastUpgradeVersion = "0700"
|
||||
version = "1.3">
|
||||
<BuildAction
|
||||
parallelizeBuildables = "YES"
|
||||
buildImplicitDependencies = "YES">
|
||||
<BuildActionEntries>
|
||||
<BuildActionEntry
|
||||
buildForTesting = "YES"
|
||||
buildForRunning = "YES"
|
||||
buildForProfiling = "YES"
|
||||
buildForArchiving = "YES"
|
||||
buildForAnalyzing = "YES">
|
||||
<BuildableReference
|
||||
BuildableIdentifier = "primary"
|
||||
BlueprintIdentifier = "B5D9E2ED1CA2C317007A9D52"
|
||||
BuildableName = "CoreStore_iOS7.framework"
|
||||
BlueprintName = "CoreStore iOS7"
|
||||
ReferencedContainer = "container:CoreStore.xcodeproj">
|
||||
</BuildableReference>
|
||||
</BuildActionEntry>
|
||||
<BuildActionEntry
|
||||
buildForTesting = "YES"
|
||||
buildForRunning = "NO"
|
||||
buildForProfiling = "NO"
|
||||
buildForArchiving = "NO"
|
||||
buildForAnalyzing = "NO">
|
||||
<BuildableReference
|
||||
BuildableIdentifier = "primary"
|
||||
BlueprintIdentifier = "2F03A53A19C5C6DA005002A5"
|
||||
BuildableName = "CoreStoreTests.xctest"
|
||||
BlueprintName = "CoreStoreTests iOS"
|
||||
ReferencedContainer = "container:CoreStore.xcodeproj">
|
||||
</BuildableReference>
|
||||
</BuildActionEntry>
|
||||
</BuildActionEntries>
|
||||
</BuildAction>
|
||||
<TestAction
|
||||
buildConfiguration = "Debug"
|
||||
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
|
||||
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
|
||||
shouldUseLaunchSchemeArgsEnv = "YES">
|
||||
<Testables>
|
||||
<TestableReference
|
||||
skipped = "NO">
|
||||
<BuildableReference
|
||||
BuildableIdentifier = "primary"
|
||||
BlueprintIdentifier = "2F03A53A19C5C6DA005002A5"
|
||||
BuildableName = "CoreStoreTests.xctest"
|
||||
BlueprintName = "CoreStoreTests iOS"
|
||||
ReferencedContainer = "container:CoreStore.xcodeproj">
|
||||
</BuildableReference>
|
||||
</TestableReference>
|
||||
</Testables>
|
||||
<MacroExpansion>
|
||||
<BuildableReference
|
||||
BuildableIdentifier = "primary"
|
||||
BlueprintIdentifier = "2F03A52F19C5C6DA005002A5"
|
||||
BuildableName = "CoreStore.framework"
|
||||
BlueprintName = "CoreStore iOS"
|
||||
ReferencedContainer = "container:CoreStore.xcodeproj">
|
||||
</BuildableReference>
|
||||
</MacroExpansion>
|
||||
<AdditionalOptions>
|
||||
</AdditionalOptions>
|
||||
</TestAction>
|
||||
<LaunchAction
|
||||
buildConfiguration = "Debug"
|
||||
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
|
||||
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
|
||||
launchStyle = "0"
|
||||
useCustomWorkingDirectory = "NO"
|
||||
ignoresPersistentStateOnLaunch = "NO"
|
||||
debugDocumentVersioning = "YES"
|
||||
debugServiceExtension = "internal"
|
||||
allowLocationSimulation = "YES">
|
||||
<MacroExpansion>
|
||||
<BuildableReference
|
||||
BuildableIdentifier = "primary"
|
||||
BlueprintIdentifier = "B5D9E2ED1CA2C317007A9D52"
|
||||
BuildableName = "CoreStore_iOS7.framework"
|
||||
BlueprintName = "CoreStore iOS7"
|
||||
ReferencedContainer = "container:CoreStore.xcodeproj">
|
||||
</BuildableReference>
|
||||
</MacroExpansion>
|
||||
<AdditionalOptions>
|
||||
</AdditionalOptions>
|
||||
</LaunchAction>
|
||||
<ProfileAction
|
||||
buildConfiguration = "Release"
|
||||
shouldUseLaunchSchemeArgsEnv = "YES"
|
||||
savedToolIdentifier = ""
|
||||
useCustomWorkingDirectory = "NO"
|
||||
debugDocumentVersioning = "YES">
|
||||
</ProfileAction>
|
||||
<AnalyzeAction
|
||||
buildConfiguration = "Release">
|
||||
</AnalyzeAction>
|
||||
<ArchiveAction
|
||||
buildConfiguration = "Release"
|
||||
revealArchiveInOrganizer = "YES">
|
||||
</ArchiveAction>
|
||||
</Scheme>
|
||||
@@ -0,0 +1,99 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<Scheme
|
||||
LastUpgradeVersion = "0720"
|
||||
version = "1.3">
|
||||
<BuildAction
|
||||
parallelizeBuildables = "YES"
|
||||
buildImplicitDependencies = "YES">
|
||||
<BuildActionEntries>
|
||||
<BuildActionEntry
|
||||
buildForTesting = "YES"
|
||||
buildForRunning = "YES"
|
||||
buildForProfiling = "YES"
|
||||
buildForArchiving = "YES"
|
||||
buildForAnalyzing = "YES">
|
||||
<BuildableReference
|
||||
BuildableIdentifier = "primary"
|
||||
BlueprintIdentifier = "82BA18881C4BBCBA00A0916E"
|
||||
BuildableName = "CoreStore.framework"
|
||||
BlueprintName = "CoreStore tvOS"
|
||||
ReferencedContainer = "container:CoreStore.xcodeproj">
|
||||
</BuildableReference>
|
||||
</BuildActionEntry>
|
||||
</BuildActionEntries>
|
||||
</BuildAction>
|
||||
<TestAction
|
||||
buildConfiguration = "Debug"
|
||||
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
|
||||
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
|
||||
shouldUseLaunchSchemeArgsEnv = "YES">
|
||||
<Testables>
|
||||
<TestableReference
|
||||
skipped = "NO">
|
||||
<BuildableReference
|
||||
BuildableIdentifier = "primary"
|
||||
BlueprintIdentifier = "82BA18911C4BBCBA00A0916E"
|
||||
BuildableName = "CoreStoreTests.xctest"
|
||||
BlueprintName = "CoreStoreTests tvOS"
|
||||
ReferencedContainer = "container:CoreStore.xcodeproj">
|
||||
</BuildableReference>
|
||||
</TestableReference>
|
||||
</Testables>
|
||||
<MacroExpansion>
|
||||
<BuildableReference
|
||||
BuildableIdentifier = "primary"
|
||||
BlueprintIdentifier = "82BA18881C4BBCBA00A0916E"
|
||||
BuildableName = "CoreStore.framework"
|
||||
BlueprintName = "CoreStore tvOS"
|
||||
ReferencedContainer = "container:CoreStore.xcodeproj">
|
||||
</BuildableReference>
|
||||
</MacroExpansion>
|
||||
<AdditionalOptions>
|
||||
</AdditionalOptions>
|
||||
</TestAction>
|
||||
<LaunchAction
|
||||
buildConfiguration = "Debug"
|
||||
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
|
||||
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
|
||||
launchStyle = "0"
|
||||
useCustomWorkingDirectory = "NO"
|
||||
ignoresPersistentStateOnLaunch = "NO"
|
||||
debugDocumentVersioning = "YES"
|
||||
debugServiceExtension = "internal"
|
||||
allowLocationSimulation = "YES">
|
||||
<MacroExpansion>
|
||||
<BuildableReference
|
||||
BuildableIdentifier = "primary"
|
||||
BlueprintIdentifier = "82BA18881C4BBCBA00A0916E"
|
||||
BuildableName = "CoreStore.framework"
|
||||
BlueprintName = "CoreStore tvOS"
|
||||
ReferencedContainer = "container:CoreStore.xcodeproj">
|
||||
</BuildableReference>
|
||||
</MacroExpansion>
|
||||
<AdditionalOptions>
|
||||
</AdditionalOptions>
|
||||
</LaunchAction>
|
||||
<ProfileAction
|
||||
buildConfiguration = "Release"
|
||||
shouldUseLaunchSchemeArgsEnv = "YES"
|
||||
savedToolIdentifier = ""
|
||||
useCustomWorkingDirectory = "NO"
|
||||
debugDocumentVersioning = "YES">
|
||||
<MacroExpansion>
|
||||
<BuildableReference
|
||||
BuildableIdentifier = "primary"
|
||||
BlueprintIdentifier = "82BA18881C4BBCBA00A0916E"
|
||||
BuildableName = "CoreStore.framework"
|
||||
BlueprintName = "CoreStore tvOS"
|
||||
ReferencedContainer = "container:CoreStore.xcodeproj">
|
||||
</BuildableReference>
|
||||
</MacroExpansion>
|
||||
</ProfileAction>
|
||||
<AnalyzeAction
|
||||
buildConfiguration = "Debug">
|
||||
</AnalyzeAction>
|
||||
<ArchiveAction
|
||||
buildConfiguration = "Release"
|
||||
revealArchiveInOrganizer = "YES">
|
||||
</ArchiveAction>
|
||||
</Scheme>
|
||||
@@ -1,7 +1,7 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<Scheme
|
||||
LastUpgradeVersion = "0630"
|
||||
version = "1.8">
|
||||
LastUpgradeVersion = "0700"
|
||||
version = "1.3">
|
||||
<BuildAction
|
||||
parallelizeBuildables = "YES"
|
||||
buildImplicitDependencies = "YES">
|
||||
@@ -14,72 +14,61 @@
|
||||
buildForAnalyzing = "YES">
|
||||
<BuildableReference
|
||||
BuildableIdentifier = "primary"
|
||||
BlueprintIdentifier = "B54AAD481AF4D26E00848AE0"
|
||||
BuildableName = "CoreStoreDemo.app"
|
||||
BlueprintName = "CoreStoreDemo"
|
||||
ReferencedContainer = "container:CoreStoreDemo.xcodeproj">
|
||||
BlueprintIdentifier = "B563216E1BD65082006C9394"
|
||||
BuildableName = "CoreStore.framework"
|
||||
BlueprintName = "CoreStore watchOS"
|
||||
ReferencedContainer = "container:CoreStore.xcodeproj">
|
||||
</BuildableReference>
|
||||
</BuildActionEntry>
|
||||
</BuildActionEntries>
|
||||
</BuildAction>
|
||||
<TestAction
|
||||
buildConfiguration = "Debug"
|
||||
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
|
||||
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
|
||||
shouldUseLaunchSchemeArgsEnv = "YES"
|
||||
buildConfiguration = "Debug">
|
||||
shouldUseLaunchSchemeArgsEnv = "YES">
|
||||
<Testables>
|
||||
</Testables>
|
||||
<MacroExpansion>
|
||||
<BuildableReference
|
||||
BuildableIdentifier = "primary"
|
||||
BlueprintIdentifier = "B54AAD481AF4D26E00848AE0"
|
||||
BuildableName = "CoreStoreDemo.app"
|
||||
BlueprintName = "CoreStoreDemo"
|
||||
ReferencedContainer = "container:CoreStoreDemo.xcodeproj">
|
||||
</BuildableReference>
|
||||
</MacroExpansion>
|
||||
<AdditionalOptions>
|
||||
</AdditionalOptions>
|
||||
</TestAction>
|
||||
<LaunchAction
|
||||
buildConfiguration = "Debug"
|
||||
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
|
||||
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
|
||||
launchStyle = "0"
|
||||
useCustomWorkingDirectory = "NO"
|
||||
buildConfiguration = "Debug"
|
||||
ignoresPersistentStateOnLaunch = "NO"
|
||||
debugDocumentVersioning = "YES"
|
||||
debugServiceExtension = "internal"
|
||||
allowLocationSimulation = "YES">
|
||||
<BuildableProductRunnable
|
||||
runnableDebuggingMode = "0">
|
||||
<MacroExpansion>
|
||||
<BuildableReference
|
||||
BuildableIdentifier = "primary"
|
||||
BlueprintIdentifier = "B54AAD481AF4D26E00848AE0"
|
||||
BuildableName = "CoreStoreDemo.app"
|
||||
BlueprintName = "CoreStoreDemo"
|
||||
ReferencedContainer = "container:CoreStoreDemo.xcodeproj">
|
||||
BlueprintIdentifier = "B563216E1BD65082006C9394"
|
||||
BuildableName = "CoreStore.framework"
|
||||
BlueprintName = "CoreStore watchOS"
|
||||
ReferencedContainer = "container:CoreStore.xcodeproj">
|
||||
</BuildableReference>
|
||||
</BuildableProductRunnable>
|
||||
</MacroExpansion>
|
||||
<AdditionalOptions>
|
||||
</AdditionalOptions>
|
||||
</LaunchAction>
|
||||
<ProfileAction
|
||||
buildConfiguration = "Release"
|
||||
shouldUseLaunchSchemeArgsEnv = "YES"
|
||||
savedToolIdentifier = ""
|
||||
useCustomWorkingDirectory = "NO"
|
||||
buildConfiguration = "Release"
|
||||
debugDocumentVersioning = "YES">
|
||||
<BuildableProductRunnable
|
||||
runnableDebuggingMode = "0">
|
||||
<MacroExpansion>
|
||||
<BuildableReference
|
||||
BuildableIdentifier = "primary"
|
||||
BlueprintIdentifier = "B54AAD481AF4D26E00848AE0"
|
||||
BuildableName = "CoreStoreDemo.app"
|
||||
BlueprintName = "CoreStoreDemo"
|
||||
ReferencedContainer = "container:CoreStoreDemo.xcodeproj">
|
||||
BlueprintIdentifier = "B563216E1BD65082006C9394"
|
||||
BuildableName = "CoreStore.framework"
|
||||
BlueprintName = "CoreStore watchOS"
|
||||
ReferencedContainer = "container:CoreStore.xcodeproj">
|
||||
</BuildableReference>
|
||||
</BuildableProductRunnable>
|
||||
</MacroExpansion>
|
||||
</ProfileAction>
|
||||
<AnalyzeAction
|
||||
buildConfiguration = "Debug">
|
||||
13
CoreStore.xcworkspace/contents.xcworkspacedata
generated
Normal file
@@ -0,0 +1,13 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<Workspace
|
||||
version = "1.0">
|
||||
<FileRef
|
||||
location = "group:CoreStore.xcodeproj">
|
||||
</FileRef>
|
||||
<FileRef
|
||||
location = "group:CoreStoreDemo/CoreStoreDemo.xcodeproj">
|
||||
</FileRef>
|
||||
<FileRef
|
||||
location = "group:Carthage/Checkouts/GCDKit/GCDKit.xcodeproj">
|
||||
</FileRef>
|
||||
</Workspace>
|
||||
37
CoreStore.xcworkspace/xcshareddata/CoreStore.xcscmblueprint
Normal file
@@ -0,0 +1,37 @@
|
||||
{
|
||||
"DVTSourceControlWorkspaceBlueprintPrimaryRemoteRepositoryKey" : "4B60F1BCB491FF717C56441AE7783C74F417BE48",
|
||||
"DVTSourceControlWorkspaceBlueprintWorkingCopyRepositoryLocationsKey" : {
|
||||
|
||||
},
|
||||
"DVTSourceControlWorkspaceBlueprintWorkingCopyStatesKey" : {
|
||||
"8B2E522D57154DFA93A06982C36315ECBEA4FA97" : 0,
|
||||
"95438028B10BBB846574013D29F154A00556A9D1" : 0,
|
||||
"4B60F1BCB491FF717C56441AE7783C74F417BE48" : 0
|
||||
},
|
||||
"DVTSourceControlWorkspaceBlueprintIdentifierKey" : "EBFDEFFE-8BA0-441A-862A-1DE28AA5CD21",
|
||||
"DVTSourceControlWorkspaceBlueprintWorkingCopyPathsKey" : {
|
||||
"8B2E522D57154DFA93A06982C36315ECBEA4FA97" : "CoreStore\/Carthage\/Checkouts\/GCDKit\/",
|
||||
"95438028B10BBB846574013D29F154A00556A9D1" : "CoreStore\/Carthage\/Checkouts\/Nimble\/",
|
||||
"4B60F1BCB491FF717C56441AE7783C74F417BE48" : "CoreStore\/"
|
||||
},
|
||||
"DVTSourceControlWorkspaceBlueprintNameKey" : "CoreStore",
|
||||
"DVTSourceControlWorkspaceBlueprintVersion" : 204,
|
||||
"DVTSourceControlWorkspaceBlueprintRelativePathToProjectKey" : "CoreStore.xcworkspace",
|
||||
"DVTSourceControlWorkspaceBlueprintRemoteRepositoriesKey" : [
|
||||
{
|
||||
"DVTSourceControlWorkspaceBlueprintRemoteRepositoryURLKey" : "https:\/\/github.com\/JohnEstropia\/CoreStore",
|
||||
"DVTSourceControlWorkspaceBlueprintRemoteRepositorySystemKey" : "com.apple.dt.Xcode.sourcecontrol.Git",
|
||||
"DVTSourceControlWorkspaceBlueprintRemoteRepositoryIdentifierKey" : "4B60F1BCB491FF717C56441AE7783C74F417BE48"
|
||||
},
|
||||
{
|
||||
"DVTSourceControlWorkspaceBlueprintRemoteRepositoryURLKey" : "https:\/\/github.com\/JohnEstropia\/GCDKit.git",
|
||||
"DVTSourceControlWorkspaceBlueprintRemoteRepositorySystemKey" : "com.apple.dt.Xcode.sourcecontrol.Git",
|
||||
"DVTSourceControlWorkspaceBlueprintRemoteRepositoryIdentifierKey" : "8B2E522D57154DFA93A06982C36315ECBEA4FA97"
|
||||
},
|
||||
{
|
||||
"DVTSourceControlWorkspaceBlueprintRemoteRepositoryURLKey" : "https:\/\/github.com\/Quick\/Nimble.git",
|
||||
"DVTSourceControlWorkspaceBlueprintRemoteRepositorySystemKey" : "com.apple.dt.Xcode.sourcecontrol.Git",
|
||||
"DVTSourceControlWorkspaceBlueprintRemoteRepositoryIdentifierKey" : "95438028B10BBB846574013D29F154A00556A9D1"
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -1,271 +0,0 @@
|
||||
//
|
||||
// BaseDataTransaction+Querying.swift
|
||||
// CoreStore
|
||||
//
|
||||
// Copyright (c) 2015 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
|
||||
|
||||
|
||||
// MARK: - DataTransaction
|
||||
|
||||
public extension BaseDataTransaction {
|
||||
|
||||
// MARK: Public
|
||||
|
||||
/**
|
||||
Fetches the first `NSManagedObject` instance that satisfies the specified `FetchClause`s. Accepts `Where`, `OrderBy`, and `Tweak` clauses.
|
||||
|
||||
:param: from a `From` clause indicating the entity type
|
||||
:param: fetchClauses a series of `FetchClause` instances for the fetch request. Accepts `Where`, `OrderBy`, and `Tweak` clauses.
|
||||
:returns: the first `NSManagedObject` instance that satisfies the specified `FetchClause`s
|
||||
*/
|
||||
public func fetchOne<T: NSManagedObject>(from: From<T>, _ fetchClauses: FetchClause...) -> T? {
|
||||
|
||||
CoreStore.assert(self.transactionQueue.isCurrentExecutionContext(), "Attempted to fetch from a \(typeName(self)) outside its designated queue.")
|
||||
|
||||
return self.context.fetchOne(from, fetchClauses)
|
||||
}
|
||||
|
||||
/**
|
||||
Fetches the first `NSManagedObject` instance that satisfies the specified `FetchClause`s. Accepts `Where`, `OrderBy`, and `Tweak` clauses.
|
||||
|
||||
:param: from a `From` clause indicating the entity type
|
||||
:param: fetchClauses a series of `FetchClause` instances for the fetch request. Accepts `Where`, `OrderBy`, and `Tweak` clauses.
|
||||
:returns: the first `NSManagedObject` instance that satisfies the specified `FetchClause`s
|
||||
*/
|
||||
public func fetchOne<T: NSManagedObject>(from: From<T>, _ fetchClauses: [FetchClause]) -> T? {
|
||||
|
||||
CoreStore.assert(self.transactionQueue.isCurrentExecutionContext(), "Attempted to fetch from a \(typeName(self)) outside its designated queue.")
|
||||
|
||||
return self.context.fetchOne(from, fetchClauses)
|
||||
}
|
||||
|
||||
/**
|
||||
Fetches all `NSManagedObject` instances that satisfy the specified `FetchClause`s. Accepts `Where`, `OrderBy`, and `Tweak` clauses.
|
||||
|
||||
:param: from a `From` clause indicating the entity type
|
||||
:param: fetchClauses a series of `FetchClause` instances for the fetch request. Accepts `Where`, `OrderBy`, and `Tweak` clauses.
|
||||
:returns: all `NSManagedObject` instances that satisfy the specified `FetchClause`s
|
||||
*/
|
||||
public func fetchAll<T: NSManagedObject>(from: From<T>, _ fetchClauses: FetchClause...) -> [T]? {
|
||||
|
||||
CoreStore.assert(self.transactionQueue.isCurrentExecutionContext(), "Attempted to fetch from a \(typeName(self)) outside its designated queue.")
|
||||
|
||||
return self.context.fetchAll(from, fetchClauses)
|
||||
}
|
||||
|
||||
/**
|
||||
Fetches all `NSManagedObject` instances that satisfy the specified `FetchClause`s. Accepts `Where`, `OrderBy`, and `Tweak` clauses.
|
||||
|
||||
:param: from a `From` clause indicating the entity type
|
||||
:param: fetchClauses a series of `FetchClause` instances for the fetch request. Accepts `Where`, `OrderBy`, and `Tweak` clauses.
|
||||
:returns: all `NSManagedObject` instances that satisfy the specified `FetchClause`s
|
||||
*/
|
||||
public func fetchAll<T: NSManagedObject>(from: From<T>, _ fetchClauses: [FetchClause]) -> [T]? {
|
||||
|
||||
CoreStore.assert(self.transactionQueue.isCurrentExecutionContext(), "Attempted to fetch from a \(typeName(self)) outside its designated queue.")
|
||||
|
||||
return self.context.fetchAll(from, fetchClauses)
|
||||
}
|
||||
|
||||
/**
|
||||
Fetches the number of `NSManagedObject`'s that satisfy the specified `FetchClause`s. Accepts `Where`, `OrderBy`, and `Tweak` clauses.
|
||||
|
||||
:param: from a `From` clause indicating the entity type
|
||||
:param: fetchClauses a series of `FetchClause` instances for the fetch request. Accepts `Where`, `OrderBy`, and `Tweak` clauses.
|
||||
:returns: the number `NSManagedObject`'s that satisfy the specified `FetchClause`s
|
||||
*/
|
||||
public func fetchCount<T: NSManagedObject>(from: From<T>, _ fetchClauses: FetchClause...) -> Int? {
|
||||
|
||||
CoreStore.assert(self.transactionQueue.isCurrentExecutionContext(), "Attempted to fetch from a \(typeName(self)) outside its designated queue.")
|
||||
|
||||
return self.context.fetchCount(from, fetchClauses)
|
||||
}
|
||||
|
||||
/**
|
||||
Fetches the number of `NSManagedObject`'s that satisfy the specified `FetchClause`s. Accepts `Where`, `OrderBy`, and `Tweak` clauses.
|
||||
|
||||
:param: from a `From` clause indicating the entity type
|
||||
:param: fetchClauses a series of `FetchClause` instances for the fetch request. Accepts `Where`, `OrderBy`, and `Tweak` clauses.
|
||||
:returns: the number `NSManagedObject`'s that satisfy the specified `FetchClause`s
|
||||
*/
|
||||
public func fetchCount<T: NSManagedObject>(from: From<T>, _ fetchClauses: [FetchClause]) -> Int? {
|
||||
|
||||
CoreStore.assert(self.transactionQueue.isCurrentExecutionContext(), "Attempted to fetch from a \(typeName(self)) outside its designated queue.")
|
||||
|
||||
return self.context.fetchCount(from, fetchClauses)
|
||||
}
|
||||
|
||||
/**
|
||||
Fetches the `NSManagedObjectID` for the first `NSManagedObject` that satisfies the specified `FetchClause`s. Accepts `Where`, `OrderBy`, and `Tweak` clauses.
|
||||
|
||||
:param: from a `From` clause indicating the entity type
|
||||
:param: fetchClauses a series of `FetchClause` instances for the fetch request. Accepts `Where`, `OrderBy`, and `Tweak` clauses.
|
||||
:returns: the `NSManagedObjectID` for the first `NSManagedObject` that satisfies the specified `FetchClause`s
|
||||
*/
|
||||
public func fetchObjectID<T: NSManagedObject>(from: From<T>, _ fetchClauses: FetchClause...) -> NSManagedObjectID? {
|
||||
|
||||
CoreStore.assert(self.transactionQueue.isCurrentExecutionContext(), "Attempted to fetch from a \(typeName(self)) outside its designated queue.")
|
||||
|
||||
return self.context.fetchObjectID(from, fetchClauses)
|
||||
}
|
||||
|
||||
/**
|
||||
Fetches the `NSManagedObjectID` for the first `NSManagedObject` that satisfies the specified `FetchClause`s. Accepts `Where`, `OrderBy`, and `Tweak` clauses.
|
||||
|
||||
:param: from a `From` clause indicating the entity type
|
||||
:param: fetchClauses a series of `FetchClause` instances for the fetch request. Accepts `Where`, `OrderBy`, and `Tweak` clauses.
|
||||
:returns: the `NSManagedObjectID` for the first `NSManagedObject` that satisfies the specified `FetchClause`s
|
||||
*/
|
||||
public func fetchObjectID<T: NSManagedObject>(from: From<T>, _ fetchClauses: [FetchClause]) -> NSManagedObjectID? {
|
||||
|
||||
CoreStore.assert(self.transactionQueue.isCurrentExecutionContext(), "Attempted to fetch from a \(typeName(self)) outside its designated queue.")
|
||||
|
||||
return self.context.fetchObjectID(from, fetchClauses)
|
||||
}
|
||||
|
||||
/**
|
||||
Fetches the `NSManagedObjectID` for all `NSManagedObject`'s that satisfy the specified `FetchClause`s. Accepts `Where`, `OrderBy`, and `Tweak` clauses.
|
||||
|
||||
:param: from a `From` clause indicating the entity type
|
||||
:param: fetchClauses a series of `FetchClause` instances for the fetch request. Accepts `Where`, `OrderBy`, and `Tweak` clauses.
|
||||
:returns: the `NSManagedObjectID` for all `NSManagedObject`'s that satisfy the specified `FetchClause`s
|
||||
*/
|
||||
public func fetchObjectIDs<T: NSManagedObject>(from: From<T>, _ fetchClauses: FetchClause...) -> [NSManagedObjectID]? {
|
||||
|
||||
CoreStore.assert(self.transactionQueue.isCurrentExecutionContext(), "Attempted to fetch from a \(typeName(self)) outside its designated queue.")
|
||||
|
||||
return self.context.fetchObjectIDs(from, fetchClauses)
|
||||
}
|
||||
|
||||
/**
|
||||
Fetches the `NSManagedObjectID` for all `NSManagedObject`'s that satisfy the specified `FetchClause`s. Accepts `Where`, `OrderBy`, and `Tweak` clauses.
|
||||
|
||||
:param: from a `From` clause indicating the entity type
|
||||
:param: fetchClauses a series of `FetchClause` instances for the fetch request. Accepts `Where`, `OrderBy`, and `Tweak` clauses.
|
||||
:returns: the `NSManagedObjectID` for all `NSManagedObject`'s that satisfy the specified `FetchClause`s
|
||||
*/
|
||||
public func fetchObjectIDs<T: NSManagedObject>(from: From<T>, _ fetchClauses: [FetchClause]) -> [NSManagedObjectID]? {
|
||||
|
||||
CoreStore.assert(self.transactionQueue.isCurrentExecutionContext(), "Attempted to fetch from a \(typeName(self)) outside its designated queue.")
|
||||
|
||||
return self.context.fetchObjectIDs(from, fetchClauses)
|
||||
}
|
||||
|
||||
/**
|
||||
Deletes all `NSManagedObject`'s that satisfy the specified `DeleteClause`s. Accepts `Where`, `OrderBy`, and `Tweak` clauses.
|
||||
|
||||
:param: from a `From` clause indicating the entity type
|
||||
:param: deleteClauses a series of `DeleteClause` instances for the delete request. Accepts `Where`, `OrderBy`, and `Tweak` clauses.
|
||||
:returns: the number of `NSManagedObject`'s deleted
|
||||
*/
|
||||
public func deleteAll<T: NSManagedObject>(from: From<T>, _ deleteClauses: DeleteClause...) -> Int? {
|
||||
|
||||
CoreStore.assert(self.transactionQueue.isCurrentExecutionContext(), "Attempted to delete from a \(typeName(self)) outside its designated queue.")
|
||||
|
||||
return self.context.deleteAll(from, deleteClauses)
|
||||
}
|
||||
|
||||
/**
|
||||
Deletes all `NSManagedObject`'s that satisfy the specified `DeleteClause`s. Accepts `Where`, `OrderBy`, and `Tweak` clauses.
|
||||
|
||||
:param: from a `From` clause indicating the entity type
|
||||
:param: deleteClauses a series of `DeleteClause` instances for the delete request. Accepts `Where`, `OrderBy`, and `Tweak` clauses.
|
||||
:returns: the number of `NSManagedObject`'s deleted
|
||||
*/
|
||||
public func deleteAll<T: NSManagedObject>(from: From<T>, _ deleteClauses: [DeleteClause]) -> Int? {
|
||||
|
||||
CoreStore.assert(self.transactionQueue.isCurrentExecutionContext(), "Attempted to delete from a \(typeName(self)) outside its designated queue.")
|
||||
|
||||
return self.context.deleteAll(from, deleteClauses)
|
||||
}
|
||||
|
||||
/**
|
||||
Queries aggregate values as specified by the `QueryClause`'s. Requires at least a `Select` clause, and optional `Where`, `OrderBy`, `GroupBy`, and `Tweak` clauses.
|
||||
|
||||
A "query" differs from a "fetch" in that it only retrieves values already stored in the persistent store. As such, values from unsaved transactions or contexts will not be incorporated in the query result.
|
||||
|
||||
:param: from a `From` clause indicating the entity type
|
||||
:param: selectClause a `Select<U>` clause indicating the properties to fetch, and with the generic type indicating the return type.
|
||||
:param: queryClauses a series of `QueryClause` instances for the query request. Accepts `Where`, `OrderBy`, `GroupBy`, and `Tweak` clauses.
|
||||
:returns: the result of the the query. The type of the return value is specified by the generic type of the `Select<U>` parameter.
|
||||
*/
|
||||
public func queryValue<T: NSManagedObject, U: SelectValueResultType>(from: From<T>, _ selectClause: Select<U>, _ queryClauses: QueryClause...) -> U? {
|
||||
|
||||
CoreStore.assert(self.transactionQueue.isCurrentExecutionContext(), "Attempted to query from a \(typeName(self)) outside its designated queue.")
|
||||
|
||||
return self.context.queryValue(from, selectClause, queryClauses)
|
||||
}
|
||||
|
||||
/**
|
||||
Queries aggregate values or aggregates as specified by the `QueryClause`'s. Requires at least a `Select` clause, and optional `Where`, `OrderBy`, `GroupBy`, and `Tweak` clauses.
|
||||
|
||||
A "query" differs from a "fetch" in that it only retrieves values already stored in the persistent store. As such, values from unsaved transactions or contexts will not be incorporated in the query result.
|
||||
|
||||
:param: from a `From` clause indicating the entity type
|
||||
:param: selectClause a `Select<U>` clause indicating the properties to fetch, and with the generic type indicating the return type.
|
||||
:param: queryClauses a series of `QueryClause` instances for the query request. Accepts `Where`, `OrderBy`, `GroupBy`, and `Tweak` clauses.
|
||||
:returns: the result of the the query. The type of the return value is specified by the generic type of the `Select<U>` parameter.
|
||||
*/
|
||||
public func queryValue<T: NSManagedObject, U: SelectValueResultType>(from: From<T>, _ selectClause: Select<U>, _ queryClauses: [QueryClause]) -> U? {
|
||||
|
||||
CoreStore.assert(self.transactionQueue.isCurrentExecutionContext(), "Attempted to query from a \(typeName(self)) outside its designated queue.")
|
||||
|
||||
return self.context.queryValue(from, selectClause, queryClauses)
|
||||
}
|
||||
|
||||
/**
|
||||
Queries a dictionary of attribute values as specified by the `QueryClause`'s. Requires at least a `Select` clause, and optional `Where`, `OrderBy`, `GroupBy`, and `Tweak` clauses.
|
||||
|
||||
A "query" differs from a "fetch" in that it only retrieves values already stored in the persistent store. As such, values from unsaved transactions or contexts will not be incorporated in the query result.
|
||||
|
||||
:param: from a `From` clause indicating the entity type
|
||||
:param: selectClause a `Select<U>` clause indicating the properties to fetch, and with the generic type indicating the return type.
|
||||
:param: queryClauses a series of `QueryClause` instances for the query request. Accepts `Where`, `OrderBy`, `GroupBy`, and `Tweak` clauses.
|
||||
:returns: the result of the the query. The type of the return value is specified by the generic type of the `Select<U>` parameter.
|
||||
*/
|
||||
public func queryAttributes<T: NSManagedObject>(from: From<T>, _ selectClause: Select<NSDictionary>, _ queryClauses: QueryClause...) -> [[NSString: AnyObject]]? {
|
||||
|
||||
CoreStore.assert(self.transactionQueue.isCurrentExecutionContext(), "Attempted to query from a \(typeName(self)) outside its designated queue.")
|
||||
|
||||
return self.context.queryAttributes(from, selectClause, queryClauses)
|
||||
}
|
||||
|
||||
/**
|
||||
Queries a dictionary of attribute values as specified by the `QueryClause`'s. Requires at least a `Select` clause, and optional `Where`, `OrderBy`, `GroupBy`, and `Tweak` clauses.
|
||||
|
||||
A "query" differs from a "fetch" in that it only retrieves values already stored in the persistent store. As such, values from unsaved transactions or contexts will not be incorporated in the query result.
|
||||
|
||||
:param: from a `From` clause indicating the entity type
|
||||
:param: selectClause a `Select<U>` clause indicating the properties to fetch, and with the generic type indicating the return type.
|
||||
:param: queryClauses a series of `QueryClause` instances for the query request. Accepts `Where`, `OrderBy`, `GroupBy`, and `Tweak` clauses.
|
||||
:returns: the result of the the query. The type of the return value is specified by the generic type of the `Select<U>` parameter.
|
||||
*/
|
||||
public func queryAttributes<T: NSManagedObject>(from: From<T>, _ selectClause: Select<NSDictionary>, _ queryClauses: [QueryClause]) -> [[NSString: AnyObject]]? {
|
||||
|
||||
CoreStore.assert(self.transactionQueue.isCurrentExecutionContext(), "Attempted to query from a \(typeName(self)) outside its designated queue.")
|
||||
|
||||
return self.context.queryAttributes(from, selectClause, queryClauses)
|
||||
}
|
||||
}
|
||||
@@ -1,158 +0,0 @@
|
||||
//
|
||||
// From.swift
|
||||
// CoreStore
|
||||
//
|
||||
// Copyright (c) 2015 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
|
||||
|
||||
|
||||
// MARK: - From
|
||||
|
||||
/**
|
||||
A `Form` clause binds the `NSManagedObject` entity type to the generics type system.
|
||||
*/
|
||||
public struct From<T: NSManagedObject> {
|
||||
|
||||
// MARK: Public
|
||||
|
||||
public init(){
|
||||
|
||||
self.findPersistentStores = { _ in nil }
|
||||
}
|
||||
|
||||
public init(_ entity: T.Type) {
|
||||
|
||||
self.findPersistentStores = { _ in nil }
|
||||
}
|
||||
|
||||
public init(_ configurations: String?...) {
|
||||
|
||||
self.init(configurations: configurations)
|
||||
}
|
||||
|
||||
public init(_ configurations: [String?]) {
|
||||
|
||||
self.init(configurations: configurations)
|
||||
}
|
||||
|
||||
public init(_ entity: T.Type, _ configurations: String?...) {
|
||||
|
||||
self.init(configurations: configurations)
|
||||
}
|
||||
|
||||
public init(_ entity: T.Type, _ configurations: [String?]) {
|
||||
|
||||
self.init(configurations: configurations)
|
||||
}
|
||||
|
||||
public init(_ storeURLs: NSURL...) {
|
||||
|
||||
self.init(storeURLs: storeURLs)
|
||||
}
|
||||
|
||||
public init(_ storeURLs: [NSURL]) {
|
||||
|
||||
self.init(storeURLs: storeURLs)
|
||||
}
|
||||
|
||||
public init(_ entity: T.Type, _ storeURLs: NSURL...) {
|
||||
|
||||
self.init(storeURLs: storeURLs)
|
||||
}
|
||||
|
||||
public init(_ entity: T.Type, _ storeURLs: [NSURL]) {
|
||||
|
||||
self.init(storeURLs: storeURLs)
|
||||
}
|
||||
|
||||
public init(_ persistentStores: NSPersistentStore...) {
|
||||
|
||||
self.init(persistentStores: persistentStores)
|
||||
}
|
||||
|
||||
public init(_ persistentStores: [NSPersistentStore]) {
|
||||
|
||||
self.init(persistentStores: persistentStores)
|
||||
}
|
||||
|
||||
public init(_ entity: T.Type, _ persistentStores: NSPersistentStore...) {
|
||||
|
||||
self.init(persistentStores: persistentStores)
|
||||
}
|
||||
|
||||
public init(_ entity: T.Type, _ persistentStores: [NSPersistentStore]) {
|
||||
|
||||
self.init(persistentStores: persistentStores)
|
||||
}
|
||||
|
||||
|
||||
// MARK: Internal
|
||||
|
||||
internal func applyToFetchRequest(fetchRequest: NSFetchRequest, context: NSManagedObjectContext) {
|
||||
|
||||
fetchRequest.entity = context.entityDescriptionForEntityClass(T.self)
|
||||
fetchRequest.affectedStores = self.findPersistentStores(context: context)
|
||||
}
|
||||
|
||||
|
||||
// MARK: Private
|
||||
|
||||
private let findPersistentStores: (context: NSManagedObjectContext) -> [NSPersistentStore]?
|
||||
|
||||
private init(configurations: [String?]) {
|
||||
|
||||
let configurationsSet = Set(configurations.map { $0 ?? Into.defaultConfigurationName })
|
||||
self.findPersistentStores = { (context: NSManagedObjectContext) -> [NSPersistentStore]? in
|
||||
|
||||
return context.parentStack?.persistentStoresForEntityClass(T.self)?.filter {
|
||||
|
||||
return configurationsSet.contains($0.configurationName)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private init(storeURLs: [NSURL]) {
|
||||
|
||||
let storeURLsSet = Set(storeURLs)
|
||||
self.findPersistentStores = { (context: NSManagedObjectContext) -> [NSPersistentStore]? in
|
||||
|
||||
return context.parentStack?.persistentStoresForEntityClass(T.self)?.filter {
|
||||
|
||||
return $0.URL != nil && storeURLsSet.contains($0.URL!)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private init(persistentStores: [NSPersistentStore]) {
|
||||
|
||||
let persistentStores = Set(persistentStores)
|
||||
self.findPersistentStores = { (context: NSManagedObjectContext) -> [NSPersistentStore]? in
|
||||
|
||||
return context.parentStack?.persistentStoresForEntityClass(T.self)?.filter {
|
||||
|
||||
return persistentStores.contains($0)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,213 +0,0 @@
|
||||
//
|
||||
// CoreStore+Querying.swift
|
||||
// CoreStore
|
||||
//
|
||||
// Copyright (c) 2015 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
|
||||
|
||||
// MARK: - CoreStore
|
||||
|
||||
public extension CoreStore {
|
||||
|
||||
// MARK: Public
|
||||
|
||||
/**
|
||||
Using the `defaultStack`, fetches the first `NSManagedObject` instance that satisfies the specified `FetchClause`s. Accepts `Where`, `OrderBy`, and `Tweak` clauses.
|
||||
|
||||
:param: from a `From` clause indicating the entity type
|
||||
:param: fetchClauses a series of `FetchClause` instances for the fetch request. Accepts `Where`, `OrderBy`, and `Tweak` clauses.
|
||||
:returns: the first `NSManagedObject` instance that satisfies the specified `FetchClause`s
|
||||
*/
|
||||
public static func fetchOne<T: NSManagedObject>(from: From<T>, _ fetchClauses: FetchClause...) -> T? {
|
||||
|
||||
return self.defaultStack.fetchOne(from, fetchClauses)
|
||||
}
|
||||
|
||||
/**
|
||||
Using the `defaultStack`, fetches the first `NSManagedObject` instance that satisfies the specified `FetchClause`s. Accepts `Where`, `OrderBy`, and `Tweak` clauses.
|
||||
|
||||
:param: from a `From` clause indicating the entity type
|
||||
:param: fetchClauses a series of `FetchClause` instances for the fetch request. Accepts `Where`, `OrderBy`, and `Tweak` clauses.
|
||||
:returns: the first `NSManagedObject` instance that satisfies the specified `FetchClause`s
|
||||
*/
|
||||
public static func fetchOne<T: NSManagedObject>(from: From<T>, _ fetchClauses: [FetchClause]) -> T? {
|
||||
|
||||
return self.defaultStack.fetchOne(from, fetchClauses)
|
||||
}
|
||||
|
||||
/**
|
||||
Using the `defaultStack`, fetches all `NSManagedObject` instances that satisfy the specified `FetchClause`s. Accepts `Where`, `OrderBy`, and `Tweak` clauses.
|
||||
|
||||
:param: from a `From` clause indicating the entity type
|
||||
:param: fetchClauses a series of `FetchClause` instances for the fetch request. Accepts `Where`, `OrderBy`, and `Tweak` clauses.
|
||||
:returns: all `NSManagedObject` instances that satisfy the specified `FetchClause`s
|
||||
*/
|
||||
public static func fetchAll<T: NSManagedObject>(from: From<T>, _ fetchClauses: FetchClause...) -> [T]? {
|
||||
|
||||
return self.defaultStack.fetchAll(from, fetchClauses)
|
||||
}
|
||||
|
||||
/**
|
||||
Using the `defaultStack`, fetches all `NSManagedObject` instances that satisfy the specified `FetchClause`s. Accepts `Where`, `OrderBy`, and `Tweak` clauses.
|
||||
|
||||
:param: from a `From` clause indicating the entity type
|
||||
:param: fetchClauses a series of `FetchClause` instances for the fetch request. Accepts `Where`, `OrderBy`, and `Tweak` clauses.
|
||||
:returns: all `NSManagedObject` instances that satisfy the specified `FetchClause`s
|
||||
*/
|
||||
public static func fetchAll<T: NSManagedObject>(from: From<T>, _ fetchClauses: [FetchClause]) -> [T]? {
|
||||
|
||||
return self.defaultStack.fetchAll(from, fetchClauses)
|
||||
}
|
||||
|
||||
/**
|
||||
Using the `defaultStack`, fetches the number of `NSManagedObject`'s that satisfy the specified `FetchClause`s. Accepts `Where`, `OrderBy`, and `Tweak` clauses.
|
||||
|
||||
:param: from a `From` clause indicating the entity type
|
||||
:param: fetchClauses a series of `FetchClause` instances for the fetch request. Accepts `Where`, `OrderBy`, and `Tweak` clauses.
|
||||
:returns: the number `NSManagedObject`'s that satisfy the specified `FetchClause`s
|
||||
*/
|
||||
public static func fetchCount<T: NSManagedObject>(from: From<T>, _ fetchClauses: FetchClause...) -> Int? {
|
||||
|
||||
return self.defaultStack.fetchCount(from, fetchClauses)
|
||||
}
|
||||
|
||||
/**
|
||||
Using the `defaultStack`, fetches the number of `NSManagedObject`'s that satisfy the specified `FetchClause`s. Accepts `Where`, `OrderBy`, and `Tweak` clauses.
|
||||
|
||||
:param: from a `From` clause indicating the entity type
|
||||
:param: fetchClauses a series of `FetchClause` instances for the fetch request. Accepts `Where`, `OrderBy`, and `Tweak` clauses.
|
||||
:returns: the number `NSManagedObject`'s that satisfy the specified `FetchClause`s
|
||||
*/
|
||||
public static func fetchCount<T: NSManagedObject>(from: From<T>, _ fetchClauses: [FetchClause]) -> Int? {
|
||||
|
||||
return self.defaultStack.fetchCount(from, fetchClauses)
|
||||
}
|
||||
|
||||
/**
|
||||
Using the `defaultStack`, fetches the `NSManagedObjectID` for the first `NSManagedObject` that satisfies the specified `FetchClause`s. Accepts `Where`, `OrderBy`, and `Tweak` clauses.
|
||||
|
||||
:param: from a `From` clause indicating the entity type
|
||||
:param: fetchClauses a series of `FetchClause` instances for the fetch request. Accepts `Where`, `OrderBy`, and `Tweak` clauses.
|
||||
:returns: the `NSManagedObjectID` for the first `NSManagedObject` that satisfies the specified `FetchClause`s
|
||||
*/
|
||||
public static func fetchObjectID<T: NSManagedObject>(from: From<T>, _ fetchClauses: FetchClause...) -> NSManagedObjectID? {
|
||||
|
||||
return self.defaultStack.fetchObjectID(from, fetchClauses)
|
||||
}
|
||||
|
||||
/**
|
||||
Using the `defaultStack`, fetches the `NSManagedObjectID` for the first `NSManagedObject` that satisfies the specified `FetchClause`s. Accepts `Where`, `OrderBy`, and `Tweak` clauses.
|
||||
|
||||
:param: from a `From` clause indicating the entity type
|
||||
:param: fetchClauses a series of `FetchClause` instances for the fetch request. Accepts `Where`, `OrderBy`, and `Tweak` clauses.
|
||||
:returns: the `NSManagedObjectID` for the first `NSManagedObject` that satisfies the specified `FetchClause`s
|
||||
*/
|
||||
public static func fetchObjectID<T: NSManagedObject>(from: From<T>, _ fetchClauses: [FetchClause]) -> NSManagedObjectID? {
|
||||
|
||||
return self.defaultStack.fetchObjectID(from, fetchClauses)
|
||||
}
|
||||
|
||||
/**
|
||||
Using the `defaultStack`, fetches the `NSManagedObjectID` for all `NSManagedObject`'s that satisfy the specified `FetchClause`s. Accepts `Where`, `OrderBy`, and `Tweak` clauses.
|
||||
|
||||
:param: from a `From` clause indicating the entity type
|
||||
:param: fetchClauses a series of `FetchClause` instances for the fetch request. Accepts `Where`, `OrderBy`, and `Tweak` clauses.
|
||||
:returns: the `NSManagedObjectID` for all `NSManagedObject`'s that satisfy the specified `FetchClause`s
|
||||
*/
|
||||
public static func fetchObjectIDs<T: NSManagedObject>(from: From<T>, _ fetchClauses: FetchClause...) -> [NSManagedObjectID]? {
|
||||
|
||||
return self.defaultStack.fetchObjectIDs(from, fetchClauses)
|
||||
}
|
||||
|
||||
/**
|
||||
Using the `defaultStack`, fetches the `NSManagedObjectID` for all `NSManagedObject`'s that satisfy the specified `FetchClause`s. Accepts `Where`, `OrderBy`, and `Tweak` clauses.
|
||||
|
||||
:param: from a `From` clause indicating the entity type
|
||||
:param: fetchClauses a series of `FetchClause` instances for the fetch request. Accepts `Where`, `OrderBy`, and `Tweak` clauses.
|
||||
:returns: the `NSManagedObjectID` for all `NSManagedObject`'s that satisfy the specified `FetchClause`s
|
||||
*/
|
||||
public static func fetchObjectIDs<T: NSManagedObject>(from: From<T>, _ fetchClauses: [FetchClause]) -> [NSManagedObjectID]? {
|
||||
|
||||
return self.defaultStack.fetchObjectIDs(from, fetchClauses)
|
||||
}
|
||||
|
||||
/**
|
||||
Using the `defaultStack`, queries aggregate values as specified by the `QueryClause`'s. Requires at least a `Select` clause, and optional `Where`, `OrderBy`, `GroupBy`, and `Tweak` clauses.
|
||||
|
||||
A "query" differs from a "fetch" in that it only retrieves values already stored in the persistent store. As such, values from unsaved transactions or contexts will not be incorporated in the query result.
|
||||
|
||||
:param: from a `From` clause indicating the entity type
|
||||
:param: selectClause a `Select<U>` clause indicating the properties to fetch, and with the generic type indicating the return type.
|
||||
:param: queryClauses a series of `QueryClause` instances for the query request. Accepts `Where`, `OrderBy`, `GroupBy`, and `Tweak` clauses.
|
||||
:returns: the result of the the query. The type of the return value is specified by the generic type of the `Select<U>` parameter.
|
||||
*/
|
||||
public static func queryValue<T: NSManagedObject, U: SelectValueResultType>(from: From<T>, _ selectClause: Select<U>, _ queryClauses: QueryClause...) -> U? {
|
||||
|
||||
return self.defaultStack.queryValue(from, selectClause, queryClauses)
|
||||
}
|
||||
|
||||
/**
|
||||
Using the `defaultStack`, queries aggregate values as specified by the `QueryClause`'s. Requires at least a `Select` clause, and optional `Where`, `OrderBy`, `GroupBy`, and `Tweak` clauses.
|
||||
|
||||
A "query" differs from a "fetch" in that it only retrieves values already stored in the persistent store. As such, values from unsaved transactions or contexts will not be incorporated in the query result.
|
||||
|
||||
:param: from a `From` clause indicating the entity type
|
||||
:param: selectClause a `Select<U>` clause indicating the properties to fetch, and with the generic type indicating the return type.
|
||||
:param: queryClauses a series of `QueryClause` instances for the query request. Accepts `Where`, `OrderBy`, `GroupBy`, and `Tweak` clauses.
|
||||
:returns: the result of the the query. The type of the return value is specified by the generic type of the `Select<U>` parameter.
|
||||
*/
|
||||
public static func queryValue<T: NSManagedObject, U: SelectValueResultType>(from: From<T>, _ selectClause: Select<U>, _ queryClauses: [QueryClause]) -> U? {
|
||||
|
||||
return self.defaultStack.queryValue(from, selectClause, queryClauses)
|
||||
}
|
||||
|
||||
/**
|
||||
Using the `defaultStack`, queries a dictionary of attribtue values as specified by the `QueryClause`'s. Requires at least a `Select` clause, and optional `Where`, `OrderBy`, `GroupBy`, and `Tweak` clauses.
|
||||
|
||||
A "query" differs from a "fetch" in that it only retrieves values already stored in the persistent store. As such, values from unsaved transactions or contexts will not be incorporated in the query result.
|
||||
|
||||
:param: from a `From` clause indicating the entity type
|
||||
:param: selectClause a `Select<U>` clause indicating the properties to fetch, and with the generic type indicating the return type.
|
||||
:param: queryClauses a series of `QueryClause` instances for the query request. Accepts `Where`, `OrderBy`, `GroupBy`, and `Tweak` clauses.
|
||||
:returns: the result of the the query. The type of the return value is specified by the generic type of the `Select<U>` parameter.
|
||||
*/
|
||||
public static func queryAttributes<T: NSManagedObject>(from: From<T>, _ selectClause: Select<NSDictionary>, _ queryClauses: QueryClause...) -> [[NSString: AnyObject]]? {
|
||||
|
||||
return self.defaultStack.queryAttributes(from, selectClause, queryClauses)
|
||||
}
|
||||
|
||||
/**
|
||||
Using the `defaultStack`, queries a dictionary of attribute values as specified by the `QueryClause`'s. Requires at least a `Select` clause, and optional `Where`, `OrderBy`, `GroupBy`, and `Tweak` clauses.
|
||||
|
||||
A "query" differs from a "fetch" in that it only retrieves values already stored in the persistent store. As such, values from unsaved transactions or contexts will not be incorporated in the query result.
|
||||
|
||||
:param: from a `From` clause indicating the entity type
|
||||
:param: selectClause a `Select<U>` clause indicating the properties to fetch, and with the generic type indicating the return type.
|
||||
:param: queryClauses a series of `QueryClause` instances for the query request. Accepts `Where`, `OrderBy`, `GroupBy`, and `Tweak` clauses.
|
||||
:returns: the result of the the query. The type of the return value is specified by the generic type of the `Select<U>` parameter.
|
||||
*/
|
||||
public static func queryAttributes<T: NSManagedObject>(from: From<T>, _ selectClause: Select<NSDictionary>, _ queryClauses: [QueryClause]) -> [[NSString: AnyObject]]? {
|
||||
|
||||
return self.defaultStack.queryAttributes(from, selectClause, queryClauses)
|
||||
}
|
||||
}
|
||||
@@ -1,244 +0,0 @@
|
||||
//
|
||||
// DataStack+Querying.swift
|
||||
// CoreStore
|
||||
//
|
||||
// Copyright (c) 2015 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
|
||||
|
||||
|
||||
// MARK: - DataStack
|
||||
|
||||
public extension DataStack {
|
||||
|
||||
// MARK: Public
|
||||
|
||||
/**
|
||||
Fetches the first `NSManagedObject` instance that satisfies the specified `FetchClause`s. Accepts `Where`, `OrderBy`, and `Tweak` clauses.
|
||||
|
||||
:param: from a `From` clause indicating the entity type
|
||||
:param: fetchClauses a series of `FetchClause` instances for the fetch request. Accepts `Where`, `OrderBy`, and `Tweak` clauses.
|
||||
:returns: the first `NSManagedObject` instance that satisfies the specified `FetchClause`s
|
||||
*/
|
||||
public func fetchOne<T: NSManagedObject>(from: From<T>, _ fetchClauses: FetchClause...) -> T? {
|
||||
|
||||
CoreStore.assert(NSThread.isMainThread(), "Attempted to fetch from a \(typeName(self)) outside the main thread.")
|
||||
|
||||
return self.mainContext.fetchOne(from, fetchClauses)
|
||||
}
|
||||
|
||||
/**
|
||||
Fetches the first `NSManagedObject` instance that satisfies the specified `FetchClause`s. Accepts `Where`, `OrderBy`, and `Tweak` clauses.
|
||||
|
||||
:param: from a `From` clause indicating the entity type
|
||||
:param: fetchClauses a series of `FetchClause` instances for the fetch request. Accepts `Where`, `OrderBy`, and `Tweak` clauses.
|
||||
:returns: the first `NSManagedObject` instance that satisfies the specified `FetchClause`s
|
||||
*/
|
||||
public func fetchOne<T: NSManagedObject>(from: From<T>, _ fetchClauses: [FetchClause]) -> T? {
|
||||
|
||||
CoreStore.assert(NSThread.isMainThread(), "Attempted to fetch from a \(typeName(self)) outside the main thread.")
|
||||
|
||||
return self.mainContext.fetchOne(from, fetchClauses)
|
||||
}
|
||||
|
||||
/**
|
||||
Fetches all `NSManagedObject` instances that satisfy the specified `FetchClause`s. Accepts `Where`, `OrderBy`, and `Tweak` clauses.
|
||||
|
||||
:param: from a `From` clause indicating the entity type
|
||||
:param: fetchClauses a series of `FetchClause` instances for the fetch request. Accepts `Where`, `OrderBy`, and `Tweak` clauses.
|
||||
:returns: all `NSManagedObject` instances that satisfy the specified `FetchClause`s
|
||||
*/
|
||||
public func fetchAll<T: NSManagedObject>(from: From<T>, _ fetchClauses: FetchClause...) -> [T]? {
|
||||
|
||||
CoreStore.assert(NSThread.isMainThread(), "Attempted to fetch from a \(typeName(self)) outside the main thread.")
|
||||
|
||||
return self.mainContext.fetchAll(from, fetchClauses)
|
||||
}
|
||||
|
||||
/**
|
||||
Fetches all `NSManagedObject` instances that satisfy the specified `FetchClause`s. Accepts `Where`, `OrderBy`, and `Tweak` clauses.
|
||||
|
||||
:param: from a `From` clause indicating the entity type
|
||||
:param: fetchClauses a series of `FetchClause` instances for the fetch request. Accepts `Where`, `OrderBy`, and `Tweak` clauses.
|
||||
:returns: all `NSManagedObject` instances that satisfy the specified `FetchClause`s
|
||||
*/
|
||||
public func fetchAll<T: NSManagedObject>(from: From<T>, _ fetchClauses: [FetchClause]) -> [T]? {
|
||||
|
||||
CoreStore.assert(NSThread.isMainThread(), "Attempted to fetch from a \(typeName(self)) outside the main thread.")
|
||||
|
||||
return self.mainContext.fetchAll(from, fetchClauses)
|
||||
}
|
||||
|
||||
/**
|
||||
Fetches the number of `NSManagedObject`'s that satisfy the specified `FetchClause`s. Accepts `Where`, `OrderBy`, and `Tweak` clauses.
|
||||
|
||||
:param: from a `From` clause indicating the entity type
|
||||
:param: fetchClauses a series of `FetchClause` instances for the fetch request. Accepts `Where`, `OrderBy`, and `Tweak` clauses.
|
||||
:returns: the number `NSManagedObject`'s that satisfy the specified `FetchClause`s
|
||||
*/
|
||||
public func fetchCount<T: NSManagedObject>(from: From<T>, _ fetchClauses: FetchClause...) -> Int? {
|
||||
|
||||
CoreStore.assert(NSThread.isMainThread(), "Attempted to fetch from a \(typeName(self)) outside the main thread.")
|
||||
|
||||
return self.mainContext.fetchCount(from, fetchClauses)
|
||||
}
|
||||
|
||||
/**
|
||||
Fetches the number of `NSManagedObject`'s that satisfy the specified `FetchClause`s. Accepts `Where`, `OrderBy`, and `Tweak` clauses.
|
||||
|
||||
:param: from a `From` clause indicating the entity type
|
||||
:param: fetchClauses a series of `FetchClause` instances for the fetch request. Accepts `Where`, `OrderBy`, and `Tweak` clauses.
|
||||
:returns: the number `NSManagedObject`'s that satisfy the specified `FetchClause`s
|
||||
*/
|
||||
public func fetchCount<T: NSManagedObject>(from: From<T>, _ fetchClauses: [FetchClause]) -> Int? {
|
||||
|
||||
CoreStore.assert(NSThread.isMainThread(), "Attempted to fetch from a \(typeName(self)) outside the main thread.")
|
||||
|
||||
return self.mainContext.fetchCount(from, fetchClauses)
|
||||
}
|
||||
|
||||
/**
|
||||
Fetches the `NSManagedObjectID` for the first `NSManagedObject` that satisfies the specified `FetchClause`s. Accepts `Where`, `OrderBy`, and `Tweak` clauses.
|
||||
|
||||
:param: from a `From` clause indicating the entity type
|
||||
:param: fetchClauses a series of `FetchClause` instances for the fetch request. Accepts `Where`, `OrderBy`, and `Tweak` clauses.
|
||||
:returns: the `NSManagedObjectID` for the first `NSManagedObject` that satisfies the specified `FetchClause`s
|
||||
*/
|
||||
public func fetchObjectID<T: NSManagedObject>(from: From<T>, _ fetchClauses: FetchClause...) -> NSManagedObjectID? {
|
||||
|
||||
CoreStore.assert(NSThread.isMainThread(), "Attempted to fetch from a \(typeName(self)) outside the main thread.")
|
||||
|
||||
return self.mainContext.fetchObjectID(from, fetchClauses)
|
||||
}
|
||||
|
||||
/**
|
||||
Fetches the `NSManagedObjectID` for the first `NSManagedObject` that satisfies the specified `FetchClause`s. Accepts `Where`, `OrderBy`, and `Tweak` clauses.
|
||||
|
||||
:param: from a `From` clause indicating the entity type
|
||||
:param: fetchClauses a series of `FetchClause` instances for the fetch request. Accepts `Where`, `OrderBy`, and `Tweak` clauses.
|
||||
:returns: the `NSManagedObjectID` for the first `NSManagedObject` that satisfies the specified `FetchClause`s
|
||||
*/
|
||||
public func fetchObjectID<T: NSManagedObject>(from: From<T>, _ fetchClauses: [FetchClause]) -> NSManagedObjectID? {
|
||||
|
||||
CoreStore.assert(NSThread.isMainThread(), "Attempted to fetch from a \(typeName(self)) outside the main thread.")
|
||||
|
||||
return self.mainContext.fetchObjectID(from, fetchClauses)
|
||||
}
|
||||
|
||||
/**
|
||||
Fetches the `NSManagedObjectID` for all `NSManagedObject`'s that satisfy the specified `FetchClause`s. Accepts `Where`, `OrderBy`, and `Tweak` clauses.
|
||||
|
||||
:param: from a `From` clause indicating the entity type
|
||||
:param: fetchClauses a series of `FetchClause` instances for the fetch request. Accepts `Where`, `OrderBy`, and `Tweak` clauses.
|
||||
:returns: the `NSManagedObjectID` for all `NSManagedObject`'s that satisfy the specified `FetchClause`s
|
||||
*/
|
||||
public func fetchObjectIDs<T: NSManagedObject>(from: From<T>, _ fetchClauses: FetchClause...) -> [NSManagedObjectID]? {
|
||||
|
||||
CoreStore.assert(NSThread.isMainThread(), "Attempted to fetch from a \(typeName(self)) outside the main thread.")
|
||||
|
||||
return self.mainContext.fetchObjectIDs(from, fetchClauses)
|
||||
}
|
||||
|
||||
/**
|
||||
Fetches the `NSManagedObjectID` for all `NSManagedObject`'s that satisfy the specified `FetchClause`s. Accepts `Where`, `OrderBy`, and `Tweak` clauses.
|
||||
|
||||
:param: from a `From` clause indicating the entity type
|
||||
:param: fetchClauses a series of `FetchClause` instances for the fetch request. Accepts `Where`, `OrderBy`, and `Tweak` clauses.
|
||||
:returns: the `NSManagedObjectID` for all `NSManagedObject`'s that satisfy the specified `FetchClause`s
|
||||
*/
|
||||
public func fetchObjectIDs<T: NSManagedObject>(from: From<T>, _ fetchClauses: [FetchClause]) -> [NSManagedObjectID]? {
|
||||
|
||||
CoreStore.assert(NSThread.isMainThread(), "Attempted to fetch from a \(typeName(self)) outside the main thread.")
|
||||
|
||||
return self.mainContext.fetchObjectIDs(from, fetchClauses)
|
||||
}
|
||||
|
||||
/**
|
||||
Queries aggregate values as specified by the `QueryClause`'s. Requires at least a `Select` clause, and optional `Where`, `OrderBy`, `GroupBy`, and `Tweak` clauses.
|
||||
|
||||
A "query" differs from a "fetch" in that it only retrieves values already stored in the persistent store. As such, values from unsaved transactions or contexts will not be incorporated in the query result.
|
||||
|
||||
:param: from a `From` clause indicating the entity type
|
||||
:param: selectClause a `Select<U>` clause indicating the properties to fetch, and with the generic type indicating the return type.
|
||||
:param: queryClauses a series of `QueryClause` instances for the query request. Accepts `Where`, `OrderBy`, `GroupBy`, and `Tweak` clauses.
|
||||
:returns: the result of the the query. The type of the return value is specified by the generic type of the `Select<U>` parameter.
|
||||
*/
|
||||
public func queryValue<T: NSManagedObject, U: SelectValueResultType>(from: From<T>, _ selectClause: Select<U>, _ queryClauses: QueryClause...) -> U? {
|
||||
|
||||
CoreStore.assert(NSThread.isMainThread(), "Attempted to query from a \(typeName(self)) outside the main thread.")
|
||||
|
||||
return self.mainContext.queryValue(from, selectClause, queryClauses)
|
||||
}
|
||||
|
||||
/**
|
||||
Queries aggregate values as specified by the `QueryClause`'s. Requires at least a `Select` clause, and optional `Where`, `OrderBy`, `GroupBy`, and `Tweak` clauses.
|
||||
|
||||
A "query" differs from a "fetch" in that it only retrieves values already stored in the persistent store. As such, values from unsaved transactions or contexts will not be incorporated in the query result.
|
||||
|
||||
:param: from a `From` clause indicating the entity type
|
||||
:param: selectClause a `Select<U>` clause indicating the properties to fetch, and with the generic type indicating the return type.
|
||||
:param: queryClauses a series of `QueryClause` instances for the query request. Accepts `Where`, `OrderBy`, `GroupBy`, and `Tweak` clauses.
|
||||
:returns: the result of the the query. The type of the return value is specified by the generic type of the `Select<U>` parameter.
|
||||
*/
|
||||
public func queryValue<T: NSManagedObject, U: SelectValueResultType>(from: From<T>, _ selectClause: Select<U>, _ queryClauses: [QueryClause]) -> U? {
|
||||
|
||||
CoreStore.assert(NSThread.isMainThread(), "Attempted to query from a \(typeName(self)) outside the main thread.")
|
||||
|
||||
return self.mainContext.queryValue(from, selectClause, queryClauses)
|
||||
}
|
||||
|
||||
/**
|
||||
Queries a dictionary of attribute values as specified by the `QueryClause`'s. Requires at least a `Select` clause, and optional `Where`, `OrderBy`, `GroupBy`, and `Tweak` clauses.
|
||||
|
||||
A "query" differs from a "fetch" in that it only retrieves values already stored in the persistent store. As such, values from unsaved transactions or contexts will not be incorporated in the query result.
|
||||
|
||||
:param: from a `From` clause indicating the entity type
|
||||
:param: selectClause a `Select<U>` clause indicating the properties to fetch, and with the generic type indicating the return type.
|
||||
:param: queryClauses a series of `QueryClause` instances for the query request. Accepts `Where`, `OrderBy`, `GroupBy`, and `Tweak` clauses.
|
||||
:returns: the result of the the query. The type of the return value is specified by the generic type of the `Select<U>` parameter.
|
||||
*/
|
||||
public func queryAttributes<T: NSManagedObject>(from: From<T>, _ selectClause: Select<NSDictionary>, _ queryClauses: QueryClause...) -> [[NSString: AnyObject]]? {
|
||||
|
||||
CoreStore.assert(NSThread.isMainThread(), "Attempted to query from a \(typeName(self)) outside the main thread.")
|
||||
|
||||
return self.mainContext.queryAttributes(from, selectClause, queryClauses)
|
||||
}
|
||||
|
||||
/**
|
||||
Queries a dictionary of attribute values as specified by the `QueryClause`'s. Requires at least a `Select` clause, and optional `Where`, `OrderBy`, `GroupBy`, and `Tweak` clauses.
|
||||
|
||||
A "query" differs from a "fetch" in that it only retrieves values already stored in the persistent store. As such, values from unsaved transactions or contexts will not be incorporated in the query result.
|
||||
|
||||
:param: from a `From` clause indicating the entity type
|
||||
:param: selectClause a `Select<U>` clause indicating the properties to fetch, and with the generic type indicating the return type.
|
||||
:param: queryClauses a series of `QueryClause` instances for the query request. Accepts `Where`, `OrderBy`, `GroupBy`, and `Tweak` clauses.
|
||||
:returns: the result of the the query. The type of the return value is specified by the generic type of the `Select<U>` parameter.
|
||||
*/
|
||||
public func queryAttributes<T: NSManagedObject>(from: From<T>, _ selectClause: Select<NSDictionary>, _ queryClauses: [QueryClause]) -> [[NSString: AnyObject]]? {
|
||||
|
||||
CoreStore.assert(NSThread.isMainThread(), "Attempted to query from a \(typeName(self)) outside the main thread.")
|
||||
|
||||
return self.mainContext.queryAttributes(from, selectClause, queryClauses)
|
||||
}
|
||||
}
|
||||
@@ -1,68 +0,0 @@
|
||||
//
|
||||
// NSObject+CoreStore.swift
|
||||
// CoreStore
|
||||
//
|
||||
// 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
|
||||
|
||||
internal func getAssociatedObjectForKey<T: AnyObject>(key: UnsafePointer<Void>, inObject object: AnyObject) -> T? {
|
||||
|
||||
switch objc_getAssociatedObject(object, key) {
|
||||
|
||||
case let associatedObject as T:
|
||||
return associatedObject
|
||||
|
||||
case let associatedObject as WeakObject:
|
||||
return associatedObject.object as? T
|
||||
|
||||
default:
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
internal func setAssociatedRetainedObject<T: AnyObject>(associatedObject: T?, forKey key: UnsafePointer<Void>, inObject object: AnyObject) {
|
||||
|
||||
objc_setAssociatedObject(object, key, associatedObject, UInt(OBJC_ASSOCIATION_RETAIN_NONATOMIC))
|
||||
}
|
||||
|
||||
internal func setAssociatedCopiedObject<T: AnyObject>(associatedObject: T?, forKey key: UnsafePointer<Void>, inObject object: AnyObject) {
|
||||
|
||||
objc_setAssociatedObject(object, key, associatedObject, UInt(OBJC_ASSOCIATION_COPY_NONATOMIC))
|
||||
}
|
||||
|
||||
internal func setAssociatedAssignedObject<T: AnyObject>(associatedObject: T?, forKey key: UnsafePointer<Void>, inObject object: AnyObject) {
|
||||
|
||||
objc_setAssociatedObject(object, key, associatedObject, UInt(OBJC_ASSOCIATION_ASSIGN))
|
||||
}
|
||||
|
||||
internal func setAssociatedWeakObject<T: AnyObject>(associatedObject: T?, forKey key: UnsafePointer<Void>, inObject object: AnyObject) {
|
||||
|
||||
if let associatedObject = associatedObject {
|
||||
|
||||
objc_setAssociatedObject(object, key, WeakObject(associatedObject), UInt(OBJC_ASSOCIATION_RETAIN_NONATOMIC))
|
||||
}
|
||||
else {
|
||||
|
||||
objc_setAssociatedObject(object, key, nil, UInt(OBJC_ASSOCIATION_RETAIN_NONATOMIC))
|
||||
}
|
||||
}
|
||||
@@ -1,106 +0,0 @@
|
||||
//
|
||||
// NSManagedObject+Transaction.swift
|
||||
// CoreStore
|
||||
//
|
||||
// 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
|
||||
|
||||
|
||||
// MARK: - NSManagedObject
|
||||
|
||||
internal extension NSManagedObject {
|
||||
|
||||
// MARK: Internal
|
||||
|
||||
internal class func createInContext(context: NSManagedObjectContext) -> Self {
|
||||
|
||||
return self(
|
||||
entity: context.entityDescriptionForEntityClass(self)!,
|
||||
insertIntoManagedObjectContext: context
|
||||
)
|
||||
}
|
||||
|
||||
internal class func inContext(context: NSManagedObjectContext, withObjectID objectID: NSManagedObjectID) -> Self? {
|
||||
|
||||
return self.typedObjectInContext(context, objectID: objectID)
|
||||
}
|
||||
|
||||
internal func inContext(context: NSManagedObjectContext) -> Self? {
|
||||
|
||||
return self.typedObjectInContext(context)
|
||||
}
|
||||
|
||||
internal func deleteFromContext() {
|
||||
|
||||
self.managedObjectContext?.deleteObject(self)
|
||||
}
|
||||
|
||||
|
||||
// MARK: Private
|
||||
|
||||
private class func typedObjectInContext<T: NSManagedObject>(context: NSManagedObjectContext, objectID: NSManagedObjectID) -> T? {
|
||||
|
||||
var error: NSError?
|
||||
if let existingObject = context.existingObjectWithID(objectID, error: &error) {
|
||||
|
||||
return (existingObject as! T)
|
||||
}
|
||||
|
||||
CoreStore.handleError(
|
||||
error ?? NSError(coreStoreErrorCode: .UnknownError),
|
||||
"Failed to load existing \(typeName(self)) in context.")
|
||||
return nil;
|
||||
}
|
||||
|
||||
private func typedObjectInContext<T: NSManagedObject>(context: NSManagedObjectContext) -> T? {
|
||||
|
||||
let objectID = self.objectID
|
||||
if objectID.temporaryID {
|
||||
|
||||
var error: NSError?
|
||||
let didSucceed = withExtendedLifetime(self.managedObjectContext) {
|
||||
|
||||
return $0?.obtainPermanentIDsForObjects([self], error: &error)
|
||||
}
|
||||
if didSucceed != true {
|
||||
|
||||
CoreStore.handleError(
|
||||
error ?? NSError(coreStoreErrorCode: .UnknownError),
|
||||
"Failed to obtain permanent ID for object.")
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
var error: NSError?
|
||||
if let existingObject = context.existingObjectWithID(objectID, error: &error) {
|
||||
|
||||
return (existingObject as! T)
|
||||
}
|
||||
|
||||
CoreStore.handleError(
|
||||
error ?? NSError(coreStoreErrorCode: .UnknownError),
|
||||
"Failed to load existing \(typeName(self)) in context.")
|
||||
return nil;
|
||||
}
|
||||
}
|
||||
@@ -1,330 +0,0 @@
|
||||
//
|
||||
// NSManagedObjectContext+Querying.swift
|
||||
// CoreStore
|
||||
//
|
||||
// Copyright (c) 2015 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
|
||||
|
||||
|
||||
// MARK: - NSManagedObjectContext
|
||||
|
||||
internal extension NSManagedObjectContext {
|
||||
|
||||
// MARK: Public
|
||||
|
||||
internal func fetchOne<T: NSManagedObject>(from: From<T>, _ fetchClauses: FetchClause...) -> T? {
|
||||
|
||||
return self.fetchOne(from, fetchClauses)
|
||||
}
|
||||
|
||||
internal func fetchOne<T: NSManagedObject>(from: From<T>, _ fetchClauses: [FetchClause]) -> T? {
|
||||
|
||||
let fetchRequest = NSFetchRequest()
|
||||
from.applyToFetchRequest(fetchRequest, context: self)
|
||||
|
||||
fetchRequest.fetchLimit = 1
|
||||
fetchRequest.resultType = .ManagedObjectResultType
|
||||
|
||||
for clause in fetchClauses {
|
||||
|
||||
clause.applyToFetchRequest(fetchRequest)
|
||||
}
|
||||
|
||||
var fetchResults: [T]?
|
||||
var error: NSError?
|
||||
self.performBlockAndWait {
|
||||
|
||||
fetchResults = self.executeFetchRequest(fetchRequest, error: &error) as? [T]
|
||||
}
|
||||
if fetchResults == nil {
|
||||
|
||||
CoreStore.handleError(
|
||||
error ?? NSError(coreStoreErrorCode: .UnknownError),
|
||||
"Failed executing fetch request.")
|
||||
return nil
|
||||
}
|
||||
|
||||
return fetchResults?.first
|
||||
}
|
||||
|
||||
internal func fetchAll<T: NSManagedObject>(from: From<T>, _ fetchClauses: FetchClause...) -> [T]? {
|
||||
|
||||
return self.fetchAll(from, fetchClauses)
|
||||
}
|
||||
|
||||
internal func fetchAll<T: NSManagedObject>(from: From<T>, _ fetchClauses: [FetchClause]) -> [T]? {
|
||||
|
||||
let fetchRequest = NSFetchRequest()
|
||||
from.applyToFetchRequest(fetchRequest, context: self)
|
||||
|
||||
fetchRequest.fetchLimit = 0
|
||||
fetchRequest.resultType = .ManagedObjectResultType
|
||||
|
||||
for clause in fetchClauses {
|
||||
|
||||
clause.applyToFetchRequest(fetchRequest)
|
||||
}
|
||||
|
||||
var fetchResults: [T]?
|
||||
var error: NSError?
|
||||
self.performBlockAndWait {
|
||||
|
||||
fetchResults = self.executeFetchRequest(fetchRequest, error: &error) as? [T]
|
||||
}
|
||||
if fetchResults == nil {
|
||||
|
||||
CoreStore.handleError(
|
||||
error ?? NSError(coreStoreErrorCode: .UnknownError),
|
||||
"Failed executing fetch request.")
|
||||
return nil
|
||||
}
|
||||
|
||||
return fetchResults
|
||||
}
|
||||
|
||||
internal func fetchCount<T: NSManagedObject>(from: From<T>, _ fetchClauses: FetchClause...) -> Int? {
|
||||
|
||||
return self.fetchCount(from, fetchClauses)
|
||||
}
|
||||
|
||||
internal func fetchCount<T: NSManagedObject>(from: From<T>, _ fetchClauses: [FetchClause]) -> Int? {
|
||||
|
||||
let fetchRequest = NSFetchRequest()
|
||||
from.applyToFetchRequest(fetchRequest, context: self)
|
||||
|
||||
for clause in fetchClauses {
|
||||
|
||||
clause.applyToFetchRequest(fetchRequest)
|
||||
}
|
||||
|
||||
var count = 0
|
||||
var error: NSError?
|
||||
self.performBlockAndWait {
|
||||
|
||||
count = self.countForFetchRequest(fetchRequest, error: &error)
|
||||
}
|
||||
if count == NSNotFound {
|
||||
|
||||
CoreStore.handleError(
|
||||
error ?? NSError(coreStoreErrorCode: .UnknownError),
|
||||
"Failed executing fetch request.")
|
||||
return nil
|
||||
}
|
||||
|
||||
return count
|
||||
}
|
||||
|
||||
internal func fetchObjectID<T: NSManagedObject>(from: From<T>, _ fetchClauses: FetchClause...) -> NSManagedObjectID? {
|
||||
|
||||
return self.fetchObjectID(from, fetchClauses)
|
||||
}
|
||||
|
||||
internal func fetchObjectID<T: NSManagedObject>(from: From<T>, _ fetchClauses: [FetchClause]) -> NSManagedObjectID? {
|
||||
|
||||
let fetchRequest = NSFetchRequest()
|
||||
from.applyToFetchRequest(fetchRequest, context: self)
|
||||
|
||||
fetchRequest.fetchLimit = 1
|
||||
fetchRequest.resultType = .ManagedObjectIDResultType
|
||||
|
||||
for clause in fetchClauses {
|
||||
|
||||
clause.applyToFetchRequest(fetchRequest)
|
||||
}
|
||||
|
||||
var fetchResults: [NSManagedObjectID]?
|
||||
var error: NSError?
|
||||
self.performBlockAndWait {
|
||||
|
||||
fetchResults = self.executeFetchRequest(fetchRequest, error: &error) as? [NSManagedObjectID]
|
||||
}
|
||||
if fetchResults == nil {
|
||||
|
||||
CoreStore.handleError(
|
||||
error ?? NSError(coreStoreErrorCode: .UnknownError),
|
||||
"Failed executing fetch request.")
|
||||
return nil
|
||||
}
|
||||
|
||||
return fetchResults?.first
|
||||
}
|
||||
|
||||
internal func fetchObjectIDs<T: NSManagedObject>(from: From<T>, _ fetchClauses: FetchClause...) -> [NSManagedObjectID]? {
|
||||
|
||||
return self.fetchObjectIDs(from, fetchClauses)
|
||||
}
|
||||
|
||||
internal func fetchObjectIDs<T: NSManagedObject>(from: From<T>, _ fetchClauses: [FetchClause]) -> [NSManagedObjectID]? {
|
||||
|
||||
let fetchRequest = NSFetchRequest()
|
||||
from.applyToFetchRequest(fetchRequest, context: self)
|
||||
|
||||
fetchRequest.fetchLimit = 0
|
||||
fetchRequest.resultType = .ManagedObjectIDResultType
|
||||
|
||||
for clause in fetchClauses {
|
||||
|
||||
clause.applyToFetchRequest(fetchRequest)
|
||||
}
|
||||
|
||||
var fetchResults: [NSManagedObjectID]?
|
||||
var error: NSError?
|
||||
self.performBlockAndWait {
|
||||
|
||||
fetchResults = self.executeFetchRequest(fetchRequest, error: &error) as? [NSManagedObjectID]
|
||||
}
|
||||
if fetchResults == nil {
|
||||
|
||||
CoreStore.handleError(
|
||||
error ?? NSError(coreStoreErrorCode: .UnknownError),
|
||||
"Failed executing fetch request.")
|
||||
return nil
|
||||
}
|
||||
|
||||
return fetchResults
|
||||
}
|
||||
|
||||
internal func deleteAll<T: NSManagedObject>(from: From<T>, _ deleteClauses: DeleteClause...) -> Int? {
|
||||
|
||||
return self.deleteAll(from, deleteClauses)
|
||||
}
|
||||
|
||||
internal func deleteAll<T: NSManagedObject>(from: From<T>, _ deleteClauses: [DeleteClause]) -> Int? {
|
||||
|
||||
let fetchRequest = NSFetchRequest()
|
||||
from.applyToFetchRequest(fetchRequest, context: self)
|
||||
|
||||
fetchRequest.fetchLimit = 0
|
||||
fetchRequest.resultType = .ManagedObjectResultType
|
||||
fetchRequest.returnsObjectsAsFaults = true
|
||||
|
||||
for clause in deleteClauses {
|
||||
|
||||
clause.applyToFetchRequest(fetchRequest)
|
||||
}
|
||||
|
||||
var numberOfDeletedObjects: Int?
|
||||
var error: NSError?
|
||||
self.performBlockAndWait {
|
||||
|
||||
autoreleasepool {
|
||||
|
||||
if let fetchResults = self.executeFetchRequest(fetchRequest, error: &error) as? [T] {
|
||||
|
||||
numberOfDeletedObjects = fetchResults.count
|
||||
for object in fetchResults {
|
||||
|
||||
self.deleteObject(object)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if numberOfDeletedObjects == nil {
|
||||
|
||||
CoreStore.handleError(
|
||||
error ?? NSError(coreStoreErrorCode: .UnknownError),
|
||||
"Failed executing fetch request.")
|
||||
return nil
|
||||
}
|
||||
|
||||
return numberOfDeletedObjects
|
||||
}
|
||||
|
||||
internal func queryValue<T: NSManagedObject, U: SelectValueResultType>(from: From<T>, _ selectClause: Select<U>, _ queryClauses: QueryClause...) -> U? {
|
||||
|
||||
return self.queryValue(from, selectClause, queryClauses)
|
||||
}
|
||||
|
||||
internal func queryValue<T: NSManagedObject, U: SelectValueResultType>(from: From<T>, _ selectClause: Select<U>, _ queryClauses: [QueryClause]) -> U? {
|
||||
|
||||
let fetchRequest = NSFetchRequest()
|
||||
from.applyToFetchRequest(fetchRequest, context: self)
|
||||
|
||||
fetchRequest.fetchLimit = 0
|
||||
|
||||
selectClause.applyToFetchRequest(fetchRequest)
|
||||
|
||||
for clause in queryClauses {
|
||||
|
||||
clause.applyToFetchRequest(fetchRequest)
|
||||
}
|
||||
|
||||
var fetchResults: [AnyObject]?
|
||||
var error: NSError?
|
||||
self.performBlockAndWait {
|
||||
|
||||
fetchResults = self.executeFetchRequest(fetchRequest, error: &error)
|
||||
}
|
||||
if let fetchResults = fetchResults {
|
||||
|
||||
if let rawResult = fetchResults.first as? NSDictionary,
|
||||
let rawObject: AnyObject = rawResult[selectClause.keyPathForFirstSelectTerm()] {
|
||||
|
||||
return Select<U>.ReturnType.fromResultObject(rawObject)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
CoreStore.handleError(
|
||||
error ?? NSError(coreStoreErrorCode: .UnknownError),
|
||||
"Failed executing fetch request.")
|
||||
return nil
|
||||
}
|
||||
|
||||
internal func queryAttributes<T: NSManagedObject>(from: From<T>, _ selectClause: Select<NSDictionary>, _ queryClauses: QueryClause...) -> [[NSString: AnyObject]]? {
|
||||
|
||||
return self.queryAttributes(from, selectClause, queryClauses)
|
||||
}
|
||||
|
||||
internal func queryAttributes<T: NSManagedObject>(from: From<T>, _ selectClause: Select<NSDictionary>, _ queryClauses: [QueryClause]) -> [[NSString: AnyObject]]? {
|
||||
|
||||
let fetchRequest = NSFetchRequest()
|
||||
from.applyToFetchRequest(fetchRequest, context: self)
|
||||
|
||||
fetchRequest.fetchLimit = 0
|
||||
|
||||
selectClause.applyToFetchRequest(fetchRequest)
|
||||
|
||||
for clause in queryClauses {
|
||||
|
||||
clause.applyToFetchRequest(fetchRequest)
|
||||
}
|
||||
|
||||
var fetchResults: [AnyObject]?
|
||||
var error: NSError?
|
||||
self.performBlockAndWait {
|
||||
|
||||
fetchResults = self.executeFetchRequest(fetchRequest, error: &error)
|
||||
}
|
||||
if let fetchResults = fetchResults {
|
||||
|
||||
return Select<NSDictionary>.ReturnType.fromResultObjects(fetchResults)
|
||||
}
|
||||
|
||||
CoreStore.handleError(
|
||||
error ?? NSError(coreStoreErrorCode: .UnknownError),
|
||||
"Failed executing fetch request.")
|
||||
return nil
|
||||
}
|
||||
}
|
||||
@@ -1,90 +0,0 @@
|
||||
//
|
||||
// CoreStoreLogger.swift
|
||||
// CoreStore
|
||||
//
|
||||
// Copyright (c) 2015 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
|
||||
|
||||
|
||||
// MARK: - LogLevel
|
||||
|
||||
/**
|
||||
The `LogLevel` indicates the severity of a log message.
|
||||
*/
|
||||
public enum LogLevel {
|
||||
|
||||
case Trace
|
||||
case Notice
|
||||
case Warning
|
||||
case Fatal
|
||||
}
|
||||
|
||||
|
||||
// MARK: - CoreStoreLogger
|
||||
|
||||
/**
|
||||
Custom loggers should implement the `CoreStoreLogger` protocol and pass its instance to `CoreStore.logger`. Calls to `log(...)`, `handleError(...)`, and `assert(...)` are not tied to a specific queue/thread, so it is the implementer's job to handle thread-safety.
|
||||
*/
|
||||
public protocol CoreStoreLogger {
|
||||
|
||||
/**
|
||||
Handles log messages sent by the `CoreStore` framework.
|
||||
|
||||
:level: the severity of the log message
|
||||
:message: the log message
|
||||
:fileName: the source file name
|
||||
:lineNumber: the source line number
|
||||
:functionName: the source function name
|
||||
*/
|
||||
func log(#level: LogLevel, message: String, fileName: StaticString, lineNumber: Int, functionName: StaticString)
|
||||
|
||||
/**
|
||||
Handles errors sent by the `CoreStore` framework.
|
||||
|
||||
:error: the error
|
||||
:message: the error message
|
||||
:fileName: the source file name
|
||||
:lineNumber: the source line number
|
||||
:functionName: the source function name
|
||||
*/
|
||||
func handleError(#error: NSError, message: String, fileName: StaticString, lineNumber: Int, functionName: StaticString)
|
||||
|
||||
/**
|
||||
Handles assertions made throughout the `CoreStore` framework.
|
||||
|
||||
:condition: the assertion condition
|
||||
:message: the assertion message
|
||||
:fileName: the source file name
|
||||
:lineNumber: the source line number
|
||||
:functionName: the source function name
|
||||
*/
|
||||
func assert(@autoclosure condition: () -> Bool, message: String, fileName: StaticString, lineNumber: Int, functionName: StaticString)
|
||||
}
|
||||
|
||||
|
||||
// MARK: - Utilities
|
||||
|
||||
internal func typeName<T>(value: T) -> String {
|
||||
|
||||
return "<\(_stdlib_getDemangledTypeName(value))>"
|
||||
}
|
||||
@@ -1,69 +0,0 @@
|
||||
//
|
||||
// DefaultLogger.swift
|
||||
// CoreStore
|
||||
//
|
||||
// Copyright (c) 2015 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
|
||||
|
||||
|
||||
// MARK: - DefaultLogger
|
||||
|
||||
/**
|
||||
The `DefaultLogger` is a basic implementation of the `CoreStoreLogger` protocol.
|
||||
|
||||
- The `log(...)` method calls `println(...)` to print the level, source file name, line number, function name, and the log message.
|
||||
- The `handleError(...)` method calls `println(...)` to print the source file name, line number, function name, and the error message.
|
||||
- The `assert(...)` method calls `assert(...)` on the arguments.
|
||||
*/
|
||||
public final class DefaultLogger: CoreStoreLogger {
|
||||
|
||||
public init() { }
|
||||
|
||||
public func log(#level: LogLevel, message: String, fileName: StaticString, lineNumber: Int, functionName: StaticString) {
|
||||
|
||||
#if DEBUG
|
||||
let levelString: String
|
||||
switch level {
|
||||
case .Trace: levelString = "Trace"
|
||||
case .Notice: levelString = "Notice"
|
||||
case .Warning: levelString = "Warning"
|
||||
case .Fatal: levelString = "Fatal"
|
||||
}
|
||||
Swift.println("[CoreStore:\(levelString)] \(fileName.stringValue.lastPathComponent):\(lineNumber) \(functionName)\n ↪︎ \(message)\n")
|
||||
#endif
|
||||
}
|
||||
|
||||
public func handleError(#error: NSError, message: String, fileName: StaticString, lineNumber: Int, functionName: StaticString) {
|
||||
|
||||
#if DEBUG
|
||||
Swift.println("[CoreStore:Error] \(fileName.stringValue.lastPathComponent):\(lineNumber) \(functionName)\n ↪︎ \(message): \(error)\n")
|
||||
#endif
|
||||
}
|
||||
|
||||
public func assert(@autoclosure condition: () -> Bool, message: String, fileName: StaticString, lineNumber: Int, functionName: StaticString) {
|
||||
|
||||
#if DEBUG
|
||||
Swift.assert(condition, message, file: fileName, line: numericCast(lineNumber))
|
||||
#endif
|
||||
}
|
||||
}
|
||||
@@ -1,357 +0,0 @@
|
||||
//
|
||||
// DataStack+Migration.swift
|
||||
// CoreStore
|
||||
//
|
||||
// Copyright (c) 2015 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
|
||||
|
||||
|
||||
// MARK: - DataStack
|
||||
|
||||
public extension DataStack {
|
||||
|
||||
// MARK: Public
|
||||
|
||||
/**
|
||||
Initializes a `DataStack` from the specified model name and a version-specific model name.
|
||||
|
||||
:param: rootModelName the name of the (.xcdatamodeld) model file
|
||||
:param: versionModelName the name of the version-specific (.xcdatamodeld) model file
|
||||
*/
|
||||
public convenience init(rootModelName: String, versionModelName: String) {
|
||||
|
||||
let modelVersionURL: NSURL! = NSBundle.mainBundle().URLForResource(
|
||||
rootModelName.stringByAppendingPathExtension("momd")!.stringByAppendingPathComponent(versionModelName),
|
||||
withExtension: "mom"
|
||||
)
|
||||
CoreStore.assert(modelVersionURL != nil, "Could not find a \"mom\" resource from the main bundle.")
|
||||
|
||||
let managedObjectModel: NSManagedObjectModel! = NSManagedObjectModel(contentsOfURL: modelVersionURL)
|
||||
CoreStore.assert(managedObjectModel != nil, "Could not create an <\(NSManagedObjectModel.self)> from the resource at URL \"\(modelVersionURL)\".")
|
||||
|
||||
self.init(managedObjectModel: managedObjectModel)
|
||||
}
|
||||
|
||||
/**
|
||||
Checks if the store at the specified filename and configuration needs to be migrated to the `DataStack`'s managed object model version.
|
||||
|
||||
:param: fileName the local filename for the SQLite persistent store in the "Application Support" directory.
|
||||
:param: configuration an optional configuration name from the model file. If not specified, defaults to `nil`, the "Default" configuration.
|
||||
*/
|
||||
public func needsMigrationForSQLiteStore(fileName: String, configuration: String? = nil) -> Bool? {
|
||||
|
||||
return needsMigrationForSQLiteStore(
|
||||
fileURL: applicationSupportDirectory.URLByAppendingPathComponent(
|
||||
fileName,
|
||||
isDirectory: false
|
||||
),
|
||||
configuration: configuration
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
Checks if the store at the specified file URL and configuration needs to be migrated to the `DataStack`'s managed object model version.
|
||||
|
||||
:param: fileName the local filename for the SQLite persistent store in the "Application Support" directory.
|
||||
:param: configuration an optional configuration name from the model file. If not specified, defaults to `nil`, the "Default" configuration.
|
||||
*/
|
||||
public func needsMigrationForSQLiteStore(fileURL: NSURL = defaultSQLiteStoreURL, configuration: String? = nil) -> Bool? {
|
||||
|
||||
var error: NSError?
|
||||
let metadata = NSPersistentStoreCoordinator.metadataForPersistentStoreOfType(
|
||||
NSSQLiteStoreType,
|
||||
URL: fileURL,
|
||||
error: &error
|
||||
)
|
||||
if metadata == nil {
|
||||
|
||||
CoreStore.handleError(
|
||||
error ?? NSError(coreStoreErrorCode: .UnknownError),
|
||||
"Failed to add SQLite <\(NSPersistentStore.self)> at \"\(fileURL)\".")
|
||||
return nil
|
||||
}
|
||||
|
||||
return !self.coordinator.managedObjectModel.isConfiguration(
|
||||
configuration,
|
||||
compatibleWithStoreMetadata: metadata
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
EXPERIMENTAL
|
||||
*/
|
||||
private func upgradeSQLiteStoreIfNeeded(fileName: String, configuration: String? = nil, completion: (PersistentStoreResult) -> Void) {
|
||||
|
||||
self.upgradeSQLiteStoreIfNeeded(
|
||||
fileURL: applicationSupportDirectory.URLByAppendingPathComponent(
|
||||
fileName,
|
||||
isDirectory: false
|
||||
),
|
||||
configuration: configuration,
|
||||
completion: completion
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
EXPERIMENTAL
|
||||
*/
|
||||
private func upgradeSQLiteStoreIfNeeded(fileURL: NSURL = defaultSQLiteStoreURL, configuration: String? = nil, completion: (PersistentStoreResult) -> Void) {
|
||||
|
||||
var metadataError: NSError?
|
||||
let metadata: [NSObject: AnyObject]! = NSPersistentStoreCoordinator.metadataForPersistentStoreOfType(
|
||||
NSSQLiteStoreType,
|
||||
URL: fileURL,
|
||||
error: &metadataError
|
||||
)
|
||||
if metadata == nil {
|
||||
|
||||
CoreStore.handleError(
|
||||
metadataError ?? NSError(coreStoreErrorCode: .UnknownError),
|
||||
"Failed to load SQLite <\(NSPersistentStore.self)> metadata at \"\(fileURL)\".")
|
||||
|
||||
GCDQueue.Main.async {
|
||||
|
||||
// TODO: inspect valid errors for metadataForPersistentStoreOfType()
|
||||
completion(PersistentStoreResult(.PersistentStoreNotFound))
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
let coordinator = self.coordinator;
|
||||
if let store = coordinator.persistentStoreForURL(fileURL) {
|
||||
|
||||
let isExistingStoreAutomigrating = ((store.options?[NSMigratePersistentStoresAutomaticallyOption] as? Bool) ?? false)
|
||||
|
||||
if store.type == NSSQLiteStoreType
|
||||
&& isExistingStoreAutomigrating
|
||||
&& store.configurationName == (configuration ?? Into.defaultConfigurationName) {
|
||||
|
||||
GCDQueue.Main.async {
|
||||
|
||||
completion(PersistentStoreResult(store))
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
CoreStore.handleError(
|
||||
NSError(coreStoreErrorCode: .DifferentPersistentStoreExistsAtURL),
|
||||
"Failed to add SQLite <\(NSPersistentStore.self)> at \"\(fileURL)\" because a different <\(NSPersistentStore.self)> at that URL already exists.")
|
||||
|
||||
GCDQueue.Main.async {
|
||||
|
||||
completion(PersistentStoreResult(.DifferentPersistentStoreExistsAtURL))
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
let managedObjectModel = self.coordinator.managedObjectModel
|
||||
let migrationManager = NSMigrationManager(
|
||||
sourceModel: NSManagedObjectModel(
|
||||
byMergingModels: [managedObjectModel],
|
||||
forStoreMetadata: metadata!
|
||||
)!,
|
||||
destinationModel: managedObjectModel
|
||||
)
|
||||
|
||||
var mappingModel: NSMappingModel! = NSMappingModel(
|
||||
fromBundles: nil, // TODO: parametize
|
||||
forSourceModel: migrationManager.sourceModel,
|
||||
destinationModel: migrationManager.destinationModel
|
||||
)
|
||||
var modelError: NSError?
|
||||
if mappingModel == nil {
|
||||
|
||||
mappingModel = NSMappingModel.inferredMappingModelForSourceModel(
|
||||
migrationManager.sourceModel,
|
||||
destinationModel: migrationManager.destinationModel,
|
||||
error: &modelError
|
||||
)
|
||||
}
|
||||
if mappingModel == nil {
|
||||
|
||||
CoreStore.handleError(
|
||||
NSError(coreStoreErrorCode: .UnknownError),
|
||||
"Failed to load an <\(NSMappingModel.self)> for migration from version model \"\(migrationManager.sourceModel)\" to version model \"\(migrationManager.destinationModel)\".")
|
||||
|
||||
GCDQueue.Main.async {
|
||||
|
||||
completion(PersistentStoreResult(.MappingModelNotFound))
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
let temporaryFileURL = NSURL(fileURLWithPath: NSTemporaryDirectory(), isDirectory: true)!.URLByAppendingPathComponent(NSProcessInfo().globallyUniqueString)
|
||||
|
||||
var migrationError: NSError?
|
||||
if !migrationManager.migrateStoreFromURL(
|
||||
fileURL,
|
||||
type: NSSQLiteStoreType,
|
||||
options: nil,
|
||||
withMappingModel: mappingModel,
|
||||
toDestinationURL: temporaryFileURL,
|
||||
destinationType: NSSQLiteStoreType,
|
||||
destinationOptions: nil,
|
||||
error: &migrationError
|
||||
) {
|
||||
|
||||
CoreStore.handleError(
|
||||
migrationError ?? NSError(coreStoreErrorCode: .UnknownError),
|
||||
"Failed to prepare for migration from version model \"\(migrationManager.sourceModel)\" to version model \"\(migrationManager.destinationModel)\".")
|
||||
|
||||
GCDQueue.Main.async {
|
||||
|
||||
completion(PersistentStoreResult(.MigrationFailed))
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
Asynchronously adds to the stack an SQLite store from the given SQLite file name. Note that using `addSQLiteStore(...)` instead of `addSQLiteStoreAndWait(...)` implies that the migrations are allowed and expected (thus the asynchronous `completion`.)
|
||||
|
||||
: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. Note that if you have multiple configurations, you will need to specify a different `fileName` explicitly for each of them.
|
||||
:param: configuration an optional configuration name from the model file. If not specified, defaults to `nil`, the "Default" configuration. Note that if you have multiple configurations, you will need to specify a different `fileName` explicitly for each of them.
|
||||
:param: completion the closure to be executed on the main queue when the process completes, either due to success or failure. The closure's `PersistentStoreResult` argument indicates the result.
|
||||
*/
|
||||
public func addSQLiteStore(fileName: String, configuration: String? = nil, completion: (PersistentStoreResult) -> Void) {
|
||||
|
||||
self.addSQLiteStore(
|
||||
fileURL: applicationSupportDirectory.URLByAppendingPathComponent(
|
||||
fileName,
|
||||
isDirectory: false
|
||||
),
|
||||
configuration: configuration,
|
||||
completion: completion
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
Asynchronously adds to the stack an SQLite store from the given SQLite file URL. Note that using `addSQLiteStore(...)` instead of `addSQLiteStoreAndWait(...)` implies that the migrations are allowed and expected (thus the asynchronous `completion`.)
|
||||
|
||||
: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. Note that if you have multiple configurations, you will need to specify a different `fileURL` explicitly for each of them.
|
||||
:param: configuration an optional configuration name from the model file. If not specified, defaults to `nil`, the "Default" configuration. Note that if you have multiple configurations, you will need to specify a different `fileURL` explicitly for each of them.
|
||||
:param: completion the closure to be executed on the main queue when the process completes, either due to success or failure. The closure's `PersistentStoreResult` argument indicates the result.
|
||||
*/
|
||||
public func addSQLiteStore(fileURL: NSURL = defaultSQLiteStoreURL, configuration: String? = nil, completion: (PersistentStoreResult) -> Void) {
|
||||
|
||||
var error: NSError?
|
||||
let metadata = NSPersistentStoreCoordinator.metadataForPersistentStoreOfType(
|
||||
NSSQLiteStoreType,
|
||||
URL: fileURL,
|
||||
error: &error
|
||||
)
|
||||
if metadata == nil {
|
||||
|
||||
CoreStore.handleError(
|
||||
error ?? NSError(coreStoreErrorCode: .UnknownError),
|
||||
"Failed to load SQLite <\(NSPersistentStore.self)> metadata at \"\(fileURL)\".")
|
||||
|
||||
GCDQueue.Main.async {
|
||||
|
||||
completion(PersistentStoreResult(.UnknownError))
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
let coordinator = self.coordinator;
|
||||
if let store = coordinator.persistentStoreForURL(fileURL) {
|
||||
|
||||
let isExistingStoreAutomigrating = ((store.options?[NSMigratePersistentStoresAutomaticallyOption] as? Bool) ?? false)
|
||||
|
||||
if store.type == NSSQLiteStoreType
|
||||
&& isExistingStoreAutomigrating
|
||||
&& store.configurationName == (configuration ?? Into.defaultConfigurationName) {
|
||||
|
||||
GCDQueue.Main.async {
|
||||
|
||||
completion(PersistentStoreResult(store))
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
CoreStore.handleError(
|
||||
NSError(coreStoreErrorCode: .DifferentPersistentStoreExistsAtURL),
|
||||
"Failed to add SQLite <\(NSPersistentStore.self)> at \"\(fileURL)\" because a different <\(NSPersistentStore.self)> at that URL already exists.")
|
||||
|
||||
GCDQueue.Main.async {
|
||||
|
||||
completion(PersistentStoreResult(.DifferentPersistentStoreExistsAtURL))
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
let fileManager = NSFileManager.defaultManager()
|
||||
var directoryError: NSError?
|
||||
if !fileManager.createDirectoryAtURL(
|
||||
fileURL.URLByDeletingLastPathComponent!,
|
||||
withIntermediateDirectories: true,
|
||||
attributes: nil,
|
||||
error: &directoryError) {
|
||||
|
||||
CoreStore.handleError(
|
||||
directoryError ?? NSError(coreStoreErrorCode: .UnknownError),
|
||||
"Failed to create directory for SQLite store at \"\(fileURL)\".")
|
||||
GCDQueue.Main.async {
|
||||
|
||||
completion(PersistentStoreResult(directoryError!))
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
coordinator.performBlock {
|
||||
|
||||
var persistentStoreError: NSError?
|
||||
let store = coordinator.addPersistentStoreWithType(
|
||||
NSSQLiteStoreType,
|
||||
configuration: configuration,
|
||||
URL: fileURL,
|
||||
options: [NSSQLitePragmasOption: ["WAL": "journal_mode"],
|
||||
NSInferMappingModelAutomaticallyOption: true,
|
||||
NSMigratePersistentStoresAutomaticallyOption: true],
|
||||
error: &persistentStoreError)
|
||||
|
||||
if let store = store {
|
||||
|
||||
GCDQueue.Main.async {
|
||||
|
||||
self.updateMetadataForPersistentStore(store)
|
||||
completion(PersistentStoreResult(store))
|
||||
}
|
||||
}
|
||||
else {
|
||||
|
||||
GCDQueue.Main.async {
|
||||
|
||||
CoreStore.handleError(
|
||||
persistentStoreError ?? NSError(coreStoreErrorCode: .UnknownError),
|
||||
"Failed to add SQLite <\(NSPersistentStore.self)> at \"\(fileURL)\".")
|
||||
|
||||
completion(PersistentStoreResult(.UnknownError))
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,94 +0,0 @@
|
||||
//
|
||||
// NSError+CoreStore.swift
|
||||
// CoreStore
|
||||
//
|
||||
// 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 `CoreStore`.
|
||||
*/
|
||||
public let CoreStoreErrorDomain = "com.corestore.error"
|
||||
|
||||
/**
|
||||
The `NSError` error codes for `CoreStoreErrorDomain`.
|
||||
*/
|
||||
public enum CoreStoreErrorCode: 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
|
||||
|
||||
/**
|
||||
The `NSPersistentStore` specified could not be found.
|
||||
*/
|
||||
case PersistentStoreNotFound
|
||||
|
||||
/**
|
||||
An `NSMappingModel` could not be found for a specific source and destination model versions.
|
||||
*/
|
||||
case MappingModelNotFound
|
||||
|
||||
/**
|
||||
An `NSMigrationManager` prepared to migrate the store.
|
||||
*/
|
||||
case MigrationFailed
|
||||
}
|
||||
|
||||
|
||||
// MARK: - NSError+CoreStore
|
||||
|
||||
public extension NSError {
|
||||
|
||||
/**
|
||||
If the error's domain is equal to `CoreStoreErrorDomain`, returns the associated `CoreStoreErrorCode`. For other domains, returns `nil`.
|
||||
*/
|
||||
public var coreStoreErrorCode: CoreStoreErrorCode? {
|
||||
|
||||
return (self.domain == CoreStoreErrorDomain
|
||||
? CoreStoreErrorCode(rawValue: self.code)
|
||||
: nil)
|
||||
}
|
||||
|
||||
|
||||
// MARK: Internal
|
||||
|
||||
internal convenience init(coreStoreErrorCode: CoreStoreErrorCode) {
|
||||
|
||||
self.init(coreStoreErrorCode: coreStoreErrorCode, userInfo: nil)
|
||||
}
|
||||
|
||||
internal convenience init(coreStoreErrorCode: CoreStoreErrorCode, userInfo: [NSObject: AnyObject]?) {
|
||||
|
||||
self.init(
|
||||
domain: CoreStoreErrorDomain,
|
||||
code: coreStoreErrorCode.rawValue,
|
||||
userInfo: userInfo)
|
||||
}
|
||||
}
|
||||
@@ -1,96 +0,0 @@
|
||||
//
|
||||
// CoreStore+Observing.swift
|
||||
// CoreStore
|
||||
//
|
||||
// Copyright (c) 2015 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
|
||||
|
||||
|
||||
// MARK: - CoreStore
|
||||
|
||||
public extension CoreStore {
|
||||
|
||||
// MARK: Public
|
||||
|
||||
/**
|
||||
Using the `defaultStack`, creates a `ManagedObjectController` for the specified `NSManagedObject`. Multiple `ManagedObjectObserver`'s may then register themselves to be notified when changes are made to the `NSManagedObject`.
|
||||
|
||||
:param: object the `NSManagedObject` to observe changes from
|
||||
:returns: a `ManagedObjectController` that monitors changes to `object`
|
||||
*/
|
||||
public static func observeObject<T: NSManagedObject>(object: T) -> ManagedObjectController<T> {
|
||||
|
||||
return self.defaultStack.observeObject(object)
|
||||
}
|
||||
|
||||
/**
|
||||
Using the `defaultStack`, creates a `ManagedObjectListController` for a list of `NSManagedObject`'s that satisfy the specified fetch clauses. Multiple `ManagedObjectListObserver`'s may then register themselves to be notified when changes are made to the list.
|
||||
|
||||
:param: from a `From` clause indicating the entity type
|
||||
:param: fetchClauses a series of `FetchClause` instances for fetching the object list. Accepts `Where`, `OrderBy`, and `Tweak` clauses.
|
||||
:returns: a `ManagedObjectListController` instance that monitors changes to the list
|
||||
*/
|
||||
public static func observeObjectList<T: NSManagedObject>(from: From<T>, _ groupBy: GroupBy? = nil, _ queryClauses: FetchClause...) -> ManagedObjectListController<T> {
|
||||
|
||||
return self.defaultStack.observeObjectList(from, queryClauses)
|
||||
}
|
||||
|
||||
/**
|
||||
Using the `defaultStack`, creates a `ManagedObjectListController` for a list of `NSManagedObject`'s that satisfy the specified fetch clauses. Multiple `ManagedObjectListObserver`'s may then register themselves to be notified when changes are made to the list.
|
||||
|
||||
:param: from a `From` clause indicating the entity type
|
||||
:param: fetchClauses a series of `FetchClause` instances for fetching the object list. Accepts `Where`, `OrderBy`, and `Tweak` clauses.
|
||||
:returns: a `ManagedObjectListController` instance that monitors changes to the list
|
||||
*/
|
||||
public static func observeObjectList<T: NSManagedObject>(from: From<T>, _ groupBy: GroupBy? = nil, _ queryClauses: [FetchClause]) -> ManagedObjectListController<T> {
|
||||
|
||||
return self.defaultStack.observeObjectList(from, queryClauses)
|
||||
}
|
||||
|
||||
/**
|
||||
Using the `defaultStack`, creates a `ManagedObjectListController` for a sectioned list of `NSManagedObject`'s that satisfy the specified fetch clauses. Multiple `ManagedObjectListObserver`'s may then register themselves to be notified when changes are made to the list.
|
||||
|
||||
:param: from a `From` clause indicating the entity type
|
||||
:param: sectionedBy a `SectionedBy` clause indicating the keyPath for the attribute to use when sorting the list into sections.
|
||||
:param: fetchClauses a series of `FetchClause` instances for fetching the object list. Accepts `Where`, `OrderBy`, and `Tweak` clauses.
|
||||
:returns: a `ManagedObjectListController` instance that monitors changes to the list
|
||||
*/
|
||||
public static func observeSectionedList<T: NSManagedObject>(from: From<T>, _ sectionedBy: SectionedBy, _ fetchClauses: FetchClause...) -> ManagedObjectListController<T> {
|
||||
|
||||
return self.defaultStack.observeSectionedList(from, sectionedBy, fetchClauses)
|
||||
}
|
||||
|
||||
/**
|
||||
Using the `defaultStack`, creates a `ManagedObjectListController` for a sectioned list of `NSManagedObject`'s that satisfy the specified fetch clauses. Multiple `ManagedObjectListObserver`'s may then register themselves to be notified when changes are made to the list.
|
||||
|
||||
:param: from a `From` clause indicating the entity type
|
||||
:param: sectionedBy a `SectionedBy` clause indicating the keyPath for the attribute to use when sorting the list into sections.
|
||||
:param: fetchClauses a series of `FetchClause` instances for fetching the object list. Accepts `Where`, `OrderBy`, and `Tweak` clauses.
|
||||
:returns: a `ManagedObjectListController` instance that monitors changes to the list
|
||||
*/
|
||||
public static func observeSectionedList<T: NSManagedObject>(from: From<T>, _ sectionedBy: SectionedBy, _ fetchClauses: [FetchClause]) -> ManagedObjectListController<T> {
|
||||
|
||||
return self.defaultStack.observeSectionedList(from, sectionedBy, fetchClauses)
|
||||
}
|
||||
}
|
||||
@@ -1,116 +0,0 @@
|
||||
//
|
||||
// DataStack+Observing.swift
|
||||
// CoreStore
|
||||
//
|
||||
// Copyright (c) 2015 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
|
||||
|
||||
|
||||
// MARK: - DataStack
|
||||
|
||||
public extension DataStack {
|
||||
|
||||
// MARK: Public
|
||||
|
||||
/**
|
||||
Creates a `ManagedObjectController` for the specified `NSManagedObject`. Multiple `ManagedObjectObserver`'s may then register themselves to be notified when changes are made to the `NSManagedObject`.
|
||||
|
||||
:param: object the `NSManagedObject` to observe changes from
|
||||
:returns: a `ManagedObjectController` that monitors changes to `object`
|
||||
*/
|
||||
public func observeObject<T: NSManagedObject>(object: T) -> ManagedObjectController<T> {
|
||||
|
||||
CoreStore.assert(NSThread.isMainThread(), "Attempted to observe objects from \(typeName(self)) outside the main thread.")
|
||||
|
||||
return ManagedObjectController(
|
||||
dataStack: self,
|
||||
object: object
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
Creates a `ManagedObjectListController` for a list of `NSManagedObject`'s that satisfy the specified fetch clauses. Multiple `ManagedObjectListObserver`'s may then register themselves to be notified when changes are made to the list.
|
||||
|
||||
:param: from a `From` clause indicating the entity type
|
||||
:param: fetchClauses a series of `FetchClause` instances for fetching the object list. Accepts `Where`, `OrderBy`, and `Tweak` clauses.
|
||||
:returns: a `ManagedObjectListController` instance that monitors changes to the list
|
||||
*/
|
||||
public func observeObjectList<T: NSManagedObject>(from: From<T>, _ fetchClauses: FetchClause...) -> ManagedObjectListController<T> {
|
||||
|
||||
return self.observeObjectList(from, fetchClauses)
|
||||
}
|
||||
|
||||
/**
|
||||
Creates a `ManagedObjectListController` for a list of `NSManagedObject`'s that satisfy the specified fetch clauses. Multiple `ManagedObjectListObserver`'s may then register themselves to be notified when changes are made to the list.
|
||||
|
||||
:param: from a `From` clause indicating the entity type
|
||||
:param: fetchClauses a series of `FetchClause` instances for fetching the object list. Accepts `Where`, `OrderBy`, and `Tweak` clauses.
|
||||
:returns: a `ManagedObjectListController` instance that monitors changes to the list
|
||||
*/
|
||||
public func observeObjectList<T: NSManagedObject>(from: From<T>, _ fetchClauses: [FetchClause]) -> ManagedObjectListController<T> {
|
||||
|
||||
CoreStore.assert(NSThread.isMainThread(), "Attempted to observe objects from \(typeName(self)) outside the main thread.")
|
||||
|
||||
return ManagedObjectListController(
|
||||
dataStack: self,
|
||||
from: from,
|
||||
sectionedBy: nil,
|
||||
fetchClauses: fetchClauses
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
Creates a `ManagedObjectListController` for a sectioned list of `NSManagedObject`'s that satisfy the specified fetch clauses. Multiple `ManagedObjectListObserver`'s may then register themselves to be notified when changes are made to the list.
|
||||
|
||||
:param: from a `From` clause indicating the entity type
|
||||
:param: sectionedBy a `SectionedBy` clause indicating the keyPath for the attribute to use when sorting the list into sections.
|
||||
:param: fetchClauses a series of `FetchClause` instances for fetching the object list. Accepts `Where`, `OrderBy`, and `Tweak` clauses.
|
||||
:returns: a `ManagedObjectListController` instance that monitors changes to the list
|
||||
*/
|
||||
public func observeSectionedList<T: NSManagedObject>(from: From<T>, _ sectionedBy: SectionedBy, _ fetchClauses: FetchClause...) -> ManagedObjectListController<T> {
|
||||
|
||||
return self.observeSectionedList(from, sectionedBy, fetchClauses)
|
||||
}
|
||||
|
||||
/**
|
||||
Creates a `ManagedObjectListController` for a sectioned list of `NSManagedObject`'s that satisfy the specified fetch clauses. Multiple `ManagedObjectListObserver`'s may then register themselves to be notified when changes are made to the list.
|
||||
|
||||
:param: from a `From` clause indicating the entity type
|
||||
:param: sectionedBy a `SectionedBy` clause indicating the keyPath for the attribute to use when sorting the list into sections.
|
||||
:param: fetchClauses a series of `FetchClause` instances for fetching the object list. Accepts `Where`, `OrderBy`, and `Tweak` clauses.
|
||||
:returns: a `ManagedObjectListController` instance that monitors changes to the list
|
||||
*/
|
||||
public func observeSectionedList<T: NSManagedObject>(from: From<T>, _ sectionedBy: SectionedBy, _ fetchClauses: [FetchClause]) -> ManagedObjectListController<T> {
|
||||
|
||||
CoreStore.assert(NSThread.isMainThread(), "Attempted to observe objects from \(typeName(self)) outside the main thread.")
|
||||
|
||||
return ManagedObjectListController(
|
||||
dataStack: self,
|
||||
from: from,
|
||||
sectionedBy: sectionedBy,
|
||||
fetchClauses: fetchClauses
|
||||
)
|
||||
}
|
||||
}
|
||||
@@ -1,346 +0,0 @@
|
||||
//
|
||||
// ManagedObjectController.swift
|
||||
// CoreStore
|
||||
//
|
||||
// Copyright (c) 2015 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 let ManagedObjectListControllerWillChangeObjectNotification = "ManagedObjectListControllerWillChangeObjectNotification"
|
||||
private let ManagedObjectListControllerDidDeleteObjectNotification = "ManagedObjectListControllerDidDeleteObjectNotification"
|
||||
private let ManagedObjectListControllerDidUpdateObjectNotification = "ManagedObjectListControllerDidUpdateObjectNotification"
|
||||
|
||||
private let UserInfoKeyObject = "UserInfoKeyObject"
|
||||
|
||||
private struct NotificationKey {
|
||||
|
||||
static var willChangeObject: Void?
|
||||
static var didDeleteObject: Void?
|
||||
static var didUpdateObject: Void?
|
||||
}
|
||||
|
||||
|
||||
// MARK: - ManagedObjectController
|
||||
|
||||
/**
|
||||
The `ManagedObjectController` monitors changes to a single `NSManagedObject` instance. Observers that implement the `ManagedObjectObserver` protocol may then register themselves to the `ManagedObjectController`'s `addObserver(_:)` method:
|
||||
|
||||
let objectController = CoreStore.observeObject(object)
|
||||
objectController.addObserver(self)
|
||||
|
||||
The created `ManagedObjectController` instance needs to be held on (retained) for as long as the object needs to be observed.
|
||||
|
||||
Observers registered via `addObserver(_:)` are not retained. `ManagedObjectController` only keeps a `weak` reference to all observers, thus keeping itself free from retain-cycles.
|
||||
*/
|
||||
public final class ManagedObjectController<T: NSManagedObject> {
|
||||
|
||||
// MARK: Public
|
||||
|
||||
/**
|
||||
Returns the `NSManagedObject` instance being observed, or `nil` if the object was already deleted.
|
||||
*/
|
||||
public var object: T? {
|
||||
|
||||
return self.fetchedResultsController.fetchedObjects?.first as? T
|
||||
}
|
||||
|
||||
/**
|
||||
Returns `true` if the `NSManagedObject` instance being observed still exists, or `false` if the object was already deleted.
|
||||
*/
|
||||
public var isObjectDeleted: Bool {
|
||||
|
||||
return self.object?.managedObjectContext == nil
|
||||
}
|
||||
|
||||
/**
|
||||
Registers a `ManagedObjectObserver` to be notified when changes to the receiver's `object` are made.
|
||||
|
||||
To prevent retain-cycles, `ManagedObjectController` only keeps `weak` references to its observers.
|
||||
|
||||
For thread safety, this method needs to be called from the main thread. An assertion failure will occur (on debug builds only) if called from any thread other than the main thread.
|
||||
|
||||
Calling `addObserver(_:)` multiple times on the same observer is safe, as `ManagedObjectController` unregisters previous notifications to the observer before re-registering them.
|
||||
|
||||
:param: observer a `ManagedObjectObserver` to send change notifications to
|
||||
*/
|
||||
public func addObserver<U: ManagedObjectObserver where U.EntityType == T>(observer: U) {
|
||||
|
||||
CoreStore.assert(NSThread.isMainThread(), "Attempted to add an observer of type \(typeName(observer)) outside the main thread.")
|
||||
|
||||
self.removeObserver(observer)
|
||||
|
||||
self.registerChangeNotification(
|
||||
&NotificationKey.willChangeObject,
|
||||
name: ManagedObjectListControllerWillChangeObjectNotification,
|
||||
toObserver: observer,
|
||||
callback: { [weak self, weak observer] (objectController) -> Void in
|
||||
|
||||
if let strongSelf = self, let object = strongSelf.object, let observer = observer {
|
||||
|
||||
observer.managedObjectWillUpdate(objectController, object: object)
|
||||
}
|
||||
}
|
||||
)
|
||||
self.registerObjectNotification(
|
||||
&NotificationKey.didDeleteObject,
|
||||
name: ManagedObjectListControllerDidDeleteObjectNotification,
|
||||
toObserver: observer,
|
||||
callback: { [weak self, weak observer] (objectController, object) -> Void in
|
||||
|
||||
if let strongSelf = self, let observer = observer {
|
||||
|
||||
observer.managedObjectWasDeleted(objectController, object: object)
|
||||
}
|
||||
}
|
||||
)
|
||||
self.registerObjectNotification(
|
||||
&NotificationKey.didUpdateObject,
|
||||
name: ManagedObjectListControllerDidUpdateObjectNotification,
|
||||
toObserver: observer,
|
||||
callback: { [weak self, weak observer] (objectController, object) -> Void in
|
||||
|
||||
if let strongSelf = self, let observer = observer {
|
||||
|
||||
let previousCommitedAttributes = strongSelf.lastCommittedAttributes
|
||||
let currentCommitedAttributes = object.committedValuesForKeys(nil) as! [NSString: NSObject]
|
||||
|
||||
var changedKeys = Set<String>()
|
||||
for key in currentCommitedAttributes.keys {
|
||||
|
||||
if previousCommitedAttributes[key] != currentCommitedAttributes[key] {
|
||||
|
||||
changedKeys.insert(key as String)
|
||||
}
|
||||
}
|
||||
|
||||
strongSelf.lastCommittedAttributes = currentCommitedAttributes
|
||||
observer.managedObjectWasUpdated(
|
||||
objectController,
|
||||
object: object,
|
||||
changedPersistentKeys: changedKeys
|
||||
)
|
||||
}
|
||||
}
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
Unregisters a `ManagedObjectObserver` from receiving notifications for changes to the receiver's `object`.
|
||||
|
||||
For thread safety, this method needs to be called from the main thread. An assertion failure will occur (on debug builds only) if called from any thread other than the main thread.
|
||||
|
||||
:param: observer a `ManagedObjectObserver` to unregister notifications to
|
||||
*/
|
||||
public func removeObserver<U: ManagedObjectObserver where U.EntityType == T>(observer: U) {
|
||||
|
||||
CoreStore.assert(NSThread.isMainThread(), "Attempted to remove an observer of type \(typeName(observer)) outside the main thread.")
|
||||
|
||||
let nilValue: AnyObject? = nil
|
||||
setAssociatedRetainedObject(nilValue, forKey: &NotificationKey.willChangeObject, inObject: observer)
|
||||
setAssociatedRetainedObject(nilValue, forKey: &NotificationKey.didDeleteObject, inObject: observer)
|
||||
setAssociatedRetainedObject(nilValue, forKey: &NotificationKey.didUpdateObject, inObject: observer)
|
||||
}
|
||||
|
||||
|
||||
// MARK: Internal
|
||||
|
||||
internal init(dataStack: DataStack, object: T) {
|
||||
|
||||
let context = dataStack.mainContext
|
||||
|
||||
let fetchRequest = NSFetchRequest()
|
||||
fetchRequest.entity = context.entityDescriptionForEntityClass(T.self)
|
||||
fetchRequest.fetchLimit = 1
|
||||
fetchRequest.resultType = .ManagedObjectResultType
|
||||
fetchRequest.sortDescriptors = []
|
||||
|
||||
let originalObjectID = object.objectID
|
||||
Where("SELF", isEqualTo: originalObjectID).applyToFetchRequest(fetchRequest)
|
||||
|
||||
let fetchedResultsController = NSFetchedResultsController(
|
||||
fetchRequest: fetchRequest,
|
||||
managedObjectContext: context,
|
||||
sectionNameKeyPath: nil,
|
||||
cacheName: nil
|
||||
)
|
||||
|
||||
let fetchedResultsControllerDelegate = FetchedResultsControllerDelegate()
|
||||
|
||||
self.originalObjectID = originalObjectID
|
||||
self.fetchedResultsController = fetchedResultsController
|
||||
self.fetchedResultsControllerDelegate = fetchedResultsControllerDelegate
|
||||
self.parentStack = dataStack
|
||||
|
||||
fetchedResultsControllerDelegate.handler = self
|
||||
fetchedResultsControllerDelegate.fetchedResultsController = fetchedResultsController
|
||||
|
||||
var error: NSError?
|
||||
if !fetchedResultsController.performFetch(&error) {
|
||||
|
||||
CoreStore.handleError(
|
||||
error ?? NSError(coreStoreErrorCode: .UnknownError),
|
||||
"Failed to perform fetch on <\(NSFetchedResultsController.self)>.")
|
||||
}
|
||||
|
||||
self.lastCommittedAttributes = (self.object?.committedValuesForKeys(nil) as? [NSString: NSObject]) ?? [:]
|
||||
}
|
||||
|
||||
|
||||
// MARK: Private
|
||||
|
||||
private let originalObjectID: NSManagedObjectID
|
||||
private let fetchedResultsController: NSFetchedResultsController
|
||||
private let fetchedResultsControllerDelegate: FetchedResultsControllerDelegate
|
||||
private var lastCommittedAttributes = [NSString: NSObject]()
|
||||
private weak var parentStack: DataStack?
|
||||
|
||||
private func registerChangeNotification(notificationKey: UnsafePointer<Void>, name: String, toObserver observer: AnyObject, callback: (objectController: ManagedObjectController<T>) -> Void) {
|
||||
|
||||
setAssociatedRetainedObject(
|
||||
NotificationObserver(
|
||||
notificationName: name,
|
||||
object: self,
|
||||
closure: { [weak self] (note) -> Void in
|
||||
|
||||
if let strongSelf = self {
|
||||
|
||||
callback(objectController: strongSelf)
|
||||
}
|
||||
}
|
||||
),
|
||||
forKey: notificationKey,
|
||||
inObject: observer
|
||||
)
|
||||
}
|
||||
|
||||
private func registerObjectNotification(notificationKey: UnsafePointer<Void>, name: String, toObserver observer: AnyObject, callback: (objectController: ManagedObjectController<T>, object: T) -> Void) {
|
||||
|
||||
setAssociatedRetainedObject(
|
||||
NotificationObserver(
|
||||
notificationName: name,
|
||||
object: self,
|
||||
closure: { [weak self] (note) -> Void in
|
||||
|
||||
if let strongSelf = self,
|
||||
let userInfo = note.userInfo,
|
||||
let object = userInfo[UserInfoKeyObject] as? T {
|
||||
|
||||
callback(
|
||||
objectController: strongSelf,
|
||||
object: object
|
||||
)
|
||||
}
|
||||
}
|
||||
),
|
||||
forKey: notificationKey,
|
||||
inObject: observer
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// MARK: - ManagedObjectController: FetchedResultsControllerHandler
|
||||
|
||||
extension ManagedObjectController: FetchedResultsControllerHandler {
|
||||
|
||||
// MARK: FetchedResultsControllerHandler
|
||||
|
||||
private func controller(controller: NSFetchedResultsController, didChangeObject anObject: AnyObject, atIndexPath indexPath: NSIndexPath?, forChangeType type: NSFetchedResultsChangeType, newIndexPath: NSIndexPath?) {
|
||||
|
||||
switch type {
|
||||
|
||||
case .Delete:
|
||||
NSNotificationCenter.defaultCenter().postNotificationName(
|
||||
ManagedObjectListControllerDidDeleteObjectNotification,
|
||||
object: self,
|
||||
userInfo: [UserInfoKeyObject: anObject]
|
||||
)
|
||||
|
||||
case .Update:
|
||||
NSNotificationCenter.defaultCenter().postNotificationName(
|
||||
ManagedObjectListControllerDidUpdateObjectNotification,
|
||||
object: self,
|
||||
userInfo: [UserInfoKeyObject: anObject]
|
||||
)
|
||||
|
||||
default:
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
private func controllerWillChangeContent(controller: NSFetchedResultsController) {
|
||||
|
||||
NSNotificationCenter.defaultCenter().postNotificationName(
|
||||
ManagedObjectListControllerWillChangeObjectNotification,
|
||||
object: self
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// MARK: - FetchedResultsControllerHandler
|
||||
|
||||
private protocol FetchedResultsControllerHandler: class {
|
||||
|
||||
func controller(controller: NSFetchedResultsController, didChangeObject anObject: AnyObject, atIndexPath indexPath: NSIndexPath?, forChangeType type: NSFetchedResultsChangeType, newIndexPath: NSIndexPath?)
|
||||
|
||||
func controllerWillChangeContent(controller: NSFetchedResultsController)
|
||||
}
|
||||
|
||||
|
||||
// MARK: - FetchedResultsControllerDelegate
|
||||
|
||||
private final class FetchedResultsControllerDelegate: NSFetchedResultsControllerDelegate {
|
||||
|
||||
// MARK: NSFetchedResultsControllerDelegate
|
||||
|
||||
@objc func controllerWillChangeContent(controller: NSFetchedResultsController) {
|
||||
|
||||
self.handler?.controllerWillChangeContent(controller)
|
||||
}
|
||||
|
||||
@objc func controller(controller: NSFetchedResultsController, didChangeObject anObject: AnyObject, atIndexPath indexPath: NSIndexPath?, forChangeType type: NSFetchedResultsChangeType, newIndexPath: NSIndexPath?) {
|
||||
|
||||
self.handler?.controller(controller, didChangeObject: anObject, atIndexPath: indexPath, forChangeType: type, newIndexPath: newIndexPath)
|
||||
}
|
||||
|
||||
|
||||
// MARK: Private
|
||||
|
||||
weak var handler: FetchedResultsControllerHandler?
|
||||
weak var fetchedResultsController: NSFetchedResultsController? {
|
||||
|
||||
didSet {
|
||||
|
||||
oldValue?.delegate = nil
|
||||
self.fetchedResultsController?.delegate = self
|
||||
}
|
||||
}
|
||||
|
||||
deinit {
|
||||
|
||||
self.fetchedResultsController?.delegate = nil
|
||||
}
|
||||
}
|
||||
@@ -1,832 +0,0 @@
|
||||
//
|
||||
// ManagedObjectListController.swift
|
||||
// CoreStore
|
||||
//
|
||||
// Copyright (c) 2015 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
|
||||
|
||||
|
||||
// MARK: - SectionedBy
|
||||
|
||||
/**
|
||||
The `SectionedBy` clause indicates the key path to use to group the `ManagedObjectListController` objects into sections. An optional closure can also be provided to transform the value into an appropriate section name:
|
||||
|
||||
let listController = CoreStore.observeSectionedList(
|
||||
From(MyPersonEntity),
|
||||
SectionedBy("age") { "Age \($0)" },
|
||||
OrderBy(.Ascending("lastName"))
|
||||
)
|
||||
*/
|
||||
public struct SectionedBy {
|
||||
|
||||
// MARK: Public
|
||||
|
||||
/**
|
||||
Initializes a `SectionedBy` clause with the key path to use to group `ManagedObjectListController` objects into sections
|
||||
|
||||
:param: sectionKeyPath the key path to use to group the objects into sections
|
||||
*/
|
||||
public init(_ sectionKeyPath: KeyPath) {
|
||||
|
||||
self.init(sectionKeyPath, { $0 })
|
||||
}
|
||||
|
||||
/**
|
||||
Initializes a `SectionedBy` clause with the key path to use to group `ManagedObjectListController` objects into sections, and a closure to transform the value for the key path to an appropriate section name
|
||||
|
||||
:param: sectionKeyPath the key path to use to group the objects into sections
|
||||
:param: sectionIndexTransformer a closure to transform the value for the key path to an appropriate section name
|
||||
*/
|
||||
public init(_ sectionKeyPath: KeyPath, _ sectionIndexTransformer: (sectionName: String?) -> String?) {
|
||||
|
||||
self.sectionKeyPath = sectionKeyPath
|
||||
self.sectionIndexTransformer = sectionIndexTransformer
|
||||
}
|
||||
|
||||
|
||||
// MARK: Internal
|
||||
|
||||
internal let sectionKeyPath: KeyPath
|
||||
internal let sectionIndexTransformer: (sectionName: KeyPath?) -> String?
|
||||
}
|
||||
|
||||
|
||||
// MARK: - ManagedObjectListController
|
||||
|
||||
/**
|
||||
The `ManagedObjectListController` monitors changes to a list of `NSManagedObject` instances. Observers that implement the `ManagedObjectListChangeObserver` protocol may then register themselves to the `ManagedObjectListController`'s `addObserver(_:)` method:
|
||||
|
||||
let listController = CoreStore.observeObjectList(
|
||||
From(MyPersonEntity),
|
||||
Where("title", isEqualTo: "Engineer"),
|
||||
OrderBy(.Ascending("lastName"))
|
||||
)
|
||||
listController.addObserver(self)
|
||||
|
||||
The `ManagedObjectListController` instance needs to be held on (retained) for as long as the list needs to be observed.
|
||||
Observers registered via `addObserver(_:)` are not retained. `ManagedObjectListController` only keeps a `weak` reference to all observers, thus keeping itself free from retain-cycles.
|
||||
|
||||
Lists created with `observeObjectList(...)` keep a single-section list of objects, where each object can be accessed by index:
|
||||
|
||||
let firstPerson: MyPersonEntity = listController[0]
|
||||
|
||||
Accessing the list with an index above the valid range will throw an exception.
|
||||
|
||||
Creating a sectioned-list is also possible with the `observeSectionedList(...)` method:
|
||||
|
||||
let listController = CoreStore.observeSectionedList(
|
||||
From(MyPersonEntity),
|
||||
SectionedBy("age") { "Age \($0)" },
|
||||
Where("title", isEqualTo: "Engineer"),
|
||||
OrderBy(.Ascending("lastName"))
|
||||
)
|
||||
listController.addObserver(self)
|
||||
|
||||
Objects from `ManagedObjectListController`'s created this way can be accessed either by an `NSIndexPath` or a tuple:
|
||||
|
||||
let indexPath = NSIndexPath(forItem: 3, inSection: 2)
|
||||
let person1 = listController[indexPath]
|
||||
let person2 = listController[2, 3]
|
||||
|
||||
In the example above, both `person1` and `person2` will contain the object at section=2, index=3.
|
||||
*/
|
||||
public final class ManagedObjectListController<T: NSManagedObject> {
|
||||
|
||||
// MARK: Public
|
||||
|
||||
/**
|
||||
Accesses the object at the given index within the first section. This subscript indexer is typically used for `ManagedObjectListController`'s created with `addObserver(_:)`.
|
||||
|
||||
:param: index the index of the object. Using an index above the valid range will throw an exception.
|
||||
*/
|
||||
public subscript(index: Int) -> T {
|
||||
|
||||
return self.fetchedResultsController.objectAtIndexPath(NSIndexPath(forItem: index, inSection: 0)) as! T
|
||||
}
|
||||
|
||||
/**
|
||||
Accesses the object at the given `NSIndexPath`. This subscript indexer is typically used for `ManagedObjectListController`'s created with `observeSectionedList(_:)`.
|
||||
|
||||
:param: indexPath the `NSIndexPath` for the object. Using an `indexPath` with an invalid range will throw an exception.
|
||||
*/
|
||||
public subscript(indexPath: NSIndexPath) -> T {
|
||||
|
||||
return self.fetchedResultsController.objectAtIndexPath(indexPath) as! T
|
||||
}
|
||||
|
||||
/**
|
||||
Accesses the object at the given `sectionIndex` and `itemIndex`. This subscript indexer is typically used for `ManagedObjectListController`'s created with `observeSectionedList(_:)`.
|
||||
|
||||
:param: sectionIndex the section index for the object. Using a `sectionIndex` with an invalid range will throw an exception.
|
||||
:param: itemIndex the index for the object within the section. Using an `itemIndex` with an invalid range will throw an exception.
|
||||
*/
|
||||
public subscript(sectionIndex: Int, itemIndex: Int) -> T {
|
||||
|
||||
return self.fetchedResultsController.objectAtIndexPath(NSIndexPath(forItem: itemIndex, inSection: sectionIndex)) as! T
|
||||
}
|
||||
|
||||
/**
|
||||
Returns the number of sections
|
||||
*/
|
||||
public func numberOfSections() -> Int {
|
||||
|
||||
return self.fetchedResultsController.sections?.count ?? 0
|
||||
}
|
||||
|
||||
/**
|
||||
Returns the number of objects in the specified section
|
||||
|
||||
:param: section the section index
|
||||
*/
|
||||
public func numberOfObjectsInSection(section: Int) -> Int {
|
||||
|
||||
return (self.fetchedResultsController.sections?[section] as? NSFetchedResultsSectionInfo)?.numberOfObjects ?? 0
|
||||
}
|
||||
|
||||
/**
|
||||
Returns the `NSFetchedResultsSectionInfo` for the specified section
|
||||
|
||||
:param: section the section index
|
||||
*/
|
||||
public func sectionInfoAtIndex(section: Int) -> NSFetchedResultsSectionInfo {
|
||||
|
||||
return self.fetchedResultsController.sections![section] as! NSFetchedResultsSectionInfo
|
||||
}
|
||||
|
||||
/**
|
||||
Registers a `ManagedObjectListChangeObserver` to be notified when changes to the receiver's list occur.
|
||||
|
||||
To prevent retain-cycles, `ManagedObjectListController` only keeps `weak` references to its observers.
|
||||
|
||||
For thread safety, this method needs to be called from the main thread. An assertion failure will occur (on debug builds only) if called from any thread other than the main thread.
|
||||
|
||||
Calling `addObserver(_:)` multiple times on the same observer is safe, as `ManagedObjectListController` unregisters previous notifications to the observer before re-registering them.
|
||||
|
||||
:param: observer a `ManagedObjectListChangeObserver` to send change notifications to
|
||||
*/
|
||||
public func addObserver<U: ManagedObjectListChangeObserver where U.EntityType == T>(observer: U) {
|
||||
|
||||
CoreStore.assert(NSThread.isMainThread(), "Attempted to add an observer of type \(typeName(observer)) outside the main thread.")
|
||||
|
||||
self.removeObserver(observer)
|
||||
|
||||
self.registerChangeNotification(
|
||||
&NotificationKey.willChangeList,
|
||||
name: ManagedObjectListControllerWillChangeListNotification,
|
||||
toObserver: observer,
|
||||
callback: { [weak observer] (listController) -> Void in
|
||||
|
||||
if let observer = observer {
|
||||
|
||||
observer.managedObjectListWillChange(listController)
|
||||
}
|
||||
}
|
||||
)
|
||||
self.registerChangeNotification(
|
||||
&NotificationKey.didChangeList,
|
||||
name: ManagedObjectListControllerDidChangeListNotification,
|
||||
toObserver: observer,
|
||||
callback: { [weak observer] (listController) -> Void in
|
||||
|
||||
if let observer = observer {
|
||||
|
||||
observer.managedObjectListDidChange(listController)
|
||||
}
|
||||
}
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
Registers a `ManagedObjectListObjectObserver` to be notified when changes to the receiver's list occur.
|
||||
|
||||
To prevent retain-cycles, `ManagedObjectListController` only keeps `weak` references to its observers.
|
||||
|
||||
For thread safety, this method needs to be called from the main thread. An assertion failure will occur (on debug builds only) if called from any thread other than the main thread.
|
||||
|
||||
Calling `addObserver(_:)` multiple times on the same observer is safe, as `ManagedObjectListController` unregisters previous notifications to the observer before re-registering them.
|
||||
|
||||
:param: observer a `ManagedObjectListObjectObserver` to send change notifications to
|
||||
*/
|
||||
public func addObserver<U: ManagedObjectListObjectObserver where U.EntityType == T>(observer: U) {
|
||||
|
||||
CoreStore.assert(NSThread.isMainThread(), "Attempted to add an observer of type \(typeName(observer)) outside the main thread.")
|
||||
|
||||
self.removeObserver(observer)
|
||||
|
||||
self.registerChangeNotification(
|
||||
&NotificationKey.willChangeList,
|
||||
name: ManagedObjectListControllerWillChangeListNotification,
|
||||
toObserver: observer,
|
||||
callback: { [weak observer] (listController) -> Void in
|
||||
|
||||
if let observer = observer {
|
||||
|
||||
observer.managedObjectListWillChange(listController)
|
||||
}
|
||||
}
|
||||
)
|
||||
self.registerChangeNotification(
|
||||
&NotificationKey.didChangeList,
|
||||
name: ManagedObjectListControllerDidChangeListNotification,
|
||||
toObserver: observer,
|
||||
callback: { [weak observer] (listController) -> Void in
|
||||
|
||||
if let observer = observer {
|
||||
|
||||
observer.managedObjectListDidChange(listController)
|
||||
}
|
||||
}
|
||||
)
|
||||
|
||||
self.registerObjectNotification(
|
||||
&NotificationKey.didInsertObject,
|
||||
name: ManagedObjectListControllerDidInsertObjectNotification,
|
||||
toObserver: observer,
|
||||
callback: { [weak observer] (listController, object, indexPath, newIndexPath) -> Void in
|
||||
|
||||
if let observer = observer {
|
||||
|
||||
observer.managedObjectList(
|
||||
listController,
|
||||
didInsertObject: object,
|
||||
toIndexPath: newIndexPath!
|
||||
)
|
||||
}
|
||||
}
|
||||
)
|
||||
self.registerObjectNotification(
|
||||
&NotificationKey.didDeleteObject,
|
||||
name: ManagedObjectListControllerDidDeleteObjectNotification,
|
||||
toObserver: observer,
|
||||
callback: { [weak observer] (listController, object, indexPath, newIndexPath) -> Void in
|
||||
|
||||
if let observer = observer {
|
||||
|
||||
observer.managedObjectList(
|
||||
listController,
|
||||
didDeleteObject: object,
|
||||
fromIndexPath: indexPath!
|
||||
)
|
||||
}
|
||||
}
|
||||
)
|
||||
self.registerObjectNotification(
|
||||
&NotificationKey.didUpdateObject,
|
||||
name: ManagedObjectListControllerDidUpdateObjectNotification,
|
||||
toObserver: observer,
|
||||
callback: { [weak observer] (listController, object, indexPath, newIndexPath) -> Void in
|
||||
|
||||
if let observer = observer {
|
||||
|
||||
observer.managedObjectList(
|
||||
listController,
|
||||
didUpdateObject: object,
|
||||
atIndexPath: indexPath!
|
||||
)
|
||||
}
|
||||
}
|
||||
)
|
||||
self.registerObjectNotification(
|
||||
&NotificationKey.didMoveObject,
|
||||
name: ManagedObjectListControllerDidMoveObjectNotification,
|
||||
toObserver: observer,
|
||||
callback: { [weak observer] (listController, object, indexPath, newIndexPath) -> Void in
|
||||
|
||||
if let observer = observer {
|
||||
|
||||
observer.managedObjectList(
|
||||
listController,
|
||||
didMoveObject: object,
|
||||
fromIndexPath: indexPath!,
|
||||
toIndexPath: newIndexPath!
|
||||
)
|
||||
}
|
||||
}
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
Registers a `ManagedObjectListSectionObserver` to be notified when changes to the receiver's list occur.
|
||||
|
||||
To prevent retain-cycles, `ManagedObjectListController` only keeps `weak` references to its observers.
|
||||
|
||||
For thread safety, this method needs to be called from the main thread. An assertion failure will occur (on debug builds only) if called from any thread other than the main thread.
|
||||
|
||||
Calling `addObserver(_:)` multiple times on the same observer is safe, as `ManagedObjectListController` unregisters previous notifications to the observer before re-registering them.
|
||||
|
||||
:param: observer a `ManagedObjectListSectionObserver` to send change notifications to
|
||||
*/
|
||||
public func addObserver<U: ManagedObjectListSectionObserver where U.EntityType == T>(observer: U) {
|
||||
|
||||
CoreStore.assert(NSThread.isMainThread(), "Attempted to add an observer of type \(typeName(observer)) outside the main thread.")
|
||||
|
||||
self.removeObserver(observer)
|
||||
|
||||
self.registerChangeNotification(
|
||||
&NotificationKey.willChangeList,
|
||||
name: ManagedObjectListControllerWillChangeListNotification,
|
||||
toObserver: observer,
|
||||
callback: { [weak observer] (listController) -> Void in
|
||||
|
||||
if let observer = observer {
|
||||
|
||||
observer.managedObjectListWillChange(listController)
|
||||
}
|
||||
}
|
||||
)
|
||||
self.registerChangeNotification(
|
||||
&NotificationKey.didChangeList,
|
||||
name: ManagedObjectListControllerDidChangeListNotification,
|
||||
toObserver: observer,
|
||||
callback: { [weak observer] (listController) -> Void in
|
||||
|
||||
if let observer = observer {
|
||||
|
||||
observer.managedObjectListDidChange(listController)
|
||||
}
|
||||
}
|
||||
)
|
||||
|
||||
self.registerObjectNotification(
|
||||
&NotificationKey.didInsertObject,
|
||||
name: ManagedObjectListControllerDidInsertObjectNotification,
|
||||
toObserver: observer,
|
||||
callback: { [weak observer] (listController, object, indexPath, newIndexPath) -> Void in
|
||||
|
||||
if let observer = observer {
|
||||
|
||||
observer.managedObjectList(
|
||||
listController,
|
||||
didInsertObject: object,
|
||||
toIndexPath: newIndexPath!
|
||||
)
|
||||
}
|
||||
}
|
||||
)
|
||||
self.registerObjectNotification(
|
||||
&NotificationKey.didDeleteObject,
|
||||
name: ManagedObjectListControllerDidDeleteObjectNotification,
|
||||
toObserver: observer,
|
||||
callback: { [weak observer] (listController, object, indexPath, newIndexPath) -> Void in
|
||||
|
||||
if let observer = observer {
|
||||
|
||||
observer.managedObjectList(
|
||||
listController,
|
||||
didDeleteObject: object,
|
||||
fromIndexPath: indexPath!
|
||||
)
|
||||
}
|
||||
}
|
||||
)
|
||||
self.registerObjectNotification(
|
||||
&NotificationKey.didUpdateObject,
|
||||
name: ManagedObjectListControllerDidUpdateObjectNotification,
|
||||
toObserver: observer,
|
||||
callback: { [weak observer] (listController, object, indexPath, newIndexPath) -> Void in
|
||||
|
||||
if let observer = observer {
|
||||
|
||||
observer.managedObjectList(
|
||||
listController,
|
||||
didUpdateObject: object,
|
||||
atIndexPath: indexPath!
|
||||
)
|
||||
}
|
||||
}
|
||||
)
|
||||
self.registerObjectNotification(
|
||||
&NotificationKey.didMoveObject,
|
||||
name: ManagedObjectListControllerDidMoveObjectNotification,
|
||||
toObserver: observer,
|
||||
callback: { [weak observer] (listController, object, indexPath, newIndexPath) -> Void in
|
||||
|
||||
if let observer = observer {
|
||||
|
||||
observer.managedObjectList(
|
||||
listController,
|
||||
didMoveObject: object,
|
||||
fromIndexPath: indexPath!,
|
||||
toIndexPath: newIndexPath!
|
||||
)
|
||||
}
|
||||
}
|
||||
)
|
||||
|
||||
self.registerSectionNotification(
|
||||
&NotificationKey.didInsertSection,
|
||||
name: ManagedObjectListControllerDidInsertSectionNotification,
|
||||
toObserver: observer,
|
||||
callback: { [weak observer] (listController, sectionInfo, sectionIndex) -> Void in
|
||||
|
||||
if let observer = observer {
|
||||
|
||||
observer.managedObjectList(
|
||||
listController,
|
||||
didInsertSection: sectionInfo,
|
||||
toSectionIndex: sectionIndex
|
||||
)
|
||||
}
|
||||
}
|
||||
)
|
||||
self.registerSectionNotification(
|
||||
&NotificationKey.didDeleteSection,
|
||||
name: ManagedObjectListControllerDidDeleteSectionNotification,
|
||||
toObserver: observer,
|
||||
callback: { [weak observer] (listController, sectionInfo, sectionIndex) -> Void in
|
||||
|
||||
if let observer = observer {
|
||||
|
||||
observer.managedObjectList(
|
||||
listController,
|
||||
didDeleteSection: sectionInfo,
|
||||
fromSectionIndex: sectionIndex
|
||||
)
|
||||
}
|
||||
}
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
Unregisters a `ManagedObjectListChangeObserver` from receiving notifications for changes to the receiver's list.
|
||||
|
||||
For thread safety, this method needs to be called from the main thread. An assertion failure will occur (on debug builds only) if called from any thread other than the main thread.
|
||||
|
||||
:param: observer a `ManagedObjectListChangeObserver` to unregister notifications to
|
||||
*/
|
||||
public func removeObserver<U: ManagedObjectListChangeObserver where U.EntityType == T>(observer: U) {
|
||||
|
||||
CoreStore.assert(NSThread.isMainThread(), "Attempted to remove an observer of type \(typeName(observer)) outside the main thread.")
|
||||
|
||||
let nilValue: AnyObject? = nil
|
||||
setAssociatedRetainedObject(nilValue, forKey: &NotificationKey.willChangeList, inObject: observer)
|
||||
setAssociatedRetainedObject(nilValue, forKey: &NotificationKey.didChangeList, inObject: observer)
|
||||
|
||||
setAssociatedRetainedObject(nilValue, forKey: &NotificationKey.didInsertObject, inObject: observer)
|
||||
setAssociatedRetainedObject(nilValue, forKey: &NotificationKey.didDeleteObject, inObject: observer)
|
||||
setAssociatedRetainedObject(nilValue, forKey: &NotificationKey.didUpdateObject, inObject: observer)
|
||||
setAssociatedRetainedObject(nilValue, forKey: &NotificationKey.didMoveObject, inObject: observer)
|
||||
|
||||
setAssociatedRetainedObject(nilValue, forKey: &NotificationKey.didInsertSection, inObject: observer)
|
||||
setAssociatedRetainedObject(nilValue, forKey: &NotificationKey.didDeleteSection, inObject: observer)
|
||||
}
|
||||
|
||||
|
||||
// MARK: Internal
|
||||
|
||||
internal init(dataStack: DataStack, from: From<T>, sectionedBy: SectionedBy?, fetchClauses: [FetchClause]) {
|
||||
|
||||
let context = dataStack.mainContext
|
||||
|
||||
let fetchRequest = NSFetchRequest()
|
||||
from.applyToFetchRequest(fetchRequest, context: context)
|
||||
|
||||
fetchRequest.fetchLimit = 0
|
||||
fetchRequest.resultType = .ManagedObjectResultType
|
||||
|
||||
for clause in fetchClauses {
|
||||
|
||||
clause.applyToFetchRequest(fetchRequest)
|
||||
}
|
||||
|
||||
let fetchedResultsController = NSFetchedResultsController(
|
||||
fetchRequest: fetchRequest,
|
||||
managedObjectContext: context,
|
||||
sectionNameKeyPath: sectionedBy?.sectionKeyPath,
|
||||
cacheName: nil
|
||||
)
|
||||
|
||||
let fetchedResultsControllerDelegate = FetchedResultsControllerDelegate()
|
||||
|
||||
self.fetchedResultsController = fetchedResultsController
|
||||
self.fetchedResultsControllerDelegate = fetchedResultsControllerDelegate
|
||||
self.parentStack = dataStack
|
||||
|
||||
if let sectionIndexTransformer = sectionedBy?.sectionIndexTransformer {
|
||||
|
||||
self.sectionIndexTransformer = sectionIndexTransformer
|
||||
}
|
||||
else {
|
||||
|
||||
self.sectionIndexTransformer = { $0 }
|
||||
}
|
||||
|
||||
|
||||
fetchedResultsControllerDelegate.handler = self
|
||||
fetchedResultsControllerDelegate.fetchedResultsController = fetchedResultsController
|
||||
|
||||
var error: NSError?
|
||||
if !fetchedResultsController.performFetch(&error) {
|
||||
|
||||
CoreStore.handleError(
|
||||
error ?? NSError(coreStoreErrorCode: .UnknownError),
|
||||
"Failed to perform fetch on <\(NSFetchedResultsController.self)>.")
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// MARK: Private
|
||||
|
||||
private let fetchedResultsController: NSFetchedResultsController
|
||||
private let fetchedResultsControllerDelegate: FetchedResultsControllerDelegate
|
||||
private let sectionIndexTransformer: (sectionName: KeyPath?) -> String?
|
||||
private weak var parentStack: DataStack?
|
||||
|
||||
private func registerChangeNotification(notificationKey: UnsafePointer<Void>, name: String, toObserver observer: AnyObject, callback: (listController: ManagedObjectListController<T>) -> Void) {
|
||||
|
||||
setAssociatedRetainedObject(
|
||||
NotificationObserver(
|
||||
notificationName: name,
|
||||
object: self,
|
||||
closure: { [weak self] (note) -> Void in
|
||||
|
||||
if let strongSelf = self {
|
||||
|
||||
callback(listController: strongSelf)
|
||||
}
|
||||
}
|
||||
),
|
||||
forKey: notificationKey,
|
||||
inObject: observer
|
||||
)
|
||||
}
|
||||
|
||||
private func registerObjectNotification(notificationKey: UnsafePointer<Void>, name: String, toObserver observer: AnyObject, callback: (listController: ManagedObjectListController<T>, object: T, indexPath: NSIndexPath?, newIndexPath: NSIndexPath?) -> Void) {
|
||||
|
||||
setAssociatedRetainedObject(
|
||||
NotificationObserver(
|
||||
notificationName: name,
|
||||
object: self,
|
||||
closure: { [weak self] (note) -> Void in
|
||||
|
||||
if let strongSelf = self,
|
||||
let userInfo = note.userInfo,
|
||||
let object = userInfo[UserInfoKeyObject] as? T {
|
||||
|
||||
callback(
|
||||
listController: strongSelf,
|
||||
object: object,
|
||||
indexPath: userInfo[UserInfoKeyIndexPath] as? NSIndexPath,
|
||||
newIndexPath: userInfo[UserInfoKeyNewIndexPath] as? NSIndexPath
|
||||
)
|
||||
}
|
||||
}
|
||||
),
|
||||
forKey: notificationKey,
|
||||
inObject: observer
|
||||
)
|
||||
}
|
||||
|
||||
private func registerSectionNotification(notificationKey: UnsafePointer<Void>, name: String, toObserver observer: AnyObject, callback: (listController: ManagedObjectListController<T>, sectionInfo: NSFetchedResultsSectionInfo, sectionIndex: Int) -> Void) {
|
||||
|
||||
setAssociatedRetainedObject(
|
||||
NotificationObserver(
|
||||
notificationName: name,
|
||||
object: self,
|
||||
closure: { [weak self] (note) -> Void in
|
||||
|
||||
if let strongSelf = self,
|
||||
let userInfo = note.userInfo,
|
||||
let sectionInfo = userInfo[UserInfoKeySectionInfo] as? NSFetchedResultsSectionInfo,
|
||||
let sectionIndex = (userInfo[UserInfoKeySectionIndex] as? NSNumber)?.integerValue {
|
||||
|
||||
callback(
|
||||
listController: strongSelf,
|
||||
sectionInfo: sectionInfo,
|
||||
sectionIndex: sectionIndex
|
||||
)
|
||||
}
|
||||
}
|
||||
),
|
||||
forKey: notificationKey,
|
||||
inObject: observer
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// MARK: - ManagedObjectListController: FetchedResultsControllerHandler
|
||||
|
||||
extension ManagedObjectListController: FetchedResultsControllerHandler {
|
||||
|
||||
// MARK: FetchedResultsControllerHandler
|
||||
|
||||
private func controller(controller: NSFetchedResultsController, didChangeObject anObject: AnyObject, atIndexPath indexPath: NSIndexPath?, forChangeType type: NSFetchedResultsChangeType, newIndexPath: NSIndexPath?) {
|
||||
|
||||
switch type {
|
||||
|
||||
case .Insert:
|
||||
NSNotificationCenter.defaultCenter().postNotificationName(
|
||||
ManagedObjectListControllerDidInsertObjectNotification,
|
||||
object: self,
|
||||
userInfo: [
|
||||
UserInfoKeyObject: anObject,
|
||||
UserInfoKeyNewIndexPath: newIndexPath!
|
||||
]
|
||||
)
|
||||
|
||||
case .Delete:
|
||||
NSNotificationCenter.defaultCenter().postNotificationName(
|
||||
ManagedObjectListControllerDidDeleteObjectNotification,
|
||||
object: self,
|
||||
userInfo: [
|
||||
UserInfoKeyObject: anObject,
|
||||
UserInfoKeyIndexPath: indexPath!
|
||||
]
|
||||
)
|
||||
|
||||
case .Update:
|
||||
NSNotificationCenter.defaultCenter().postNotificationName(
|
||||
ManagedObjectListControllerDidUpdateObjectNotification,
|
||||
object: self,
|
||||
userInfo: [
|
||||
UserInfoKeyObject: anObject,
|
||||
UserInfoKeyIndexPath: indexPath!
|
||||
]
|
||||
)
|
||||
|
||||
case .Move:
|
||||
NSNotificationCenter.defaultCenter().postNotificationName(
|
||||
ManagedObjectListControllerDidMoveObjectNotification,
|
||||
object: self,
|
||||
userInfo: [
|
||||
UserInfoKeyObject: anObject,
|
||||
UserInfoKeyIndexPath: indexPath!,
|
||||
UserInfoKeyNewIndexPath: newIndexPath!
|
||||
]
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
private func controller(controller: NSFetchedResultsController, didChangeSection sectionInfo: NSFetchedResultsSectionInfo, atIndex sectionIndex: Int, forChangeType type: NSFetchedResultsChangeType) {
|
||||
|
||||
switch type {
|
||||
|
||||
case .Insert:
|
||||
NSNotificationCenter.defaultCenter().postNotificationName(
|
||||
ManagedObjectListControllerDidInsertSectionNotification,
|
||||
object: self,
|
||||
userInfo: [
|
||||
UserInfoKeySectionInfo: sectionInfo,
|
||||
UserInfoKeySectionIndex: NSNumber(integer: sectionIndex)
|
||||
]
|
||||
)
|
||||
|
||||
case .Delete:
|
||||
NSNotificationCenter.defaultCenter().postNotificationName(
|
||||
ManagedObjectListControllerDidDeleteSectionNotification,
|
||||
object: self,
|
||||
userInfo: [
|
||||
UserInfoKeySectionInfo: sectionInfo,
|
||||
UserInfoKeySectionIndex: NSNumber(integer: sectionIndex)
|
||||
]
|
||||
)
|
||||
|
||||
default:
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
private func controllerWillChangeContent(controller: NSFetchedResultsController) {
|
||||
|
||||
NSNotificationCenter.defaultCenter().postNotificationName(
|
||||
ManagedObjectListControllerWillChangeListNotification,
|
||||
object: self
|
||||
)
|
||||
}
|
||||
|
||||
private func controllerDidChangeContent(controller: NSFetchedResultsController) {
|
||||
|
||||
NSNotificationCenter.defaultCenter().postNotificationName(
|
||||
ManagedObjectListControllerDidChangeListNotification,
|
||||
object: self
|
||||
)
|
||||
}
|
||||
|
||||
private func controller(controller: NSFetchedResultsController, sectionIndexTitleForSectionName sectionName: String?) -> String? {
|
||||
|
||||
return self.sectionIndexTransformer(sectionName: sectionName)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// MARK: - FetchedResultsControllerHandler
|
||||
|
||||
private protocol FetchedResultsControllerHandler: class {
|
||||
|
||||
func controller(controller: NSFetchedResultsController, didChangeObject anObject: AnyObject, atIndexPath indexPath: NSIndexPath?, forChangeType type: NSFetchedResultsChangeType, newIndexPath: NSIndexPath?)
|
||||
|
||||
func controller(controller: NSFetchedResultsController, didChangeSection sectionInfo: NSFetchedResultsSectionInfo, atIndex sectionIndex: Int, forChangeType type: NSFetchedResultsChangeType)
|
||||
|
||||
func controllerWillChangeContent(controller: NSFetchedResultsController)
|
||||
|
||||
func controllerDidChangeContent(controller: NSFetchedResultsController)
|
||||
|
||||
func controller(controller: NSFetchedResultsController, sectionIndexTitleForSectionName sectionName: String?) -> String?
|
||||
}
|
||||
|
||||
|
||||
// MARK: - FetchedResultsControllerDelegate
|
||||
|
||||
private final class FetchedResultsControllerDelegate: NSFetchedResultsControllerDelegate {
|
||||
|
||||
// MARK: NSFetchedResultsControllerDelegate
|
||||
|
||||
@objc func controllerWillChangeContent(controller: NSFetchedResultsController) {
|
||||
|
||||
self.handler?.controllerWillChangeContent(controller)
|
||||
}
|
||||
|
||||
@objc func controllerDidChangeContent(controller: NSFetchedResultsController) {
|
||||
|
||||
self.handler?.controllerDidChangeContent(controller)
|
||||
}
|
||||
|
||||
@objc func controller(controller: NSFetchedResultsController, didChangeObject anObject: AnyObject, atIndexPath indexPath: NSIndexPath?, forChangeType type: NSFetchedResultsChangeType, newIndexPath: NSIndexPath?) {
|
||||
|
||||
self.handler?.controller(controller, didChangeObject: anObject, atIndexPath: indexPath, forChangeType: type, newIndexPath: newIndexPath)
|
||||
}
|
||||
|
||||
@objc func controller(controller: NSFetchedResultsController, didChangeSection sectionInfo: NSFetchedResultsSectionInfo, atIndex sectionIndex: Int, forChangeType type: NSFetchedResultsChangeType) {
|
||||
|
||||
self.handler?.controller(controller, didChangeSection: sectionInfo, atIndex: sectionIndex, forChangeType: type)
|
||||
}
|
||||
|
||||
@objc func controller(controller: NSFetchedResultsController, sectionIndexTitleForSectionName sectionName: String?) -> String? {
|
||||
|
||||
return self.handler?.controller(controller, sectionIndexTitleForSectionName: sectionName)
|
||||
}
|
||||
|
||||
|
||||
// MARK: Private
|
||||
|
||||
weak var handler: FetchedResultsControllerHandler?
|
||||
weak var fetchedResultsController: NSFetchedResultsController? {
|
||||
|
||||
didSet {
|
||||
|
||||
oldValue?.delegate = nil
|
||||
self.fetchedResultsController?.delegate = self
|
||||
}
|
||||
}
|
||||
|
||||
deinit {
|
||||
|
||||
self.fetchedResultsController?.delegate = nil
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
private let ManagedObjectListControllerWillChangeListNotification = "ManagedObjectListControllerWillChangeListNotification"
|
||||
private let ManagedObjectListControllerDidChangeListNotification = "ManagedObjectListControllerDidChangeListNotification"
|
||||
|
||||
private let ManagedObjectListControllerDidInsertObjectNotification = "ManagedObjectListControllerDidInsertObjectNotification"
|
||||
private let ManagedObjectListControllerDidDeleteObjectNotification = "ManagedObjectListControllerDidDeleteObjectNotification"
|
||||
private let ManagedObjectListControllerDidUpdateObjectNotification = "ManagedObjectListControllerDidUpdateObjectNotification"
|
||||
private let ManagedObjectListControllerDidMoveObjectNotification = "ManagedObjectListControllerDidMoveObjectNotification"
|
||||
|
||||
private let ManagedObjectListControllerDidInsertSectionNotification = "ManagedObjectListControllerDidInsertSectionNotification"
|
||||
private let ManagedObjectListControllerDidDeleteSectionNotification = "ManagedObjectListControllerDidDeleteSectionNotification"
|
||||
|
||||
private let UserInfoKeyObject = "UserInfoKeyObject"
|
||||
private let UserInfoKeyIndexPath = "UserInfoKeyIndexPath"
|
||||
private let UserInfoKeyNewIndexPath = "UserInfoKeyNewIndexPath"
|
||||
|
||||
private let UserInfoKeySectionInfo = "UserInfoKeySectionInfo"
|
||||
private let UserInfoKeySectionIndex = "UserInfoKeySectionIndex"
|
||||
|
||||
private struct NotificationKey {
|
||||
|
||||
static var willChangeList: Void?
|
||||
static var didChangeList: Void?
|
||||
|
||||
static var didInsertObject: Void?
|
||||
static var didDeleteObject: Void?
|
||||
static var didUpdateObject: Void?
|
||||
static var didMoveObject: Void?
|
||||
|
||||
static var didInsertSection: Void?
|
||||
static var didDeleteSection: Void?
|
||||
}
|
||||
@@ -1,147 +0,0 @@
|
||||
//
|
||||
// ManagedObjectListObserver.swift
|
||||
// CoreStore
|
||||
//
|
||||
// Copyright (c) 2015 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
|
||||
|
||||
|
||||
// MARK: - ManagedObjectListChangeObserver
|
||||
|
||||
/**
|
||||
Implement the `ManagedObjectListChangeObserver` protocol to observe changes to a list of `NSManagedObject`'s. `ManagedObjectListChangeObserver`'s may register themselves to a `ManagedObjectListController`'s `addObserver(_:)` method:
|
||||
|
||||
let listController = CoreStore.observeObjectList(
|
||||
From(MyPersonEntity),
|
||||
OrderBy(.Ascending("lastName"))
|
||||
)
|
||||
listController.addObserver(self)
|
||||
*/
|
||||
public protocol ManagedObjectListChangeObserver: class {
|
||||
|
||||
/**
|
||||
The `NSManagedObject` type for the observed list
|
||||
*/
|
||||
typealias EntityType: NSManagedObject
|
||||
|
||||
/**
|
||||
Handles processing just before a change to the observed list occurs
|
||||
|
||||
:param: listController the `ManagedObjectListController` monitoring the list being observed
|
||||
*/
|
||||
func managedObjectListWillChange(listController: ManagedObjectListController<EntityType>)
|
||||
|
||||
/**
|
||||
Handles processing right after a change to the observed list occurs
|
||||
|
||||
:param: listController the `ManagedObjectListController` monitoring the object being observed
|
||||
*/
|
||||
func managedObjectListDidChange(listController: ManagedObjectListController<EntityType>)
|
||||
}
|
||||
|
||||
|
||||
// MARK: - ManagedObjectListObjectObserver
|
||||
|
||||
/**
|
||||
Implement the `ManagedObjectListObjectObserver` protocol to observe detailed changes to a list's object. `ManagedObjectListObjectObserver`'s may register themselves to a `ManagedObjectListController`'s `addObserver(_:)` method:
|
||||
|
||||
let listController = CoreStore.observeObjectList(
|
||||
From(MyPersonEntity),
|
||||
OrderBy(.Ascending("lastName"))
|
||||
)
|
||||
listController.addObserver(self)
|
||||
*/
|
||||
public protocol ManagedObjectListObjectObserver: ManagedObjectListChangeObserver {
|
||||
|
||||
/**
|
||||
Notifies that an object was inserted to the specified `NSIndexPath` in the list
|
||||
|
||||
:param: listController the `ManagedObjectListController` monitoring the list being observed
|
||||
:param: object the entity type for the inserted object
|
||||
:param: indexPath the new `NSIndexPath` for the inserted object
|
||||
*/
|
||||
func managedObjectList(listController: ManagedObjectListController<EntityType>, didInsertObject object: EntityType, toIndexPath indexPath: NSIndexPath)
|
||||
|
||||
/**
|
||||
Notifies that an object was deleted from the specified `NSIndexPath` in the list
|
||||
|
||||
:param: listController the `ManagedObjectListController` monitoring the list being observed
|
||||
:param: object the entity type for the deleted object
|
||||
:param: indexPath the `NSIndexPath` for the deleted object
|
||||
*/
|
||||
func managedObjectList(listController: ManagedObjectListController<EntityType>, didDeleteObject object: EntityType, fromIndexPath indexPath: NSIndexPath)
|
||||
|
||||
/**
|
||||
Notifies that an object at the specified `NSIndexPath` was updated
|
||||
|
||||
:param: listController the `ManagedObjectListController` monitoring the list being observed
|
||||
:param: object the entity type for the updated object
|
||||
:param: indexPath the `NSIndexPath` for the updated object
|
||||
*/
|
||||
func managedObjectList(listController: ManagedObjectListController<EntityType>, didUpdateObject object: EntityType, atIndexPath indexPath: NSIndexPath)
|
||||
|
||||
/**
|
||||
Notifies that an object's index changed
|
||||
|
||||
:param: listController the `ManagedObjectListController` monitoring the list being observed
|
||||
:param: object the entity type for the moved object
|
||||
:param: fromIndexPath the previous `NSIndexPath` for the moved object
|
||||
:param: toIndexPath the new `NSIndexPath` for the moved object
|
||||
*/
|
||||
func managedObjectList(listController: ManagedObjectListController<EntityType>, didMoveObject object: EntityType, fromIndexPath: NSIndexPath, toIndexPath: NSIndexPath)
|
||||
}
|
||||
|
||||
|
||||
// MARK: - ManagedObjectListSectionObserver
|
||||
|
||||
/**
|
||||
Implement the `ManagedObjectListSectionObserver` protocol to observe changes to a list's section info. `ManagedObjectListSectionObserver`'s may register themselves to a `ManagedObjectListController`'s `addObserver(_:)` method:
|
||||
|
||||
let listController = CoreStore.observeSectionedList(
|
||||
From(MyPersonEntity),
|
||||
SectionedBy("age") { "Age \($0)" },
|
||||
OrderBy(.Ascending("lastName"))
|
||||
)
|
||||
listController.addObserver(self)
|
||||
*/
|
||||
public protocol ManagedObjectListSectionObserver: ManagedObjectListObjectObserver {
|
||||
|
||||
/**
|
||||
Notifies that a section was inserted at the specified index
|
||||
|
||||
:param: listController the `ManagedObjectListController` monitoring the list being observed
|
||||
:param: sectionInfo the `NSFetchedResultsSectionInfo` for the inserted section
|
||||
:param: sectionIndex the new section index for the new section
|
||||
*/
|
||||
func managedObjectList(listController: ManagedObjectListController<EntityType>, didInsertSection sectionInfo: NSFetchedResultsSectionInfo, toSectionIndex sectionIndex: Int)
|
||||
|
||||
/**
|
||||
Notifies that a section was inserted at the specified index
|
||||
|
||||
:param: listController the `ManagedObjectListController` monitoring the list being observed
|
||||
:param: sectionInfo the `NSFetchedResultsSectionInfo` for the deleted section
|
||||
:param: sectionIndex the previous section index for the deleted section
|
||||
*/
|
||||
func managedObjectList(listController: ManagedObjectListController<EntityType>, didDeleteSection sectionInfo: NSFetchedResultsSectionInfo, fromSectionIndex sectionIndex: Int)
|
||||
}
|
||||
@@ -1,69 +0,0 @@
|
||||
//
|
||||
// ManagedObjectObserver.swift
|
||||
// CoreStore
|
||||
//
|
||||
// Copyright (c) 2015 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
|
||||
|
||||
|
||||
// MARK: - ManagedObjectObserver
|
||||
|
||||
/**
|
||||
Implement the `ManagedObjectObserver` protocol to observe changes to a single `NSManagedObject` instance. `ManagedObjectObserver`'s may register themselves to a `ManagedObjectController`'s `addObserver(_:)` method:
|
||||
|
||||
let objectController = CoreStore.observeObject(object)
|
||||
objectController.addObserver(self)
|
||||
*/
|
||||
public protocol ManagedObjectObserver: class {
|
||||
|
||||
/**
|
||||
The `NSManagedObject` type for the observed object
|
||||
*/
|
||||
typealias EntityType: NSManagedObject
|
||||
|
||||
/**
|
||||
Handles processing just before a change to the observed `object` occurs
|
||||
|
||||
:param: objectController the `ManagedObjectController` monitoring the object being observed
|
||||
:param: object the `NSManagedObject` instance being observed
|
||||
*/
|
||||
func managedObjectWillUpdate(objectController: ManagedObjectController<EntityType>, object: EntityType)
|
||||
|
||||
/**
|
||||
Handles processing right after a change to the observed `object` occurs
|
||||
|
||||
:param: objectController the `ManagedObjectController` monitoring the object being observed
|
||||
:param: object the `NSManagedObject` instance being observed
|
||||
:param: changedPersistentKeys a `Set` of key paths for the attributes that were changed. Note that `changedPersistentKeys` only contains keys for attributes/relationships present in the persistent store, thus transient properties will not be reported.
|
||||
*/
|
||||
func managedObjectWasUpdated(objectController: ManagedObjectController<EntityType>, object: EntityType, changedPersistentKeys: Set<KeyPath>)
|
||||
|
||||
/**
|
||||
Handles processing right after `object` is deleted
|
||||
|
||||
:param: objectController the `ManagedObjectController` monitoring the object being observed
|
||||
:param: object the `NSManagedObject` instance being observed
|
||||
*/
|
||||
func managedObjectWasDeleted(objectController: ManagedObjectController<EntityType>, object: EntityType)
|
||||
}
|
||||
@@ -1,220 +0,0 @@
|
||||
//
|
||||
// AsynchronousDataTransaction.swift
|
||||
// CoreStore
|
||||
//
|
||||
// Copyright (c) 2015 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
|
||||
|
||||
|
||||
// MARK: - AsynchronousDataTransaction
|
||||
|
||||
/**
|
||||
The `AsynchronousDataTransaction` 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.beginAsynchronous(_:)`, or from `CoreStore.beginAsynchronous(_:)`.
|
||||
*/
|
||||
public final class AsynchronousDataTransaction: BaseDataTransaction {
|
||||
|
||||
// MARK: Public
|
||||
|
||||
/**
|
||||
Saves the transaction changes asynchronously. This method should not be used after the `commit()` 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) -> Void) {
|
||||
|
||||
CoreStore.assert(self.transactionQueue.isCurrentExecutionContext(), "Attempted to commit a \(typeName(self)) outside its designated queue.")
|
||||
CoreStore.assert(!self.isCommitted, "Attempted to commit a \(typeName(self)) more than once.")
|
||||
|
||||
self.isCommitted = true
|
||||
let semaphore = GCDSemaphore(0)
|
||||
self.context.saveAsynchronouslyWithCompletion { (result) -> Void in
|
||||
|
||||
self.result = result
|
||||
completion(result: result)
|
||||
semaphore.signal()
|
||||
}
|
||||
semaphore.wait()
|
||||
}
|
||||
|
||||
/**
|
||||
Saves the transaction changes and waits for completion synchronously. This method should not be used after the `commit()` method was already called once.
|
||||
*/
|
||||
public func commit() {
|
||||
|
||||
CoreStore.assert(self.transactionQueue.isCurrentExecutionContext(), "Attempted to commit a \(typeName(self)) outside its designated queue.")
|
||||
CoreStore.assert(!self.isCommitted, "Attempted to commit a \(typeName(self)) more than once.")
|
||||
|
||||
self.isCommitted = true
|
||||
self.result = self.context.saveSynchronously()
|
||||
}
|
||||
|
||||
/**
|
||||
Begins a child transaction synchronously where NSManagedObject creates, updates, and deletes can be made. This method should not be used after the `commit()` method was already called once.
|
||||
|
||||
: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, or `nil` if the transaction was not comitted synchronously
|
||||
*/
|
||||
public func beginSynchronous(closure: (transaction: SynchronousDataTransaction) -> Void) -> SaveResult? {
|
||||
|
||||
CoreStore.assert(self.transactionQueue.isCurrentExecutionContext(), "Attempted to begin a child transaction from a \(typeName(self)) outside its designated queue.")
|
||||
CoreStore.assert(!self.isCommitted, "Attempted to begin a child transaction from an already committed \(typeName(self)).")
|
||||
|
||||
return SynchronousDataTransaction(
|
||||
mainContext: self.context,
|
||||
queue: self.childTransactionQueue,
|
||||
closure: closure).performAndWait()
|
||||
}
|
||||
|
||||
|
||||
// MARK: BaseDataTransaction
|
||||
|
||||
/**
|
||||
Creates a new `NSManagedObject` with the specified entity type.
|
||||
|
||||
:param: into the `Into` clause indicating the destination `NSManagedObject` entity type and the destination configuration
|
||||
:returns: a new `NSManagedObject` instance of the specified entity type.
|
||||
*/
|
||||
public override func create<T: NSManagedObject>(into: Into<T>) -> T {
|
||||
|
||||
CoreStore.assert(!self.isCommitted, "Attempted to create an entity of type <\(T.self)> from an already committed \(typeName(self)).")
|
||||
|
||||
return super.create(into)
|
||||
}
|
||||
|
||||
/**
|
||||
Returns an editable proxy of a specified `NSManagedObject`. This method should not be used after the `commit()` method was already called once.
|
||||
|
||||
:param: object the `NSManagedObject` type to be edited
|
||||
:returns: an editable proxy for the specified `NSManagedObject`.
|
||||
*/
|
||||
public override func edit<T: NSManagedObject>(object: T?) -> T? {
|
||||
|
||||
CoreStore.assert(!self.isCommitted, "Attempted to update an entity of type \(typeName(object)) from an already committed \(typeName(self)).")
|
||||
|
||||
return super.edit(object)
|
||||
}
|
||||
|
||||
/**
|
||||
Returns an editable proxy of the object with the specified `NSManagedObjectID`. This method should not be used after the `commit()` method was already called once.
|
||||
|
||||
:param: into an `Into` clause specifying the entity type
|
||||
:param: objectID the `NSManagedObjectID` for the object to be edited
|
||||
:returns: an editable proxy for the specified `NSManagedObject`.
|
||||
*/
|
||||
public override func edit<T: NSManagedObject>(into: Into<T>, _ objectID: NSManagedObjectID) -> T? {
|
||||
|
||||
CoreStore.assert(!self.isCommitted, "Attempted to update an entity of type <\(T.self)> from an already committed \(typeName(self)).")
|
||||
|
||||
return super.edit(into, objectID)
|
||||
}
|
||||
|
||||
/**
|
||||
Deletes a specified `NSManagedObject`. This method should not be used after the `commit()` method was already called once.
|
||||
|
||||
:param: object the `NSManagedObject` type to be deleted
|
||||
*/
|
||||
public override func delete(object: NSManagedObject?) {
|
||||
|
||||
CoreStore.assert(!self.isCommitted, "Attempted to delete an entity of type \(typeName(object)) from an already committed \(typeName(self)).")
|
||||
|
||||
super.delete(object)
|
||||
}
|
||||
|
||||
/**
|
||||
Deletes the specified `NSManagedObject`'s.
|
||||
|
||||
:param: object1 the `NSManagedObject` type to be deleted
|
||||
:param: object2 another `NSManagedObject` type to be deleted
|
||||
:param: objects other `NSManagedObject`s type to be deleted
|
||||
*/
|
||||
public override func delete(object1: NSManagedObject?, _ object2: NSManagedObject?, _ objects: NSManagedObject?...) {
|
||||
|
||||
CoreStore.assert(!self.isCommitted, "Attempted to delete an entities from an already committed \(typeName(self)).")
|
||||
|
||||
super.delete([object1, object2] + objects)
|
||||
}
|
||||
|
||||
/**
|
||||
Deletes the specified `NSManagedObject`'s.
|
||||
|
||||
:param: objects the `NSManagedObject`'s type to be deleted
|
||||
*/
|
||||
public override func delete(objects: [NSManagedObject?]) {
|
||||
|
||||
CoreStore.assert(!self.isCommitted, "Attempted to delete an entities from an already committed \(typeName(self)).")
|
||||
|
||||
super.delete(objects)
|
||||
}
|
||||
|
||||
/**
|
||||
Rolls back the transaction by resetting the `NSManagedObjectContext`. After calling this method, all `NSManagedObjects` fetched within the transaction will become invalid. This method should not be used after the `commit()` method was already called once.
|
||||
*/
|
||||
public override func rollback() {
|
||||
|
||||
CoreStore.assert(!self.isCommitted, "Attempted to rollback an already committed \(typeName(self)).")
|
||||
|
||||
super.rollback()
|
||||
}
|
||||
|
||||
|
||||
// MARK: Internal
|
||||
|
||||
internal init(mainContext: NSManagedObjectContext, queue: GCDQueue, closure: (transaction: AsynchronousDataTransaction) -> Void) {
|
||||
|
||||
self.closure = closure
|
||||
|
||||
super.init(mainContext: mainContext, queue: queue)
|
||||
}
|
||||
|
||||
internal func perform() {
|
||||
|
||||
self.transactionQueue.async {
|
||||
|
||||
self.closure(transaction: self)
|
||||
if !self.isCommitted && self.hasChanges {
|
||||
|
||||
CoreStore.log(.Warning, message: "The closure for the \(typeName(self)) completed without being committed. All changes made within the transaction were discarded.")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
internal func performAndWait() -> SaveResult? {
|
||||
|
||||
self.transactionQueue.sync {
|
||||
|
||||
self.closure(transaction: self)
|
||||
if !self.isCommitted && self.hasChanges {
|
||||
|
||||
CoreStore.log(.Warning, message: "The closure for the \(typeName(self)) completed without being committed. All changes made within the transaction were discarded.")
|
||||
}
|
||||
}
|
||||
return self.result
|
||||
}
|
||||
|
||||
|
||||
// MARK: Private
|
||||
|
||||
private let closure: (transaction: AsynchronousDataTransaction) -> Void
|
||||
}
|
||||
@@ -1,285 +0,0 @@
|
||||
//
|
||||
// BaseDataTransaction.swift
|
||||
// CoreStore
|
||||
//
|
||||
// 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
|
||||
|
||||
|
||||
// MARK: - Into
|
||||
|
||||
/**
|
||||
A `Into` clause contains the destination entity and destination persistent store for a `create(...)` method. A common usage is to just indicate the entity:
|
||||
|
||||
let person = transaction.create(Into(MyPersonEntity))
|
||||
|
||||
For cases where multiple `NSPersistentStore`'s contain the same entity, the destination configuration's name needs to be specified as well:
|
||||
|
||||
let person = transaction.create(Into<MyPersonEntity>("Configuration1"))
|
||||
|
||||
This helps the `NSManagedObjectContext` to determine which
|
||||
*/
|
||||
public struct Into<T: NSManagedObject> {
|
||||
|
||||
// MARK: Public
|
||||
|
||||
internal static var defaultConfigurationName: String {
|
||||
|
||||
return "PF_DEFAULT_CONFIGURATION_NAME"
|
||||
}
|
||||
|
||||
/**
|
||||
Initializes an `Into` clause.
|
||||
Sample Usage:
|
||||
|
||||
let person = transaction.create(Into<MyPersonEntity>())
|
||||
*/
|
||||
public init(){
|
||||
|
||||
self.configuration = nil
|
||||
self.inferStoreIfPossible = true
|
||||
}
|
||||
|
||||
/**
|
||||
Initializes an `Into` clause with the specified entity type.
|
||||
Sample Usage:
|
||||
|
||||
let person = transaction.create(Into(MyPersonEntity))
|
||||
|
||||
:param: entity the `NSManagedObject` type to be created
|
||||
*/
|
||||
public init(_ entity: T.Type) {
|
||||
|
||||
self.configuration = nil
|
||||
self.inferStoreIfPossible = true
|
||||
}
|
||||
|
||||
/**
|
||||
Initializes an `Into` clause with the specified configuration.
|
||||
Sample Usage:
|
||||
|
||||
let person = transaction.create(Into<MyPersonEntity>("Configuration1"))
|
||||
|
||||
:param: configuration the `NSPersistentStore` configuration name to associate the object to. This parameter is required if multiple configurations contain the created `NSManagedObject`'s entity type. Set to `nil` to use the default configuration.
|
||||
*/
|
||||
public init(_ configuration: String?) {
|
||||
|
||||
self.configuration = configuration
|
||||
self.inferStoreIfPossible = false
|
||||
}
|
||||
|
||||
/**
|
||||
Initializes an `Into` clause with the specified entity type and configuration.
|
||||
Sample Usage:
|
||||
|
||||
let person = transaction.create(Into(MyPersonEntity.self, "Configuration1"))
|
||||
|
||||
:param: entity the `NSManagedObject` type to be created
|
||||
:param: configuration the `NSPersistentStore` configuration name to associate the object to. This parameter is required if multiple configurations contain the created `NSManagedObject`'s entity type. Set to `nil` to use the default configuration.
|
||||
*/
|
||||
public init(_ entity: T.Type, _ configuration: String?) {
|
||||
|
||||
self.configuration = configuration
|
||||
self.inferStoreIfPossible = false
|
||||
}
|
||||
|
||||
|
||||
// MARK: Internal
|
||||
|
||||
internal let configuration: String?
|
||||
internal let inferStoreIfPossible: Bool
|
||||
}
|
||||
|
||||
|
||||
// MARK: - BaseDataTransaction
|
||||
|
||||
/**
|
||||
The `BaseDataTransaction` is an abstract interface for `NSManagedObject` creates, updates, and deletes. All `BaseDataTransaction` subclasses manage a private `NSManagedObjectContext` which are direct children of the `NSPersistentStoreCoordinator`'s root `NSManagedObjectContext`. This means that all updates are saved first to the persistent store, and then propagated up to the read-only `NSManagedObjectContext`.
|
||||
*/
|
||||
public /*abstract*/ class BaseDataTransaction {
|
||||
|
||||
// MARK: Object management
|
||||
|
||||
/**
|
||||
Indicates if the transaction has pending changes
|
||||
*/
|
||||
public var hasChanges: Bool {
|
||||
|
||||
return self.context.hasChanges
|
||||
}
|
||||
|
||||
/**
|
||||
Creates a new `NSManagedObject` with the specified entity type.
|
||||
|
||||
:param: into the `Into` clause indicating the destination `NSManagedObject` entity type and the destination configuration
|
||||
:returns: a new `NSManagedObject` instance of the specified entity type.
|
||||
*/
|
||||
public func create<T: NSManagedObject>(into: Into<T>) -> T {
|
||||
|
||||
CoreStore.assert(self.transactionQueue.isCurrentExecutionContext(), "Attempted to create an entity of type <\(T.self)> outside its designated queue.")
|
||||
|
||||
let context = self.context
|
||||
let object = T.createInContext(context)
|
||||
|
||||
if into.inferStoreIfPossible {
|
||||
|
||||
switch context.parentStack!.persistentStoreForEntityClass(T.self, configuration: nil, inferStoreIfPossible: true) {
|
||||
|
||||
case (.Some(let persistentStore), _):
|
||||
context.assignObject(object, toPersistentStore: persistentStore)
|
||||
|
||||
case (.None, true):
|
||||
CoreStore.assert(false, "Attempted to create an entity of type \(typeName(object)) with ambiguous destination persistent store, but the configuration name was not specified.")
|
||||
|
||||
default:
|
||||
CoreStore.assert(false, "Attempted to create an entity of type \(typeName(object)), but a destination persistent store containing the entity type could not be found.")
|
||||
}
|
||||
}
|
||||
else {
|
||||
|
||||
switch context.parentStack!.persistentStoreForEntityClass(T.self, configuration: into.configuration, inferStoreIfPossible: false) {
|
||||
|
||||
case (.Some(let persistentStore), _):
|
||||
context.assignObject(object, toPersistentStore: persistentStore)
|
||||
|
||||
default:
|
||||
if let configuration = into.configuration {
|
||||
|
||||
CoreStore.assert(false, "Attempted to create an entity of type \(typeName(object)) into the configuration \"\(configuration)\", which it doesn't belong to.")
|
||||
}
|
||||
else {
|
||||
|
||||
CoreStore.assert(false, "Attempted to create an entity of type \(typeName(object)) into the default configuration, which it doesn't belong to.")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return object
|
||||
}
|
||||
|
||||
/**
|
||||
Returns an editable proxy of a specified `NSManagedObject`.
|
||||
|
||||
:param: object the `NSManagedObject` type to be edited
|
||||
:returns: an editable proxy for the specified `NSManagedObject`.
|
||||
*/
|
||||
public func edit<T: NSManagedObject>(object: T?) -> T? {
|
||||
|
||||
CoreStore.assert(self.transactionQueue.isCurrentExecutionContext(), "Attempted to update an entity of type \(typeName(object)) outside its designated queue.")
|
||||
|
||||
return object?.inContext(self.context)
|
||||
}
|
||||
|
||||
/**
|
||||
Returns an editable proxy of the object with the specified `NSManagedObjectID`.
|
||||
|
||||
:param: into an `Into` clause specifying the entity type
|
||||
:param: objectID the `NSManagedObjectID` for the object to be edited
|
||||
:returns: an editable proxy for the specified `NSManagedObject`.
|
||||
*/
|
||||
public func edit<T: NSManagedObject>(into: Into<T>, _ objectID: NSManagedObjectID) -> T? {
|
||||
|
||||
CoreStore.assert(self.transactionQueue.isCurrentExecutionContext(), "Attempted to update an entity of type <\(T.self)> outside its designated queue.")
|
||||
CoreStore.assert(into.inferStoreIfPossible || (into.configuration ?? Into.defaultConfigurationName) == objectID.persistentStore?.configurationName, "Attempted to update an entity of type <\(T.self)> but the specified persistent store do not match the `NSManagedObjectID`.")
|
||||
|
||||
return T.inContext(self.context, withObjectID: objectID)
|
||||
}
|
||||
|
||||
/**
|
||||
Deletes a specified `NSManagedObject`.
|
||||
|
||||
:param: object the `NSManagedObject` type to be deleted
|
||||
*/
|
||||
public func delete(object: NSManagedObject?) {
|
||||
|
||||
CoreStore.assert(self.transactionQueue.isCurrentExecutionContext(), "Attempted to delete an entity outside its designated queue.")
|
||||
|
||||
object?.inContext(self.context)?.deleteFromContext()
|
||||
}
|
||||
|
||||
/**
|
||||
Deletes the specified `NSManagedObject`'s.
|
||||
|
||||
:param: object1 the `NSManagedObject` type to be deleted
|
||||
:param: object2 another `NSManagedObject` type to be deleted
|
||||
:param: objects other `NSManagedObject`s type to be deleted
|
||||
*/
|
||||
public func delete(object1: NSManagedObject?, _ object2: NSManagedObject?, _ objects: NSManagedObject?...) {
|
||||
|
||||
self.delete([object1, object2] + objects)
|
||||
}
|
||||
|
||||
/**
|
||||
Deletes the specified `NSManagedObject`'s.
|
||||
|
||||
:param: objects the `NSManagedObject`'s type to be deleted
|
||||
*/
|
||||
public func delete(objects: [NSManagedObject?]) {
|
||||
|
||||
CoreStore.assert(self.transactionQueue.isCurrentExecutionContext(), "Attempted to delete entities outside their designated queue.")
|
||||
|
||||
let context = self.context
|
||||
for object in objects {
|
||||
|
||||
object?.inContext(context)?.deleteFromContext()
|
||||
}
|
||||
}
|
||||
|
||||
// MARK: Saving changes
|
||||
|
||||
/**
|
||||
Rolls back the transaction by resetting the `NSManagedObjectContext`. After calling this method, all `NSManagedObjects` fetched within the transaction will become invalid.
|
||||
*/
|
||||
public func rollback() {
|
||||
|
||||
CoreStore.assert(self.transactionQueue.isCurrentExecutionContext(), "Attempted to rollback a \(typeName(self)) outside its designated queue.")
|
||||
|
||||
self.context.reset()
|
||||
}
|
||||
|
||||
|
||||
// MARK: Internal
|
||||
|
||||
internal let context: NSManagedObjectContext
|
||||
internal let transactionQueue: GCDQueue
|
||||
internal let childTransactionQueue: GCDQueue = .createSerial("com.corestore.datastack.childtransactionqueue")
|
||||
|
||||
internal var isCommitted = false
|
||||
internal var result: SaveResult?
|
||||
|
||||
internal init(mainContext: NSManagedObjectContext, queue: GCDQueue) {
|
||||
|
||||
self.transactionQueue = queue
|
||||
|
||||
let context = mainContext.temporaryContextInTransactionWithConcurrencyType(
|
||||
queue == .Main
|
||||
? .MainQueueConcurrencyType
|
||||
: .PrivateQueueConcurrencyType
|
||||
)
|
||||
self.context = context
|
||||
|
||||
context.parentTransaction = self
|
||||
}
|
||||
}
|
||||
@@ -1,65 +0,0 @@
|
||||
//
|
||||
// CoreStore+Transaction.swift
|
||||
// CoreStore
|
||||
//
|
||||
// Copyright (c) 2015 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
|
||||
|
||||
|
||||
// MARK: - CoreStore
|
||||
|
||||
public extension CoreStore {
|
||||
|
||||
// MARK: Public
|
||||
|
||||
/**
|
||||
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 beginAsynchronous(closure: (transaction: AsynchronousDataTransaction) -> Void) {
|
||||
|
||||
self.defaultStack.beginAsynchronous(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, or `nil` if the transaction was not comitted synchronously
|
||||
*/
|
||||
public static func beginSynchronous(closure: (transaction: SynchronousDataTransaction) -> Void) -> SaveResult? {
|
||||
|
||||
return self.defaultStack.beginSynchronous(closure)
|
||||
}
|
||||
|
||||
/**
|
||||
Using the `defaultStack`, begins a non-contiguous transaction where `NSManagedObject` creates, updates, and deletes can be made. This is useful for making temporary changes, such as partially filled forms. A detached transaction object should typically be only used from the main queue.
|
||||
|
||||
:returns: a `DetachedDataTransaction` instance where creates, updates, and deletes can be made.
|
||||
*/
|
||||
public static func beginDetached() -> DetachedDataTransaction {
|
||||
|
||||
return self.defaultStack.beginDetached()
|
||||
}
|
||||
}
|
||||
@@ -1,75 +0,0 @@
|
||||
//
|
||||
// DataStack+Transaction.swift
|
||||
// CoreStore
|
||||
//
|
||||
// Copyright (c) 2015 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
|
||||
|
||||
|
||||
// MARK: - DataStack
|
||||
|
||||
public extension DataStack {
|
||||
|
||||
// MARK: Public
|
||||
|
||||
/**
|
||||
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 beginAsynchronous(closure: (transaction: AsynchronousDataTransaction) -> Void) {
|
||||
|
||||
AsynchronousDataTransaction(
|
||||
mainContext: self.rootSavingContext,
|
||||
queue: self.childTransactionQueue,
|
||||
closure: closure).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, or `nil` if the transaction was not comitted synchronously
|
||||
*/
|
||||
public func beginSynchronous(closure: (transaction: SynchronousDataTransaction) -> Void) -> SaveResult? {
|
||||
|
||||
return SynchronousDataTransaction(
|
||||
mainContext: self.rootSavingContext,
|
||||
queue: self.childTransactionQueue,
|
||||
closure: closure).performAndWait()
|
||||
}
|
||||
|
||||
/**
|
||||
Begins a non-contiguous transaction where `NSManagedObject` creates, updates, and deletes can be made. This is useful for making temporary changes, such as partially filled forms. A detached transaction object should typically be only used from the main queue.
|
||||
|
||||
:returns: a `DetachedDataTransaction` instance where creates, updates, and deletes can be made.
|
||||
*/
|
||||
public func beginDetached() -> DetachedDataTransaction {
|
||||
|
||||
return DetachedDataTransaction(
|
||||
mainContext: self.rootSavingContext,
|
||||
queue: .Main)
|
||||
}
|
||||
}
|
||||
@@ -1,55 +0,0 @@
|
||||
//
|
||||
// DetachedDataTransaction.swift
|
||||
// CoreStore
|
||||
//
|
||||
// Copyright (c) 2015 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 GCDKit
|
||||
|
||||
|
||||
// MARK: - DetachedDataTransaction
|
||||
|
||||
/**
|
||||
The `DetachedDataTransaction` provides an interface for non-contiguous `NSManagedObject` creates, updates, and deletes. This is useful for making temporary changes, such as partially filled forms. A detached transaction object should typically be only used from the main queue.
|
||||
*/
|
||||
public final class DetachedDataTransaction: BaseDataTransaction {
|
||||
|
||||
// MARK: Public
|
||||
|
||||
/**
|
||||
Saves the transaction changes asynchronously. For a `DetachedDataTransaction`, multiple commits are allowed, although it is the developer's responsibility to ensure a reasonable leeway to prevent blocking the main thread.
|
||||
|
||||
: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) -> Void) {
|
||||
|
||||
CoreStore.assert(self.transactionQueue.isCurrentExecutionContext(), "Attempted to commit a \(typeName(self)) outside its designated queue.")
|
||||
|
||||
self.context.saveAsynchronouslyWithCompletion { (result) -> Void in
|
||||
|
||||
self.result = result
|
||||
completion(result: result)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,112 +0,0 @@
|
||||
//
|
||||
// SaveResult.swift
|
||||
// CoreStore
|
||||
//
|
||||
// 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
|
||||
|
||||
|
||||
// MARK: - SaveResult
|
||||
|
||||
/**
|
||||
The `SaveResult` indicates the result of a `commit(...)` for a transaction.
|
||||
The `SaveResult` can be treated as a boolean:
|
||||
|
||||
CoreStore.beginAsynchronous { transaction in
|
||||
// ...
|
||||
let result = transaction.commit()
|
||||
if result {
|
||||
// succeeded
|
||||
}
|
||||
else {
|
||||
// failed
|
||||
}
|
||||
}
|
||||
|
||||
or as an `enum`, where the resulting associated object can also be inspected:
|
||||
|
||||
CoreStore.beginAsynchronous { transaction in
|
||||
// ...
|
||||
let result = transaction.commit()
|
||||
switch result {
|
||||
case .Success(let hasChanges):
|
||||
// hasChanges indicates if there were changes or not
|
||||
case .Failure(let error):
|
||||
// error is the NSError instance for the failure
|
||||
}
|
||||
}
|
||||
```
|
||||
*/
|
||||
public enum SaveResult {
|
||||
|
||||
// MARK: Public
|
||||
|
||||
/**
|
||||
`SaveResult.Success` indicates that the `commit()` for the transaction succeeded, either because the save succeeded or because there were no changes to save. The associated value `hasChanges` indicates if there were saved changes or not.
|
||||
*/
|
||||
case Success(hasChanges: Bool)
|
||||
|
||||
/**
|
||||
`SaveResult.Failure` indicates that the `commit()` for the transaction failed. The associated object for this value is the related `NSError` instance.
|
||||
*/
|
||||
case Failure(NSError)
|
||||
|
||||
|
||||
// MARK: Internal
|
||||
|
||||
internal init(hasChanges: Bool) {
|
||||
|
||||
self = .Success(hasChanges: hasChanges)
|
||||
}
|
||||
|
||||
internal init(_ error: NSError) {
|
||||
|
||||
self = .Failure(error)
|
||||
}
|
||||
|
||||
internal init(_ errorCode: CoreStoreErrorCode) {
|
||||
|
||||
self.init(errorCode, userInfo: nil)
|
||||
}
|
||||
|
||||
internal init(_ errorCode: CoreStoreErrorCode, userInfo: [NSObject: AnyObject]?) {
|
||||
|
||||
self.init(NSError(
|
||||
coreStoreErrorCode: errorCode,
|
||||
userInfo: userInfo))
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// MARK: - SaveResult: BooleanType
|
||||
|
||||
extension SaveResult: BooleanType {
|
||||
|
||||
public var boolValue: Bool {
|
||||
|
||||
switch self {
|
||||
case .Success: return true
|
||||
case .Failure: return false
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,187 +0,0 @@
|
||||
//
|
||||
// SynchronousDataTransaction.swift
|
||||
// CoreStore
|
||||
//
|
||||
// Copyright (c) 2015 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
|
||||
|
||||
|
||||
// MARK: - SynchronousDataTransaction
|
||||
|
||||
/**
|
||||
The `SynchronousDataTransaction` 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.beginSynchronous(_:)`, or from `CoreStore.beginSynchronous(_:)`.
|
||||
*/
|
||||
public final class SynchronousDataTransaction: BaseDataTransaction {
|
||||
|
||||
// MARK: Public
|
||||
|
||||
/**
|
||||
Saves the transaction changes and waits for completion synchronously. This method should not be used after the `commit()` method was already called once.
|
||||
*/
|
||||
public func commit() {
|
||||
|
||||
CoreStore.assert(self.transactionQueue.isCurrentExecutionContext(), "Attempted to commit a \(typeName(self)) outside its designated queue.")
|
||||
CoreStore.assert(!self.isCommitted, "Attempted to commit a \(typeName(self)) more than once.")
|
||||
|
||||
self.isCommitted = true
|
||||
self.result = self.context.saveSynchronously()
|
||||
}
|
||||
|
||||
/**
|
||||
Begins a child transaction synchronously where `NSManagedObject` creates, updates, and deletes can be made. This method should not be used after the `commit()` method was already called once.
|
||||
|
||||
: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, or `nil` if the transaction was not comitted synchronously
|
||||
*/
|
||||
public func beginSynchronous(closure: (transaction: SynchronousDataTransaction) -> Void) -> SaveResult? {
|
||||
|
||||
CoreStore.assert(self.transactionQueue.isCurrentExecutionContext(), "Attempted to begin a child transaction from a \(typeName(self)) outside its designated queue.")
|
||||
CoreStore.assert(!self.isCommitted, "Attempted to begin a child transaction from an already committed \(typeName(self)).")
|
||||
|
||||
return SynchronousDataTransaction(
|
||||
mainContext: self.context,
|
||||
queue: self.childTransactionQueue,
|
||||
closure: closure).performAndWait()
|
||||
}
|
||||
|
||||
|
||||
// MARK: BaseDataTransaction
|
||||
|
||||
/**
|
||||
Creates a new `NSManagedObject` with the specified entity type.
|
||||
|
||||
:param: into the `Into` clause indicating the destination `NSManagedObject` entity type and the destination configuration
|
||||
:returns: a new `NSManagedObject` instance of the specified entity type.
|
||||
*/
|
||||
public override func create<T: NSManagedObject>(into: Into<T>) -> T {
|
||||
|
||||
CoreStore.assert(!self.isCommitted, "Attempted to create an entity of type <\(T.self)> from an already committed \(typeName(self)).")
|
||||
|
||||
return super.create(into)
|
||||
}
|
||||
|
||||
/**
|
||||
Returns an editable proxy of a specified `NSManagedObject`. This method should not be used after the `commit()` method was already called once.
|
||||
|
||||
:param: object the `NSManagedObject` type to be edited
|
||||
:returns: an editable proxy for the specified `NSManagedObject`.
|
||||
*/
|
||||
public override func edit<T: NSManagedObject>(object: T?) -> T? {
|
||||
|
||||
CoreStore.assert(!self.isCommitted, "Attempted to update an entity of type \(typeName(object)) from an already committed \(typeName(self)).")
|
||||
|
||||
return super.edit(object)
|
||||
}
|
||||
|
||||
/**
|
||||
Returns an editable proxy of the object with the specified `NSManagedObjectID`. This method should not be used after the `commit()` method was already called once.
|
||||
|
||||
:param: into an `Into` clause specifying the entity type
|
||||
:param: objectID the `NSManagedObjectID` for the object to be edited
|
||||
:returns: an editable proxy for the specified `NSManagedObject`.
|
||||
*/
|
||||
public override func edit<T: NSManagedObject>(into: Into<T>, _ objectID: NSManagedObjectID) -> T? {
|
||||
|
||||
CoreStore.assert(!self.isCommitted, "Attempted to update an entity of type <\(T.self)> from an already committed \(typeName(self)).")
|
||||
|
||||
return super.edit(into, objectID)
|
||||
}
|
||||
|
||||
/**
|
||||
Deletes a specified `NSManagedObject`. This method should not be used after the `commit()` method was already called once.
|
||||
|
||||
:param: object the `NSManagedObject` type to be deleted
|
||||
*/
|
||||
public override func delete(object: NSManagedObject?) {
|
||||
|
||||
CoreStore.assert(!self.isCommitted, "Attempted to delete an entity of type \(typeName(object)) from an already committed \(typeName(self)).")
|
||||
|
||||
super.delete(object)
|
||||
}
|
||||
|
||||
/**
|
||||
Deletes the specified `NSManagedObject`'s.
|
||||
|
||||
:param: object1 the `NSManagedObject` type to be deleted
|
||||
:param: object2 another `NSManagedObject` type to be deleted
|
||||
:param: objects other `NSManagedObject`s type to be deleted
|
||||
*/
|
||||
public override func delete(object1: NSManagedObject?, _ object2: NSManagedObject?, _ objects: NSManagedObject?...) {
|
||||
|
||||
CoreStore.assert(!self.isCommitted, "Attempted to delete an entities from an already committed \(typeName(self)).")
|
||||
|
||||
super.delete([object1, object2] + objects)
|
||||
}
|
||||
|
||||
/**
|
||||
Deletes the specified `NSManagedObject`'s.
|
||||
|
||||
:param: objects the `NSManagedObject`'s type to be deleted
|
||||
*/
|
||||
public override func delete(objects: [NSManagedObject?]) {
|
||||
|
||||
CoreStore.assert(!self.isCommitted, "Attempted to delete an entities from an already committed \(typeName(self)).")
|
||||
|
||||
super.delete(objects)
|
||||
}
|
||||
|
||||
/**
|
||||
Rolls back the transaction by resetting the `NSManagedObjectContext`. After calling this method, all `NSManagedObjects` fetched within the transaction will become invalid. This method should not be used after the `commit()` method was already called once.
|
||||
*/
|
||||
public override func rollback() {
|
||||
|
||||
CoreStore.assert(!self.isCommitted, "Attempted to rollback an already committed \(typeName(self)).")
|
||||
|
||||
super.rollback()
|
||||
}
|
||||
|
||||
|
||||
// MARK: Internal
|
||||
|
||||
internal func performAndWait() -> SaveResult? {
|
||||
|
||||
self.transactionQueue.sync {
|
||||
|
||||
self.closure(transaction: self)
|
||||
if !self.isCommitted && self.hasChanges {
|
||||
|
||||
CoreStore.log(.Warning, message: "The closure for the \(typeName(self)) completed without being committed. All changes made within the transaction were discarded.")
|
||||
}
|
||||
}
|
||||
return self.result
|
||||
}
|
||||
|
||||
internal init(mainContext: NSManagedObjectContext, queue: GCDQueue, closure: (transaction: SynchronousDataTransaction) -> Void) {
|
||||
|
||||
self.closure = closure
|
||||
|
||||
super.init(mainContext: mainContext, queue: queue)
|
||||
}
|
||||
|
||||
|
||||
// MARK: Private
|
||||
|
||||
private let closure: (transaction: SynchronousDataTransaction) -> Void
|
||||
}
|
||||
@@ -1,84 +0,0 @@
|
||||
//
|
||||
// CoreStore+Setup.swift
|
||||
// CoreStore
|
||||
//
|
||||
// Copyright (c) 2015 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
|
||||
|
||||
|
||||
// MARK: - CoreStore
|
||||
|
||||
public extension CoreStore {
|
||||
|
||||
/**
|
||||
Adds an in-memory store to the `defaultStack`.
|
||||
|
||||
:param: configuration an optional configuration name from the model file. If not specified, defaults to nil.
|
||||
:returns: a `PersistentStoreResult` indicating success or failure.
|
||||
*/
|
||||
public static func addInMemoryStore(configuration: String? = nil) -> PersistentStoreResult {
|
||||
|
||||
return self.defaultStack.addInMemoryStore(configuration: configuration)
|
||||
}
|
||||
|
||||
/**
|
||||
Adds to the `defaultStack` 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 static func addSQLiteStoreAndWait(fileName: String, configuration: String? = nil, automigrating: Bool = true, resetStoreOnMigrationFailure: Bool = false) -> PersistentStoreResult {
|
||||
|
||||
return self.defaultStack.addSQLiteStoreAndWait(
|
||||
fileName,
|
||||
configuration: configuration,
|
||||
automigrating: automigrating,
|
||||
resetStoreOnMigrationFailure: resetStoreOnMigrationFailure
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
Adds to the `defaultStack` 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 static func addSQLiteStoreAndWait(fileURL: NSURL = defaultSQLiteStoreURL, configuration: String? = nil, automigrating: Bool = true, resetStoreOnMigrationFailure: Bool = false) -> PersistentStoreResult {
|
||||
|
||||
return self.defaultStack.addSQLiteStoreAndWait(
|
||||
fileURL: fileURL,
|
||||
configuration: configuration,
|
||||
automigrating: automigrating,
|
||||
resetStoreOnMigrationFailure: resetStoreOnMigrationFailure
|
||||
)
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,361 +0,0 @@
|
||||
//
|
||||
// DataStack.swift
|
||||
// CoreStore
|
||||
//
|
||||
// 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
|
||||
|
||||
|
||||
internal let applicationSupportDirectory = NSFileManager.defaultManager().URLsForDirectory(.ApplicationSupportDirectory, inDomains: .UserDomainMask).first as! NSURL
|
||||
|
||||
internal let applicationName = ((NSBundle.mainBundle().objectForInfoDictionaryKey("CFBundleName") as? String) ?? "CoreData")
|
||||
|
||||
internal let defaultSQLiteStoreURL = applicationSupportDirectory.URLByAppendingPathComponent(applicationName, isDirectory: false).URLByAppendingPathExtension("sqlite")
|
||||
|
||||
|
||||
// MARK: - DataStack
|
||||
|
||||
/**
|
||||
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` designed as a read-only model interface for `NSManagedObjects`.
|
||||
*/
|
||||
public final class DataStack {
|
||||
|
||||
// MARK: Public
|
||||
|
||||
/**
|
||||
Initializes a `DataStack` from a model created by merging all the models found in all bundles.
|
||||
*/
|
||||
public convenience init() {
|
||||
|
||||
let mergedModel: NSManagedObjectModel! = NSManagedObjectModel.mergedModelFromBundles(NSBundle.allBundles())
|
||||
CoreStore.assert(mergedModel != nil, "Could not create a merged <\(NSManagedObjectModel.self)> from all bundles.")
|
||||
|
||||
self.init(managedObjectModel: mergedModel)
|
||||
}
|
||||
|
||||
/**
|
||||
Initializes a `DataStack` from the specified model name.
|
||||
|
||||
:param: modelName the name of the (.xcdatamodeld) model file.
|
||||
*/
|
||||
public convenience init(modelName: String) {
|
||||
|
||||
let modelFilePath: String! = NSBundle.mainBundle().pathForResource(modelName, ofType: "momd")
|
||||
CoreStore.assert(modelFilePath != nil, "Could not find a \"momd\" resource from the main bundle.")
|
||||
|
||||
let managedObjectModel: NSManagedObjectModel! = NSManagedObjectModel(contentsOfURL: NSURL(fileURLWithPath: modelFilePath)!)
|
||||
CoreStore.assert(managedObjectModel != nil, "Could not create an <\(NSManagedObjectModel.self)> from the resource at path \"\(modelFilePath)\".")
|
||||
|
||||
self.init(managedObjectModel: managedObjectModel)
|
||||
}
|
||||
|
||||
/**
|
||||
Initializes a `DataStack` from an `NSManagedObjectModel`.
|
||||
|
||||
:param: managedObjectModel the `NSManagedObjectModel` of the (.xcdatamodeld) model file.
|
||||
*/
|
||||
public required init(managedObjectModel: NSManagedObjectModel) {
|
||||
|
||||
self.coordinator = NSPersistentStoreCoordinator(managedObjectModel: managedObjectModel)
|
||||
self.rootSavingContext = NSManagedObjectContext.rootSavingContextForCoordinator(self.coordinator)
|
||||
self.mainContext = NSManagedObjectContext.mainContextForRootContext(self.rootSavingContext)
|
||||
|
||||
var entityNameMapping = [EntityClassNameType: EntityNameType]()
|
||||
var entityConfigurationsMapping = [EntityClassNameType: Set<String>]()
|
||||
for entityDescription in managedObjectModel.entities as! [NSEntityDescription] {
|
||||
|
||||
let managedObjectClassName = entityDescription.managedObjectClassName
|
||||
entityConfigurationsMapping[managedObjectClassName] = []
|
||||
if let entityName = entityDescription.name {
|
||||
|
||||
entityNameMapping[managedObjectClassName] = entityName
|
||||
}
|
||||
}
|
||||
self.entityNameMapping = entityNameMapping
|
||||
self.entityConfigurationsMapping = entityConfigurationsMapping
|
||||
|
||||
self.rootSavingContext.parentStack = self
|
||||
}
|
||||
|
||||
/**
|
||||
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 error: NSError?
|
||||
|
||||
var store: NSPersistentStore?
|
||||
coordinator.performBlockAndWait {
|
||||
|
||||
store = coordinator.addPersistentStoreWithType(
|
||||
NSInMemoryStoreType,
|
||||
configuration: configuration,
|
||||
URL: nil,
|
||||
options: nil,
|
||||
error: &error)
|
||||
}
|
||||
|
||||
if let store = store {
|
||||
|
||||
self.updateMetadataForPersistentStore(store)
|
||||
return PersistentStoreResult(store)
|
||||
}
|
||||
|
||||
if let error = error {
|
||||
|
||||
CoreStore.handleError(
|
||||
error,
|
||||
"Failed to add in-memory <\(NSPersistentStore.self)>.")
|
||||
return PersistentStoreResult(error)
|
||||
}
|
||||
else {
|
||||
|
||||
CoreStore.handleError(
|
||||
NSError(coreStoreErrorCode: .UnknownError),
|
||||
"Failed to add in-memory <\(NSPersistentStore.self)>.")
|
||||
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. Note that if you have multiple configurations, you will need to specify a different `fileName` explicitly for each of them.
|
||||
:param: configuration an optional configuration name from the model file. If not specified, defaults to `nil`, the "Default" configuration. Note that if you have multiple configurations, you will need to specify a different `fileName` explicitly for each of them.
|
||||
: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 addSQLiteStoreAndWait(fileName: String, configuration: String? = nil, automigrating: Bool = true, resetStoreOnMigrationFailure: Bool = false) -> PersistentStoreResult {
|
||||
|
||||
return self.addSQLiteStoreAndWait(
|
||||
fileURL: 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. Note that if you have multiple configurations, you will need to specify a different `fileURL` explicitly for each of them.
|
||||
:param: configuration an optional configuration name from the model file. If not specified, defaults to `nil`, the "Default" configuration. Note that if you have multiple configurations, you will need to specify a different `fileURL` explicitly for each of them.
|
||||
: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 addSQLiteStoreAndWait(fileURL: NSURL = defaultSQLiteStoreURL, 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
|
||||
&& store.configurationName == (configuration ?? Into.defaultConfigurationName) {
|
||||
|
||||
return PersistentStoreResult(store)
|
||||
}
|
||||
|
||||
CoreStore.handleError(
|
||||
NSError(coreStoreErrorCode: .DifferentPersistentStoreExistsAtURL),
|
||||
"Failed to add SQLite <\(NSPersistentStore.self)> at \"\(fileURL)\" because a different <\(NSPersistentStore.self)> 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) {
|
||||
|
||||
CoreStore.handleError(
|
||||
directoryError ?? NSError(coreStoreErrorCode: .UnknownError),
|
||||
"Failed to create directory for SQLite store at \"\(fileURL)\".")
|
||||
return PersistentStoreResult(directoryError!)
|
||||
}
|
||||
|
||||
var store: NSPersistentStore?
|
||||
var persistentStoreError: NSError?
|
||||
coordinator.performBlockAndWait {
|
||||
|
||||
store = coordinator.addPersistentStoreWithType(
|
||||
NSSQLiteStoreType,
|
||||
configuration: configuration,
|
||||
URL: fileURL,
|
||||
options: [NSSQLitePragmasOption: ["WAL": "journal_mode"],
|
||||
NSInferMappingModelAutomaticallyOption: true,
|
||||
NSMigratePersistentStoresAutomaticallyOption: automigrating],
|
||||
error: &persistentStoreError)
|
||||
}
|
||||
|
||||
if let store = store {
|
||||
|
||||
self.updateMetadataForPersistentStore(store)
|
||||
return PersistentStoreResult(store)
|
||||
}
|
||||
|
||||
if let error = persistentStoreError
|
||||
where (
|
||||
resetStoreOnMigrationFailure
|
||||
&& (error.code == NSPersistentStoreIncompatibleVersionHashError
|
||||
|| error.code == NSMigrationMissingSourceModelError
|
||||
|| error.code == NSMigrationError)
|
||||
&& error.domain == NSCocoaErrorDomain
|
||||
) {
|
||||
|
||||
fileManager.removeItemAtURL(fileURL, error: nil)
|
||||
fileManager.removeItemAtPath(
|
||||
fileURL.path!.stringByAppendingString("-shm"),
|
||||
error: nil)
|
||||
fileManager.removeItemAtPath(
|
||||
fileURL.path!.stringByAppendingString("-wal"),
|
||||
error: nil)
|
||||
|
||||
var store: NSPersistentStore?
|
||||
coordinator.performBlockAndWait {
|
||||
|
||||
store = coordinator.addPersistentStoreWithType(
|
||||
NSSQLiteStoreType,
|
||||
configuration: configuration,
|
||||
URL: fileURL,
|
||||
options: [NSSQLitePragmasOption: ["WAL": "journal_mode"],
|
||||
NSInferMappingModelAutomaticallyOption: true,
|
||||
NSMigratePersistentStoresAutomaticallyOption: automigrating],
|
||||
error: &persistentStoreError)
|
||||
}
|
||||
|
||||
if let store = store {
|
||||
|
||||
self.updateMetadataForPersistentStore(store)
|
||||
return PersistentStoreResult(store)
|
||||
}
|
||||
}
|
||||
|
||||
CoreStore.handleError(
|
||||
persistentStoreError ?? NSError(coreStoreErrorCode: .UnknownError),
|
||||
"Failed to add SQLite <\(NSPersistentStore.self)> at \"\(fileURL)\".")
|
||||
|
||||
return PersistentStoreResult(.UnknownError)
|
||||
}
|
||||
|
||||
|
||||
// MARK: Internal
|
||||
|
||||
internal let coordinator: NSPersistentStoreCoordinator
|
||||
internal let rootSavingContext: NSManagedObjectContext
|
||||
internal let mainContext: NSManagedObjectContext
|
||||
internal let childTransactionQueue: GCDQueue = .createSerial("com.corestore.datastack.childtransactionqueue")
|
||||
|
||||
internal func entityNameForEntityClass(entityClass: NSManagedObject.Type) -> String? {
|
||||
|
||||
return self.entityNameMapping[NSStringFromClass(entityClass)]
|
||||
}
|
||||
|
||||
internal func persistentStoresForEntityClass(entityClass: NSManagedObject.Type) -> [NSPersistentStore]? {
|
||||
|
||||
var returnValue: [NSPersistentStore]? = nil
|
||||
self.storeMetadataUpdateQueue.barrierSync {
|
||||
|
||||
let configurationsForEntity = self.entityConfigurationsMapping[NSStringFromClass(entityClass)] ?? []
|
||||
returnValue = map(configurationsForEntity) {
|
||||
|
||||
return self.configurationStoreMapping[$0]!
|
||||
}
|
||||
}
|
||||
return returnValue
|
||||
}
|
||||
|
||||
internal func persistentStoreForEntityClass(entityClass: NSManagedObject.Type, configuration: String?, inferStoreIfPossible: Bool) -> (store: NSPersistentStore?, isAmbiguous: Bool) {
|
||||
|
||||
var returnValue: (store: NSPersistentStore?, isAmbiguous: Bool) = (store: nil, isAmbiguous: false)
|
||||
self.storeMetadataUpdateQueue.barrierSync {
|
||||
|
||||
let configurationsForEntity = self.entityConfigurationsMapping[NSStringFromClass(entityClass)] ?? []
|
||||
if let configuration = configuration {
|
||||
|
||||
if configurationsForEntity.contains(configuration) {
|
||||
|
||||
returnValue = (store: self.configurationStoreMapping[configuration], isAmbiguous: false)
|
||||
return
|
||||
}
|
||||
else if !inferStoreIfPossible {
|
||||
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
switch configurationsForEntity.count {
|
||||
|
||||
case 0:
|
||||
return
|
||||
|
||||
case 1 where inferStoreIfPossible:
|
||||
returnValue = (store: self.configurationStoreMapping[configurationsForEntity.first!], isAmbiguous: false)
|
||||
|
||||
default:
|
||||
returnValue = (store: nil, isAmbiguous: true)
|
||||
}
|
||||
}
|
||||
return returnValue
|
||||
}
|
||||
|
||||
internal func updateMetadataForPersistentStore(persistentStore: NSPersistentStore) {
|
||||
|
||||
self.storeMetadataUpdateQueue.barrierAsync {
|
||||
|
||||
let configurationName = persistentStore.configurationName
|
||||
self.configurationStoreMapping[configurationName] = persistentStore
|
||||
for entityDescription in (self.coordinator.managedObjectModel.entitiesForConfiguration(configurationName) as? [NSEntityDescription] ?? []) {
|
||||
|
||||
self.entityConfigurationsMapping[entityDescription.managedObjectClassName]?.insert(configurationName)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// MARK: Private
|
||||
|
||||
private typealias EntityClassNameType = String
|
||||
private typealias EntityNameType = String
|
||||
private typealias ConfigurationNameType = String
|
||||
|
||||
private let entityNameMapping: [EntityClassNameType: EntityNameType]
|
||||
private let storeMetadataUpdateQueue = GCDQueue.createConcurrent("com.coreStore.persistentStoreBarrierQueue")
|
||||
private var configurationStoreMapping = [ConfigurationNameType: NSPersistentStore]()
|
||||
private var entityConfigurationsMapping = [EntityClassNameType: Set<String>]()
|
||||
}
|
||||
@@ -1,110 +0,0 @@
|
||||
//
|
||||
// PersistentStoreResult.swift
|
||||
// CoreStore
|
||||
//
|
||||
// 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
|
||||
|
||||
|
||||
// MARK: - PersistentStoreResult
|
||||
|
||||
/**
|
||||
The `PersistentStoreResult` indicates the result of initializing the persistent store.
|
||||
The `PersistentStoreResult` can be treated as a boolean:
|
||||
|
||||
let result = CoreStore.addSQLiteStoreAndWait()
|
||||
if result {
|
||||
// succeeded
|
||||
}
|
||||
else {
|
||||
// failed
|
||||
}
|
||||
|
||||
or as an `enum`, where the resulting associated object can also be inspected:
|
||||
|
||||
let result = CoreStore.addSQLiteStoreAndWait()
|
||||
switch result {
|
||||
case .Success(let persistentStore):
|
||||
// persistentStore is the related NSPersistentStore instance
|
||||
case .Failure(let error):
|
||||
// error is the NSError instance for the failure
|
||||
}
|
||||
```
|
||||
*/
|
||||
public enum PersistentStoreResult {
|
||||
|
||||
// MARK: Public
|
||||
|
||||
/**
|
||||
`PersistentStoreResult.Success` indicates that the persistent store process succeeded. The associated object for this `enum` value is the related `NSPersistentStore` instance.
|
||||
*/
|
||||
case Success(NSPersistentStore)
|
||||
|
||||
/**
|
||||
`PersistentStoreResult.Failure` indicates that the persistent store process failed. The associated object for this value is the related `NSError` instance.
|
||||
*/
|
||||
case Failure(NSError)
|
||||
|
||||
|
||||
// MARK: Internal
|
||||
|
||||
internal init(_ store: NSPersistentStore) {
|
||||
|
||||
self = .Success(store)
|
||||
}
|
||||
|
||||
internal init(_ error: NSError) {
|
||||
|
||||
self = .Failure(error)
|
||||
}
|
||||
|
||||
internal init(_ errorCode: CoreStoreErrorCode) {
|
||||
|
||||
self.init(errorCode, userInfo: nil)
|
||||
}
|
||||
|
||||
internal init(_ errorCode: CoreStoreErrorCode, userInfo: [NSObject: AnyObject]?) {
|
||||
|
||||
self.init(NSError(
|
||||
coreStoreErrorCode: errorCode,
|
||||
userInfo: userInfo))
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// MARK: - PersistentStoreResult: BooleanType
|
||||
|
||||
extension PersistentStoreResult: BooleanType {
|
||||
|
||||
// MARK: Public
|
||||
|
||||
public var boolValue: Bool {
|
||||
|
||||
switch self {
|
||||
|
||||
case .Success: return true
|
||||
case .Failure: return false
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -7,10 +7,12 @@
|
||||
objects = {
|
||||
|
||||
/* Begin PBXBuildFile section */
|
||||
B503FADF1AFDC71700F90881 /* ObjectListObserverDemoViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = B503FADB1AFDC71700F90881 /* ObjectListObserverDemoViewController.swift */; };
|
||||
B503FADF1AFDC71700F90881 /* ListObserverDemoViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = B503FADB1AFDC71700F90881 /* ListObserverDemoViewController.swift */; };
|
||||
B503FAE01AFDC71700F90881 /* ObjectObserverDemoViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = B503FADC1AFDC71700F90881 /* ObjectObserverDemoViewController.swift */; };
|
||||
B503FAE11AFDC71700F90881 /* Palette.swift in Sources */ = {isa = PBXBuildFile; fileRef = B503FADD1AFDC71700F90881 /* Palette.swift */; };
|
||||
B503FAE21AFDC71700F90881 /* PaletteTableViewCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = B503FADE1AFDC71700F90881 /* PaletteTableViewCell.swift */; };
|
||||
B5125C121B521B78003A42C7 /* OrganismV2ToV3.xcmappingmodel in Sources */ = {isa = PBXBuildFile; fileRef = B5125C111B521B78003A42C7 /* OrganismV2ToV3.xcmappingmodel */; };
|
||||
B5125C141B521BA7003A42C7 /* OrganismV3ToV2.xcmappingmodel in Sources */ = {isa = PBXBuildFile; fileRef = B5125C131B521BA7003A42C7 /* OrganismV3ToV2.xcmappingmodel */; };
|
||||
B52977D91B120B80003D50A5 /* ObserversViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = B52977D81B120B80003D50A5 /* ObserversViewController.swift */; };
|
||||
B52977DD1B120F3B003D50A5 /* TransactionsDemoViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = B52977DC1B120F3B003D50A5 /* TransactionsDemoViewController.swift */; };
|
||||
B52977DF1B120F83003D50A5 /* MapKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = B52977DE1B120F83003D50A5 /* MapKit.framework */; };
|
||||
@@ -21,63 +23,39 @@
|
||||
B54AAD591AF4D26E00848AE0 /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = B54AAD571AF4D26E00848AE0 /* Main.storyboard */; };
|
||||
B54AAD5B1AF4D26E00848AE0 /* Images.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = B54AAD5A1AF4D26E00848AE0 /* Images.xcassets */; };
|
||||
B54AAD5E1AF4D26E00848AE0 /* LaunchScreen.xib in Resources */ = {isa = PBXBuildFile; fileRef = B54AAD5C1AF4D26E00848AE0 /* LaunchScreen.xib */; };
|
||||
B560070F1B3EC90F00A9A8F9 /* OrganismV2ToV3MigrationPolicy.swift in Sources */ = {isa = PBXBuildFile; fileRef = B560070E1B3EC90F00A9A8F9 /* OrganismV2ToV3MigrationPolicy.swift */; };
|
||||
B566E32A1B117B1F00F4F0C6 /* StackSetupDemoViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = B566E3291B117B1F00F4F0C6 /* StackSetupDemoViewController.swift */; };
|
||||
B566E3321B11DF3200F4F0C6 /* UserAccount.swift in Sources */ = {isa = PBXBuildFile; fileRef = B566E3311B11DF3200F4F0C6 /* UserAccount.swift */; };
|
||||
B56964C91B20AC780075EE4A /* CustomLoggerViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = B56964C81B20AC780075EE4A /* CustomLoggerViewController.swift */; };
|
||||
B56964D71B231AE90075EE4A /* StackSetupDemo.xcdatamodeld in Sources */ = {isa = PBXBuildFile; fileRef = B56964D51B231AE90075EE4A /* StackSetupDemo.xcdatamodeld */; };
|
||||
B56964DA1B231BCA0075EE4A /* MaleAccount.swift in Sources */ = {isa = PBXBuildFile; fileRef = B56964D91B231BCA0075EE4A /* MaleAccount.swift */; };
|
||||
B56964DC1B231BCB0075EE4A /* FemaleAccount.swift in Sources */ = {isa = PBXBuildFile; fileRef = B56964DB1B231BCB0075EE4A /* FemaleAccount.swift */; };
|
||||
B56964DF1B2321E30075EE4A /* MigrationDemo.xcdatamodeld in Sources */ = {isa = PBXBuildFile; fileRef = B56964DD1B2321E30075EE4A /* MigrationDemo.xcdatamodeld */; };
|
||||
B569650C1B2B36E10075EE4A /* FetchingAndQueryingDemoViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = B569650B1B2B36E10075EE4A /* FetchingAndQueryingDemoViewController.swift */; };
|
||||
B56965181B2E20CC0075EE4A /* TimeZone.swift in Sources */ = {isa = PBXBuildFile; fileRef = B56965171B2E20CC0075EE4A /* TimeZone.swift */; };
|
||||
B569651A1B30888A0075EE4A /* FetchingResultsViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = B56965191B30888A0075EE4A /* FetchingResultsViewController.swift */; };
|
||||
B569651C1B30889A0075EE4A /* QueryingResultsViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = B569651B1B30889A0075EE4A /* QueryingResultsViewController.swift */; };
|
||||
B583A9201AF5F542001F76AF /* CoreStore.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = B583A91B1AF5F4F4001F76AF /* CoreStore.framework */; };
|
||||
B583A9211AF5F542001F76AF /* CoreStore.framework in Embed Frameworks */ = {isa = PBXBuildFile; fileRef = B583A91B1AF5F4F4001F76AF /* CoreStore.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; };
|
||||
B5D9C9191B20AB1900E64F0E /* GCDKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = B5D9C9181B20AB1900E64F0E /* GCDKit.framework */; };
|
||||
B5D9C91A1B20AB1900E64F0E /* GCDKit.framework in Embed Frameworks */ = {isa = PBXBuildFile; fileRef = B5D9C9181B20AB1900E64F0E /* GCDKit.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; };
|
||||
B56965291B3582D30075EE4A /* MigrationDemo.xcdatamodeld in Sources */ = {isa = PBXBuildFile; fileRef = B56965271B3582D30075EE4A /* MigrationDemo.xcdatamodeld */; };
|
||||
B5E599321B5240F50084BD5F /* OrganismTableViewCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = B5E599311B5240F50084BD5F /* OrganismTableViewCell.swift */; };
|
||||
B5E89ACD1C52929C003B04A9 /* GCDKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = B5BDC9241C202429008147CD /* GCDKit.framework */; };
|
||||
B5E89ACE1C52929C003B04A9 /* GCDKit.framework in Embed Frameworks */ = {isa = PBXBuildFile; fileRef = B5BDC9241C202429008147CD /* GCDKit.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; };
|
||||
B5E89AD01C5292A2003B04A9 /* CoreStore.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = B5BDC9211C202429008147CD /* CoreStore.framework */; };
|
||||
B5E89AD11C5292A2003B04A9 /* CoreStore.framework in Embed Frameworks */ = {isa = PBXBuildFile; fileRef = B5BDC9211C202429008147CD /* CoreStore.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; };
|
||||
B5EE25851B36E23C0000406B /* OrganismV1.swift in Sources */ = {isa = PBXBuildFile; fileRef = B5EE25841B36E23C0000406B /* OrganismV1.swift */; };
|
||||
B5EE25871B36E2520000406B /* OrganismV2.swift in Sources */ = {isa = PBXBuildFile; fileRef = B5EE25861B36E2520000406B /* OrganismV2.swift */; };
|
||||
B5EE258C1B36E40D0000406B /* MigrationsDemoViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = B5EE258B1B36E40D0000406B /* MigrationsDemoViewController.swift */; };
|
||||
B5EE259B1B3EA4890000406B /* OrganismV3.swift in Sources */ = {isa = PBXBuildFile; fileRef = B5EE259A1B3EA4890000406B /* OrganismV3.swift */; };
|
||||
B5EE259E1B3EC1B20000406B /* OrganismProtocol.swift in Sources */ = {isa = PBXBuildFile; fileRef = B5EE259D1B3EC1B20000406B /* OrganismProtocol.swift */; };
|
||||
/* End PBXBuildFile section */
|
||||
|
||||
/* Begin PBXContainerItemProxy section */
|
||||
B583A91A1AF5F4F4001F76AF /* PBXContainerItemProxy */ = {
|
||||
isa = PBXContainerItemProxy;
|
||||
containerPortal = B583A9141AF5F4F3001F76AF /* CoreStore.xcodeproj */;
|
||||
proxyType = 2;
|
||||
remoteGlobalIDString = 2F03A53019C5C6DA005002A5;
|
||||
remoteInfo = CoreStore;
|
||||
};
|
||||
B583A91C1AF5F4F4001F76AF /* PBXContainerItemProxy */ = {
|
||||
isa = PBXContainerItemProxy;
|
||||
containerPortal = B583A9141AF5F4F3001F76AF /* CoreStore.xcodeproj */;
|
||||
proxyType = 2;
|
||||
remoteGlobalIDString = 2F03A53B19C5C6DA005002A5;
|
||||
remoteInfo = CoreStoreTests;
|
||||
};
|
||||
B583A91E1AF5F512001F76AF /* PBXContainerItemProxy */ = {
|
||||
isa = PBXContainerItemProxy;
|
||||
containerPortal = B583A9141AF5F4F3001F76AF /* CoreStore.xcodeproj */;
|
||||
proxyType = 1;
|
||||
remoteGlobalIDString = 2F03A52F19C5C6DA005002A5;
|
||||
remoteInfo = CoreStore;
|
||||
};
|
||||
B583A9221AF5F542001F76AF /* PBXContainerItemProxy */ = {
|
||||
isa = PBXContainerItemProxy;
|
||||
containerPortal = B583A9141AF5F4F3001F76AF /* CoreStore.xcodeproj */;
|
||||
proxyType = 1;
|
||||
remoteGlobalIDString = 2F03A52F19C5C6DA005002A5;
|
||||
remoteInfo = CoreStore;
|
||||
};
|
||||
/* End PBXContainerItemProxy section */
|
||||
|
||||
/* Begin PBXCopyFilesBuildPhase section */
|
||||
B583A9241AF5F542001F76AF /* Embed Frameworks */ = {
|
||||
B5E89ACF1C52929C003B04A9 /* Embed Frameworks */ = {
|
||||
isa = PBXCopyFilesBuildPhase;
|
||||
buildActionMask = 2147483647;
|
||||
dstPath = "";
|
||||
dstSubfolderSpec = 10;
|
||||
files = (
|
||||
B5D9C91A1B20AB1900E64F0E /* GCDKit.framework in Embed Frameworks */,
|
||||
B583A9211AF5F542001F76AF /* CoreStore.framework in Embed Frameworks */,
|
||||
B5E89ACE1C52929C003B04A9 /* GCDKit.framework in Embed Frameworks */,
|
||||
B5E89AD11C5292A2003B04A9 /* CoreStore.framework in Embed Frameworks */,
|
||||
);
|
||||
name = "Embed Frameworks";
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
@@ -85,10 +63,12 @@
|
||||
/* End PBXCopyFilesBuildPhase section */
|
||||
|
||||
/* Begin PBXFileReference section */
|
||||
B503FADB1AFDC71700F90881 /* ObjectListObserverDemoViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ObjectListObserverDemoViewController.swift; sourceTree = "<group>"; };
|
||||
B503FADB1AFDC71700F90881 /* ListObserverDemoViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ListObserverDemoViewController.swift; sourceTree = "<group>"; };
|
||||
B503FADC1AFDC71700F90881 /* ObjectObserverDemoViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ObjectObserverDemoViewController.swift; sourceTree = "<group>"; };
|
||||
B503FADD1AFDC71700F90881 /* Palette.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Palette.swift; sourceTree = "<group>"; };
|
||||
B503FADE1AFDC71700F90881 /* PaletteTableViewCell.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = PaletteTableViewCell.swift; sourceTree = "<group>"; };
|
||||
B5125C111B521B78003A42C7 /* OrganismV2ToV3.xcmappingmodel */ = {isa = PBXFileReference; lastKnownFileType = wrapper.xcmappingmodel; path = OrganismV2ToV3.xcmappingmodel; sourceTree = "<group>"; };
|
||||
B5125C131B521BA7003A42C7 /* OrganismV3ToV2.xcmappingmodel */ = {isa = PBXFileReference; lastKnownFileType = wrapper.xcmappingmodel; path = OrganismV3ToV2.xcmappingmodel; sourceTree = "<group>"; };
|
||||
B52977D81B120B80003D50A5 /* ObserversViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ObserversViewController.swift; sourceTree = "<group>"; };
|
||||
B52977DC1B120F3B003D50A5 /* TransactionsDemoViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = TransactionsDemoViewController.swift; sourceTree = "<group>"; };
|
||||
B52977DE1B120F83003D50A5 /* MapKit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = MapKit.framework; path = System/Library/Frameworks/MapKit.framework; sourceTree = SDKROOT; };
|
||||
@@ -101,20 +81,28 @@
|
||||
B54AAD581AF4D26E00848AE0 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/Main.storyboard; sourceTree = "<group>"; };
|
||||
B54AAD5A1AF4D26E00848AE0 /* Images.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Images.xcassets; sourceTree = "<group>"; };
|
||||
B54AAD5D1AF4D26E00848AE0 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.xib; name = Base; path = Base.lproj/LaunchScreen.xib; sourceTree = "<group>"; };
|
||||
B560070E1B3EC90F00A9A8F9 /* OrganismV2ToV3MigrationPolicy.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = OrganismV2ToV3MigrationPolicy.swift; sourceTree = "<group>"; };
|
||||
B566E3291B117B1F00F4F0C6 /* StackSetupDemoViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = StackSetupDemoViewController.swift; sourceTree = "<group>"; };
|
||||
B566E3311B11DF3200F4F0C6 /* UserAccount.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = UserAccount.swift; sourceTree = "<group>"; };
|
||||
B56964C81B20AC780075EE4A /* CustomLoggerViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = CustomLoggerViewController.swift; sourceTree = "<group>"; };
|
||||
B56964D61B231AE90075EE4A /* StackSetupDemo.xcdatamodel */ = {isa = PBXFileReference; lastKnownFileType = wrapper.xcdatamodel; path = StackSetupDemo.xcdatamodel; sourceTree = "<group>"; };
|
||||
B56964D91B231BCA0075EE4A /* MaleAccount.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = MaleAccount.swift; sourceTree = "<group>"; };
|
||||
B56964DB1B231BCB0075EE4A /* FemaleAccount.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = FemaleAccount.swift; sourceTree = "<group>"; };
|
||||
B56964DE1B2321E30075EE4A /* MigrationDemo.xcdatamodel */ = {isa = PBXFileReference; lastKnownFileType = wrapper.xcdatamodel; path = MigrationDemo.xcdatamodel; sourceTree = "<group>"; };
|
||||
B56964E01B2326F30075EE4A /* MigrationDemoV2.xcdatamodel */ = {isa = PBXFileReference; lastKnownFileType = wrapper.xcdatamodel; path = MigrationDemoV2.xcdatamodel; sourceTree = "<group>"; };
|
||||
B569650B1B2B36E10075EE4A /* FetchingAndQueryingDemoViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = FetchingAndQueryingDemoViewController.swift; sourceTree = "<group>"; };
|
||||
B56965171B2E20CC0075EE4A /* TimeZone.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = TimeZone.swift; sourceTree = "<group>"; };
|
||||
B56965191B30888A0075EE4A /* FetchingResultsViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = FetchingResultsViewController.swift; sourceTree = "<group>"; };
|
||||
B569651B1B30889A0075EE4A /* QueryingResultsViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = QueryingResultsViewController.swift; sourceTree = "<group>"; };
|
||||
B583A9141AF5F4F3001F76AF /* CoreStore.xcodeproj */ = {isa = PBXFileReference; lastKnownFileType = "wrapper.pb-project"; name = CoreStore.xcodeproj; path = ../CoreStore.xcodeproj; sourceTree = "<group>"; };
|
||||
B5D9C9181B20AB1900E64F0E /* GCDKit.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; path = GCDKit.framework; sourceTree = BUILT_PRODUCTS_DIR; };
|
||||
B56965281B3582D30075EE4A /* MigrationDemo.xcdatamodel */ = {isa = PBXFileReference; lastKnownFileType = wrapper.xcdatamodel; path = MigrationDemo.xcdatamodel; sourceTree = "<group>"; };
|
||||
B5BDC9211C202429008147CD /* CoreStore.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; path = CoreStore.framework; sourceTree = BUILT_PRODUCTS_DIR; };
|
||||
B5BDC9241C202429008147CD /* GCDKit.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; path = GCDKit.framework; sourceTree = BUILT_PRODUCTS_DIR; };
|
||||
B5E599311B5240F50084BD5F /* OrganismTableViewCell.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = OrganismTableViewCell.swift; path = "CoreStoreDemo/MIgrations Demo/OrganismTableViewCell.swift"; sourceTree = SOURCE_ROOT; };
|
||||
B5EE25801B36E1B00000406B /* MigrationDemoV2.xcdatamodel */ = {isa = PBXFileReference; lastKnownFileType = wrapper.xcdatamodel; path = MigrationDemoV2.xcdatamodel; sourceTree = "<group>"; };
|
||||
B5EE25841B36E23C0000406B /* OrganismV1.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = OrganismV1.swift; sourceTree = "<group>"; };
|
||||
B5EE25861B36E2520000406B /* OrganismV2.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = OrganismV2.swift; sourceTree = "<group>"; };
|
||||
B5EE25881B36E2750000406B /* MigrationDemoV3.xcdatamodel */ = {isa = PBXFileReference; lastKnownFileType = wrapper.xcdatamodel; path = MigrationDemoV3.xcdatamodel; sourceTree = "<group>"; };
|
||||
B5EE258B1B36E40D0000406B /* MigrationsDemoViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = MigrationsDemoViewController.swift; sourceTree = "<group>"; };
|
||||
B5EE259A1B3EA4890000406B /* OrganismV3.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = OrganismV3.swift; sourceTree = "<group>"; };
|
||||
B5EE259D1B3EC1B20000406B /* OrganismProtocol.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = OrganismProtocol.swift; sourceTree = "<group>"; };
|
||||
/* End PBXFileReference section */
|
||||
|
||||
/* Begin PBXFrameworksBuildPhase section */
|
||||
@@ -122,10 +110,10 @@
|
||||
isa = PBXFrameworksBuildPhase;
|
||||
buildActionMask = 2147483647;
|
||||
files = (
|
||||
B5E89ACD1C52929C003B04A9 /* GCDKit.framework in Frameworks */,
|
||||
B5E89AD01C5292A2003B04A9 /* CoreStore.framework in Frameworks */,
|
||||
B52977E11B120F8A003D50A5 /* CoreLocation.framework in Frameworks */,
|
||||
B52977DF1B120F83003D50A5 /* MapKit.framework in Frameworks */,
|
||||
B5D9C9191B20AB1900E64F0E /* GCDKit.framework in Frameworks */,
|
||||
B583A9201AF5F542001F76AF /* CoreStore.framework in Frameworks */,
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
};
|
||||
@@ -136,7 +124,7 @@
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
B52977D81B120B80003D50A5 /* ObserversViewController.swift */,
|
||||
B503FADB1AFDC71700F90881 /* ObjectListObserverDemoViewController.swift */,
|
||||
B503FADB1AFDC71700F90881 /* ListObserverDemoViewController.swift */,
|
||||
B503FADC1AFDC71700F90881 /* ObjectObserverDemoViewController.swift */,
|
||||
B503FADD1AFDC71700F90881 /* Palette.swift */,
|
||||
B503FADE1AFDC71700F90881 /* PaletteTableViewCell.swift */,
|
||||
@@ -156,9 +144,9 @@
|
||||
B52977E21B120F90003D50A5 /* Frameworks */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
B583A9141AF5F4F3001F76AF /* CoreStore.xcodeproj */,
|
||||
B5D9C9181B20AB1900E64F0E /* GCDKit.framework */,
|
||||
B52977E01B120F8A003D50A5 /* CoreLocation.framework */,
|
||||
B5BDC9211C202429008147CD /* CoreStore.framework */,
|
||||
B5BDC9241C202429008147CD /* GCDKit.framework */,
|
||||
B52977DE1B120F83003D50A5 /* MapKit.framework */,
|
||||
);
|
||||
name = Frameworks;
|
||||
@@ -189,13 +177,14 @@
|
||||
B503FADA1AFDC71700F90881 /* List and Object Observers Demo */,
|
||||
B52977DB1B120F2C003D50A5 /* Transactions Demo */,
|
||||
B56965091B2B35370075EE4A /* Fetching and Querying Demo */,
|
||||
B569652F1B3591460075EE4A /* Migrations Demo */,
|
||||
B56964C61B20AC200075EE4A /* Loggers Demo */,
|
||||
B54AAD571AF4D26E00848AE0 /* Main.storyboard */,
|
||||
B54AAD5A1AF4D26E00848AE0 /* Images.xcassets */,
|
||||
B54AAD5C1AF4D26E00848AE0 /* LaunchScreen.xib */,
|
||||
B54AAD501AF4D26E00848AE0 /* CoreStoreDemo.xcdatamodeld */,
|
||||
B56964D51B231AE90075EE4A /* StackSetupDemo.xcdatamodeld */,
|
||||
B56964DD1B2321E30075EE4A /* MigrationDemo.xcdatamodeld */,
|
||||
B56965271B3582D30075EE4A /* MigrationDemo.xcdatamodeld */,
|
||||
B54AAD4C1AF4D26E00848AE0 /* Supporting Files */,
|
||||
);
|
||||
path = CoreStoreDemo;
|
||||
@@ -239,13 +228,20 @@
|
||||
path = "Fetching and Querying Demo";
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
B583A9151AF5F4F3001F76AF /* Products */ = {
|
||||
B569652F1B3591460075EE4A /* Migrations Demo */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
B583A91B1AF5F4F4001F76AF /* CoreStore.framework */,
|
||||
B583A91D1AF5F4F4001F76AF /* CoreStoreTests.xctest */,
|
||||
B5EE259D1B3EC1B20000406B /* OrganismProtocol.swift */,
|
||||
B5EE259A1B3EA4890000406B /* OrganismV3.swift */,
|
||||
B5EE25861B36E2520000406B /* OrganismV2.swift */,
|
||||
B5EE25841B36E23C0000406B /* OrganismV1.swift */,
|
||||
B5EE258B1B36E40D0000406B /* MigrationsDemoViewController.swift */,
|
||||
B5E599311B5240F50084BD5F /* OrganismTableViewCell.swift */,
|
||||
B5125C111B521B78003A42C7 /* OrganismV2ToV3.xcmappingmodel */,
|
||||
B560070E1B3EC90F00A9A8F9 /* OrganismV2ToV3MigrationPolicy.swift */,
|
||||
B5125C131B521BA7003A42C7 /* OrganismV3ToV2.xcmappingmodel */,
|
||||
);
|
||||
name = Products;
|
||||
path = "Migrations Demo";
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
/* End PBXGroup section */
|
||||
@@ -258,13 +254,11 @@
|
||||
B54AAD451AF4D26E00848AE0 /* Sources */,
|
||||
B54AAD461AF4D26E00848AE0 /* Frameworks */,
|
||||
B54AAD471AF4D26E00848AE0 /* Resources */,
|
||||
B583A9241AF5F542001F76AF /* Embed Frameworks */,
|
||||
B5E89ACF1C52929C003B04A9 /* Embed Frameworks */,
|
||||
);
|
||||
buildRules = (
|
||||
);
|
||||
dependencies = (
|
||||
B583A91F1AF5F512001F76AF /* PBXTargetDependency */,
|
||||
B583A9231AF5F542001F76AF /* PBXTargetDependency */,
|
||||
);
|
||||
name = CoreStoreDemo;
|
||||
productName = CoreStoreDemo;
|
||||
@@ -277,7 +271,8 @@
|
||||
B54AAD411AF4D26E00848AE0 /* Project object */ = {
|
||||
isa = PBXProject;
|
||||
attributes = {
|
||||
LastUpgradeCheck = 0630;
|
||||
LastSwiftUpdateCheck = 0700;
|
||||
LastUpgradeCheck = 0700;
|
||||
ORGANIZATIONNAME = "John Rommel Estropia";
|
||||
TargetAttributes = {
|
||||
B54AAD481AF4D26E00848AE0 = {
|
||||
@@ -296,12 +291,6 @@
|
||||
mainGroup = B54AAD401AF4D26E00848AE0;
|
||||
productRefGroup = B54AAD4A1AF4D26E00848AE0 /* Products */;
|
||||
projectDirPath = "";
|
||||
projectReferences = (
|
||||
{
|
||||
ProductGroup = B583A9151AF5F4F3001F76AF /* Products */;
|
||||
ProjectRef = B583A9141AF5F4F3001F76AF /* CoreStore.xcodeproj */;
|
||||
},
|
||||
);
|
||||
projectRoot = "";
|
||||
targets = (
|
||||
B54AAD481AF4D26E00848AE0 /* CoreStoreDemo */,
|
||||
@@ -309,23 +298,6 @@
|
||||
};
|
||||
/* End PBXProject section */
|
||||
|
||||
/* Begin PBXReferenceProxy section */
|
||||
B583A91B1AF5F4F4001F76AF /* CoreStore.framework */ = {
|
||||
isa = PBXReferenceProxy;
|
||||
fileType = wrapper.framework;
|
||||
path = CoreStore.framework;
|
||||
remoteRef = B583A91A1AF5F4F4001F76AF /* PBXContainerItemProxy */;
|
||||
sourceTree = BUILT_PRODUCTS_DIR;
|
||||
};
|
||||
B583A91D1AF5F4F4001F76AF /* CoreStoreTests.xctest */ = {
|
||||
isa = PBXReferenceProxy;
|
||||
fileType = wrapper.cfbundle;
|
||||
path = CoreStoreTests.xctest;
|
||||
remoteRef = B583A91C1AF5F4F4001F76AF /* PBXContainerItemProxy */;
|
||||
sourceTree = BUILT_PRODUCTS_DIR;
|
||||
};
|
||||
/* End PBXReferenceProxy section */
|
||||
|
||||
/* Begin PBXResourcesBuildPhase section */
|
||||
B54AAD471AF4D26E00848AE0 /* Resources */ = {
|
||||
isa = PBXResourcesBuildPhase;
|
||||
@@ -345,11 +317,14 @@
|
||||
buildActionMask = 2147483647;
|
||||
files = (
|
||||
B56965181B2E20CC0075EE4A /* TimeZone.swift in Sources */,
|
||||
B56965291B3582D30075EE4A /* MigrationDemo.xcdatamodeld in Sources */,
|
||||
B5E599321B5240F50084BD5F /* OrganismTableViewCell.swift in Sources */,
|
||||
B5EE25851B36E23C0000406B /* OrganismV1.swift in Sources */,
|
||||
B52977DD1B120F3B003D50A5 /* TransactionsDemoViewController.swift in Sources */,
|
||||
B56964DF1B2321E30075EE4A /* MigrationDemo.xcdatamodeld in Sources */,
|
||||
B52977E41B121635003D50A5 /* Place.swift in Sources */,
|
||||
B569650C1B2B36E10075EE4A /* FetchingAndQueryingDemoViewController.swift in Sources */,
|
||||
B569651A1B30888A0075EE4A /* FetchingResultsViewController.swift in Sources */,
|
||||
B5EE25871B36E2520000406B /* OrganismV2.swift in Sources */,
|
||||
B503FAE01AFDC71700F90881 /* ObjectObserverDemoViewController.swift in Sources */,
|
||||
B52977D91B120B80003D50A5 /* ObserversViewController.swift in Sources */,
|
||||
B56964C91B20AC780075EE4A /* CustomLoggerViewController.swift in Sources */,
|
||||
@@ -357,31 +332,24 @@
|
||||
B56964DA1B231BCA0075EE4A /* MaleAccount.swift in Sources */,
|
||||
B566E3321B11DF3200F4F0C6 /* UserAccount.swift in Sources */,
|
||||
B54AAD521AF4D26E00848AE0 /* CoreStoreDemo.xcdatamodeld in Sources */,
|
||||
B5EE259B1B3EA4890000406B /* OrganismV3.swift in Sources */,
|
||||
B503FAE11AFDC71700F90881 /* Palette.swift in Sources */,
|
||||
B503FAE21AFDC71700F90881 /* PaletteTableViewCell.swift in Sources */,
|
||||
B503FADF1AFDC71700F90881 /* ObjectListObserverDemoViewController.swift in Sources */,
|
||||
B560070F1B3EC90F00A9A8F9 /* OrganismV2ToV3MigrationPolicy.swift in Sources */,
|
||||
B5125C141B521BA7003A42C7 /* OrganismV3ToV2.xcmappingmodel in Sources */,
|
||||
B503FADF1AFDC71700F90881 /* ListObserverDemoViewController.swift in Sources */,
|
||||
B54AAD4F1AF4D26E00848AE0 /* AppDelegate.swift in Sources */,
|
||||
B56964D71B231AE90075EE4A /* StackSetupDemo.xcdatamodeld in Sources */,
|
||||
B56964DC1B231BCB0075EE4A /* FemaleAccount.swift in Sources */,
|
||||
B5EE259E1B3EC1B20000406B /* OrganismProtocol.swift in Sources */,
|
||||
B5EE258C1B36E40D0000406B /* MigrationsDemoViewController.swift in Sources */,
|
||||
B569651C1B30889A0075EE4A /* QueryingResultsViewController.swift in Sources */,
|
||||
B5125C121B521B78003A42C7 /* OrganismV2ToV3.xcmappingmodel in Sources */,
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
};
|
||||
/* End PBXSourcesBuildPhase section */
|
||||
|
||||
/* Begin PBXTargetDependency section */
|
||||
B583A91F1AF5F512001F76AF /* PBXTargetDependency */ = {
|
||||
isa = PBXTargetDependency;
|
||||
name = CoreStore;
|
||||
targetProxy = B583A91E1AF5F512001F76AF /* PBXContainerItemProxy */;
|
||||
};
|
||||
B583A9231AF5F542001F76AF /* PBXTargetDependency */ = {
|
||||
isa = PBXTargetDependency;
|
||||
name = CoreStore;
|
||||
targetProxy = B583A9221AF5F542001F76AF /* PBXContainerItemProxy */;
|
||||
};
|
||||
/* End PBXTargetDependency section */
|
||||
|
||||
/* Begin PBXVariantGroup section */
|
||||
B54AAD571AF4D26E00848AE0 /* Main.storyboard */ = {
|
||||
isa = PBXVariantGroup;
|
||||
@@ -423,6 +391,7 @@
|
||||
COPY_PHASE_STRIP = NO;
|
||||
DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
|
||||
ENABLE_STRICT_OBJC_MSGSEND = YES;
|
||||
ENABLE_TESTABILITY = YES;
|
||||
GCC_C_LANGUAGE_STANDARD = gnu99;
|
||||
GCC_DYNAMIC_NO_PIC = NO;
|
||||
GCC_NO_COMMON_BLOCKS = YES;
|
||||
@@ -438,7 +407,7 @@
|
||||
GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
|
||||
GCC_WARN_UNUSED_FUNCTION = YES;
|
||||
GCC_WARN_UNUSED_VARIABLE = YES;
|
||||
IPHONEOS_DEPLOYMENT_TARGET = 8.3;
|
||||
IPHONEOS_DEPLOYMENT_TARGET = 8.0;
|
||||
MTL_ENABLE_DEBUG_INFO = YES;
|
||||
ONLY_ACTIVE_ARCH = YES;
|
||||
SDKROOT = iphoneos;
|
||||
@@ -476,7 +445,7 @@
|
||||
GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
|
||||
GCC_WARN_UNUSED_FUNCTION = YES;
|
||||
GCC_WARN_UNUSED_VARIABLE = YES;
|
||||
IPHONEOS_DEPLOYMENT_TARGET = 8.3;
|
||||
IPHONEOS_DEPLOYMENT_TARGET = 8.0;
|
||||
MTL_ENABLE_DEBUG_INFO = NO;
|
||||
SDKROOT = iphoneos;
|
||||
VALIDATE_PRODUCT = YES;
|
||||
@@ -487,14 +456,10 @@
|
||||
isa = XCBuildConfiguration;
|
||||
buildSettings = {
|
||||
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
|
||||
FRAMEWORK_SEARCH_PATHS = (
|
||||
"$(inherited)",
|
||||
"$(USER_LIBRARY_DIR)/Developer/Xcode/DerivedData/CoreStoreDemo-ftknhsqfpsthfogvisxisgpbbhsj/Build/Products/Debug-iphoneos",
|
||||
"$(USER_LIBRARY_DIR)/Developer/Xcode/DerivedData/CoreStoreDemo-bnajhooxbfnxepepdtkvkfplrqyq/Build/Products/Debug-iphoneos",
|
||||
);
|
||||
INFOPLIST_FILE = CoreStoreDemo/Info.plist;
|
||||
IPHONEOS_DEPLOYMENT_TARGET = 8.0;
|
||||
LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks";
|
||||
PRODUCT_BUNDLE_IDENTIFIER = com.johnestropia.corestore.demo;
|
||||
PRODUCT_NAME = "$(TARGET_NAME)";
|
||||
};
|
||||
name = Debug;
|
||||
@@ -503,14 +468,10 @@
|
||||
isa = XCBuildConfiguration;
|
||||
buildSettings = {
|
||||
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
|
||||
FRAMEWORK_SEARCH_PATHS = (
|
||||
"$(inherited)",
|
||||
"$(USER_LIBRARY_DIR)/Developer/Xcode/DerivedData/CoreStoreDemo-ftknhsqfpsthfogvisxisgpbbhsj/Build/Products/Debug-iphoneos",
|
||||
"$(USER_LIBRARY_DIR)/Developer/Xcode/DerivedData/CoreStoreDemo-bnajhooxbfnxepepdtkvkfplrqyq/Build/Products/Debug-iphoneos",
|
||||
);
|
||||
INFOPLIST_FILE = CoreStoreDemo/Info.plist;
|
||||
IPHONEOS_DEPLOYMENT_TARGET = 8.0;
|
||||
LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks";
|
||||
PRODUCT_BUNDLE_IDENTIFIER = com.johnestropia.corestore.demo;
|
||||
PRODUCT_NAME = "$(TARGET_NAME)";
|
||||
};
|
||||
name = Release;
|
||||
@@ -559,13 +520,14 @@
|
||||
sourceTree = "<group>";
|
||||
versionGroupType = wrapper.xcdatamodel;
|
||||
};
|
||||
B56964DD1B2321E30075EE4A /* MigrationDemo.xcdatamodeld */ = {
|
||||
B56965271B3582D30075EE4A /* MigrationDemo.xcdatamodeld */ = {
|
||||
isa = XCVersionGroup;
|
||||
children = (
|
||||
B56964E01B2326F30075EE4A /* MigrationDemoV2.xcdatamodel */,
|
||||
B56964DE1B2321E30075EE4A /* MigrationDemo.xcdatamodel */,
|
||||
B5EE25881B36E2750000406B /* MigrationDemoV3.xcdatamodel */,
|
||||
B5EE25801B36E1B00000406B /* MigrationDemoV2.xcdatamodel */,
|
||||
B56965281B3582D30075EE4A /* MigrationDemo.xcdatamodel */,
|
||||
);
|
||||
currentVersion = B56964E01B2326F30075EE4A /* MigrationDemoV2.xcdatamodel */;
|
||||
currentVersion = B5EE25881B36E2750000406B /* MigrationDemoV3.xcdatamodel */;
|
||||
path = MigrationDemo.xcdatamodeld;
|
||||
sourceTree = "<group>";
|
||||
versionGroupType = wrapper.xcdatamodel;
|
||||
|
||||
@@ -0,0 +1,10 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
||||
<plist version="1.0">
|
||||
<dict>
|
||||
<key>HasAskedToTakeAutomaticSnapshotBeforeSignificantChanges</key>
|
||||
<true/>
|
||||
<key>SnapshotAutomaticallyBeforeSignificantChanges</key>
|
||||
<true/>
|
||||
</dict>
|
||||
</plist>
|
||||
@@ -1,39 +0,0 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<Bucket
|
||||
type = "1"
|
||||
version = "2.0">
|
||||
<Breakpoints>
|
||||
<BreakpointProxy
|
||||
BreakpointExtensionID = "Xcode.Breakpoint.FileBreakpoint">
|
||||
<BreakpointContent
|
||||
shouldBeEnabled = "Yes"
|
||||
ignoreCount = "0"
|
||||
continueAfterRunningActions = "No"
|
||||
filePath = "../CoreStore/Migrating/DataStack+Migration.swift"
|
||||
timestampString = "457102815.005196"
|
||||
startingColumnNumber = "9223372036854775807"
|
||||
endingColumnNumber = "9223372036854775807"
|
||||
startingLineNumber = "80"
|
||||
endingLineNumber = "80"
|
||||
landmarkName = "needsMigrationForSQLiteStore(fileURL:configuration:)"
|
||||
landmarkType = "5">
|
||||
</BreakpointContent>
|
||||
</BreakpointProxy>
|
||||
<BreakpointProxy
|
||||
BreakpointExtensionID = "Xcode.Breakpoint.FileBreakpoint">
|
||||
<BreakpointContent
|
||||
shouldBeEnabled = "Yes"
|
||||
ignoreCount = "0"
|
||||
continueAfterRunningActions = "No"
|
||||
filePath = "../CoreStore/Migrating/DataStack+Migration.swift"
|
||||
timestampString = "457102823.242858"
|
||||
startingColumnNumber = "9223372036854775807"
|
||||
endingColumnNumber = "9223372036854775807"
|
||||
startingLineNumber = "165"
|
||||
endingLineNumber = "165"
|
||||
landmarkName = "upgradeSQLiteStoreIfNeeded(fileURL:configuration:completion:)"
|
||||
landmarkType = "5">
|
||||
</BreakpointContent>
|
||||
</BreakpointProxy>
|
||||
</Breakpoints>
|
||||
</Bucket>
|
||||
@@ -3,7 +3,7 @@
|
||||
// CoreStoreDemo
|
||||
//
|
||||
// Created by John Rommel Estropia on 2015/05/02.
|
||||
// Copyright (c) 2015 John Rommel Estropia. All rights reserved.
|
||||
// Copyright © 2015 John Rommel Estropia. All rights reserved.
|
||||
//
|
||||
|
||||
import UIKit
|
||||
@@ -21,6 +21,7 @@ class AppDelegate: UIResponder, UIApplicationDelegate {
|
||||
func application(application: UIApplication, didFinishLaunchingWithOptions launchOptions: [NSObject: AnyObject]?) -> Bool {
|
||||
|
||||
application.statusBarStyle = .LightContent
|
||||
|
||||
return true
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,7 +1,8 @@
|
||||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||
<document type="com.apple.InterfaceBuilder3.CocoaTouch.XIB" version="3.0" toolsVersion="7706" systemVersion="14D136" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" launchScreen="YES" useTraitCollections="YES">
|
||||
<document type="com.apple.InterfaceBuilder3.CocoaTouch.XIB" version="3.0" toolsVersion="10112" systemVersion="15D21" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" launchScreen="YES" useTraitCollections="YES">
|
||||
<dependencies>
|
||||
<plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="7703"/>
|
||||
<deployment identifier="iOS"/>
|
||||
<plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="10083"/>
|
||||
<capability name="Constraints with non-1.0 multipliers" minToolsVersion="5.1"/>
|
||||
</dependencies>
|
||||
<objects>
|
||||
@@ -11,14 +12,17 @@
|
||||
<rect key="frame" x="0.0" y="0.0" width="480" height="480"/>
|
||||
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
|
||||
<subviews>
|
||||
<label opaque="NO" clipsSubviews="YES" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text=" Copyright (c) 2015 John Rommel Estropia. All rights reserved." textAlignment="center" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" minimumFontSize="9" translatesAutoresizingMaskIntoConstraints="NO" id="8ie-xW-0ye">
|
||||
<label opaque="NO" clipsSubviews="YES" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text=" Copyright © 2015 John Rommel Estropia. All rights reserved." textAlignment="center" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" minimumFontSize="9" translatesAutoresizingMaskIntoConstraints="NO" id="8ie-xW-0ye">
|
||||
<rect key="frame" x="20" y="439" width="441" height="21"/>
|
||||
<fontDescription key="fontDescription" type="system" pointSize="17"/>
|
||||
<color key="textColor" red="0.92549019607843142" green="0.94117647058823528" blue="0.94509803921568625" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
|
||||
<nil key="highlightedColor"/>
|
||||
</label>
|
||||
<label opaque="NO" clipsSubviews="YES" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" misplaced="YES" text="CoreStore" textAlignment="center" lineBreakMode="middleTruncation" baselineAdjustment="alignBaselines" minimumFontSize="18" translatesAutoresizingMaskIntoConstraints="NO" id="kId-c2-rCX">
|
||||
<rect key="frame" x="20" y="140" width="441" height="43"/>
|
||||
<imageView userInteractionEnabled="NO" contentMode="center" horizontalHuggingPriority="251" verticalHuggingPriority="251" image="CoreStoreIcon" translatesAutoresizingMaskIntoConstraints="NO" id="q8C-V6-gXH">
|
||||
<rect key="frame" x="155" y="83" width="170" height="170"/>
|
||||
</imageView>
|
||||
<label opaque="NO" clipsSubviews="YES" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="CoreStore" textAlignment="center" lineBreakMode="middleTruncation" baselineAdjustment="alignBaselines" minimumFontSize="18" translatesAutoresizingMaskIntoConstraints="NO" id="kId-c2-rCX">
|
||||
<rect key="frame" x="20" y="273" width="440" height="57.5"/>
|
||||
<fontDescription key="fontDescription" name="HelveticaNeue-UltraLight" family="Helvetica Neue" pointSize="50"/>
|
||||
<color key="textColor" red="0.92549019607843142" green="0.94117647058823528" blue="0.94509803921568625" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
|
||||
<nil key="highlightedColor"/>
|
||||
@@ -26,16 +30,21 @@
|
||||
</subviews>
|
||||
<color key="backgroundColor" red="0.20392156862745098" green="0.28627450980392155" blue="0.36862745098039218" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
|
||||
<constraints>
|
||||
<constraint firstItem="kId-c2-rCX" firstAttribute="centerY" secondItem="iN0-l3-epB" secondAttribute="bottom" multiplier="1/3" constant="1" id="5cJ-9S-tgC"/>
|
||||
<constraint firstAttribute="centerX" secondItem="kId-c2-rCX" secondAttribute="centerX" id="Koa-jz-hwk"/>
|
||||
<constraint firstAttribute="bottom" secondItem="8ie-xW-0ye" secondAttribute="bottom" constant="20" id="Kzo-t9-V3l"/>
|
||||
<constraint firstItem="8ie-xW-0ye" firstAttribute="leading" secondItem="iN0-l3-epB" secondAttribute="leading" constant="20" symbolic="YES" id="MfP-vx-nX0"/>
|
||||
<constraint firstItem="q8C-V6-gXH" firstAttribute="centerY" secondItem="iN0-l3-epB" secondAttribute="centerY" multiplier="0.7" id="QW6-8Y-w15"/>
|
||||
<constraint firstAttribute="centerX" secondItem="8ie-xW-0ye" secondAttribute="centerX" id="ZEH-qu-HZ9"/>
|
||||
<constraint firstItem="q8C-V6-gXH" firstAttribute="centerX" secondItem="iN0-l3-epB" secondAttribute="centerX" id="fRb-1V-9iD"/>
|
||||
<constraint firstItem="kId-c2-rCX" firstAttribute="leading" secondItem="iN0-l3-epB" secondAttribute="leading" constant="20" symbolic="YES" id="fvb-Df-36g"/>
|
||||
<constraint firstItem="kId-c2-rCX" firstAttribute="top" secondItem="q8C-V6-gXH" secondAttribute="bottom" constant="20" id="s63-MP-ush"/>
|
||||
</constraints>
|
||||
<nil key="simulatedStatusBarMetrics"/>
|
||||
<freeformSimulatedSizeMetrics key="simulatedDestinationMetrics"/>
|
||||
<point key="canvasLocation" x="548" y="455"/>
|
||||
</view>
|
||||
</objects>
|
||||
<resources>
|
||||
<image name="CoreStoreIcon" width="170" height="170"/>
|
||||
</resources>
|
||||
</document>
|
||||
|
||||
53
CoreStoreDemo/CoreStoreDemo/Base.lproj/LaunchScreen.xib.orig
Normal file
@@ -0,0 +1,53 @@
|
||||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||
<<<<<<< Updated upstream
|
||||
<document type="com.apple.InterfaceBuilder3.CocoaTouch.XIB" version="3.0" toolsVersion="9531" systemVersion="15C50" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" launchScreen="YES" useTraitCollections="YES">
|
||||
<dependencies>
|
||||
<plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="9529"/>
|
||||
=======
|
||||
<document type="com.apple.InterfaceBuilder3.CocoaTouch.XIB" version="3.0" toolsVersion="9532" systemVersion="15D21" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" launchScreen="YES" useTraitCollections="YES">
|
||||
<dependencies>
|
||||
<deployment identifier="iOS"/>
|
||||
<plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="9530"/>
|
||||
>>>>>>> Stashed changes
|
||||
<capability name="Constraints with non-1.0 multipliers" minToolsVersion="5.1"/>
|
||||
</dependencies>
|
||||
<objects>
|
||||
<placeholder placeholderIdentifier="IBFilesOwner" id="-1" userLabel="File's Owner"/>
|
||||
<placeholder placeholderIdentifier="IBFirstResponder" id="-2" customClass="UIResponder"/>
|
||||
<view contentMode="scaleToFill" id="iN0-l3-epB">
|
||||
<rect key="frame" x="0.0" y="0.0" width="480" height="480"/>
|
||||
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
|
||||
<subviews>
|
||||
<<<<<<< Updated upstream
|
||||
<label opaque="NO" clipsSubviews="YES" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text=" Copyright © 2015 John Rommel Estropia. All rights reserved." textAlignment="center" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" minimumFontSize="9" translatesAutoresizingMaskIntoConstraints="NO" id="8ie-xW-0ye">
|
||||
<rect key="frame" x="20" y="439" width="441" height="21"/>
|
||||
=======
|
||||
<label opaque="NO" clipsSubviews="YES" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text=" Copyright (c) 2015 John Rommel Estropia. All rights reserved." textAlignment="center" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" minimumFontSize="9" translatesAutoresizingMaskIntoConstraints="NO" id="8ie-xW-0ye">
|
||||
<rect key="frame" x="20" y="439.5" width="441" height="20.5"/>
|
||||
>>>>>>> Stashed changes
|
||||
<fontDescription key="fontDescription" type="system" pointSize="17"/>
|
||||
<color key="textColor" red="0.92549019607843142" green="0.94117647058823528" blue="0.94509803921568625" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
|
||||
<nil key="highlightedColor"/>
|
||||
</label>
|
||||
<label opaque="NO" clipsSubviews="YES" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="CoreStore" textAlignment="center" lineBreakMode="middleTruncation" baselineAdjustment="alignBaselines" minimumFontSize="18" translatesAutoresizingMaskIntoConstraints="NO" id="kId-c2-rCX">
|
||||
<rect key="frame" x="20" y="133" width="441" height="57.5"/>
|
||||
<fontDescription key="fontDescription" name="HelveticaNeue-UltraLight" family="Helvetica Neue" pointSize="50"/>
|
||||
<color key="textColor" red="0.92549019607843142" green="0.94117647058823528" blue="0.94509803921568625" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
|
||||
<nil key="highlightedColor"/>
|
||||
</label>
|
||||
</subviews>
|
||||
<color key="backgroundColor" red="0.20392156862745098" green="0.28627450980392155" blue="0.36862745098039218" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
|
||||
<constraints>
|
||||
<constraint firstItem="kId-c2-rCX" firstAttribute="centerY" secondItem="iN0-l3-epB" secondAttribute="bottom" multiplier="1/3" constant="1" id="5cJ-9S-tgC"/>
|
||||
<constraint firstAttribute="centerX" secondItem="kId-c2-rCX" secondAttribute="centerX" id="Koa-jz-hwk"/>
|
||||
<constraint firstAttribute="bottom" secondItem="8ie-xW-0ye" secondAttribute="bottom" constant="20" id="Kzo-t9-V3l"/>
|
||||
<constraint firstItem="8ie-xW-0ye" firstAttribute="leading" secondItem="iN0-l3-epB" secondAttribute="leading" constant="20" symbolic="YES" id="MfP-vx-nX0"/>
|
||||
<constraint firstAttribute="centerX" secondItem="8ie-xW-0ye" secondAttribute="centerX" id="ZEH-qu-HZ9"/>
|
||||
<constraint firstItem="kId-c2-rCX" firstAttribute="leading" secondItem="iN0-l3-epB" secondAttribute="leading" constant="20" symbolic="YES" id="fvb-Df-36g"/>
|
||||
</constraints>
|
||||
<nil key="simulatedStatusBarMetrics"/>
|
||||
<freeformSimulatedSizeMetrics key="simulatedDestinationMetrics"/>
|
||||
<point key="canvasLocation" x="548" y="455"/>
|
||||
</view>
|
||||
</objects>
|
||||
</document>
|
||||
@@ -1,11 +1,40 @@
|
||||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||
<document type="com.apple.InterfaceBuilder3.CocoaTouch.Storyboard.XIB" version="3.0" toolsVersion="7706" systemVersion="14D136" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" useTraitCollections="YES" initialViewController="Ni8-QF-XHB">
|
||||
<document type="com.apple.InterfaceBuilder3.CocoaTouch.Storyboard.XIB" version="3.0" toolsVersion="10112" systemVersion="15D21" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" useTraitCollections="YES" initialViewController="Ni8-QF-XHB">
|
||||
<dependencies>
|
||||
<plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="7703"/>
|
||||
<deployment identifier="iOS"/>
|
||||
<plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="10083"/>
|
||||
<capability name="Aspect ratio constraints" minToolsVersion="5.1"/>
|
||||
<capability name="Constraints to layout margins" minToolsVersion="6.0"/>
|
||||
<capability name="Constraints with non-1.0 multipliers" minToolsVersion="5.1"/>
|
||||
</dependencies>
|
||||
<customFonts key="customFonts">
|
||||
<mutableArray key="AppleSDGothicNeo.ttc">
|
||||
<string>AppleSDGothicNeo-Regular</string>
|
||||
</mutableArray>
|
||||
<mutableArray key="HelveticaNeue.ttc">
|
||||
<string>HelveticaNeue-Bold</string>
|
||||
<string>HelveticaNeue-Bold</string>
|
||||
<string>HelveticaNeue</string>
|
||||
<string>HelveticaNeue</string>
|
||||
</mutableArray>
|
||||
<mutableArray key="HelveticaNeueLights.ttc">
|
||||
<string>HelveticaNeue-Light</string>
|
||||
<string>HelveticaNeue-Light</string>
|
||||
<string>HelveticaNeue-Light</string>
|
||||
<string>HelveticaNeue-Light</string>
|
||||
<string>HelveticaNeue-Thin</string>
|
||||
<string>HelveticaNeue-Light</string>
|
||||
<string>HelveticaNeue-Light</string>
|
||||
<string>HelveticaNeue-Light</string>
|
||||
<string>HelveticaNeue-Light</string>
|
||||
<string>HelveticaNeue-Light</string>
|
||||
<string>HelveticaNeue-Light</string>
|
||||
<string>HelveticaNeue-Light</string>
|
||||
<string>HelveticaNeue-Light</string>
|
||||
<string>HelveticaNeue-Light</string>
|
||||
<string>HelveticaNeue-Light</string>
|
||||
</mutableArray>
|
||||
</customFonts>
|
||||
<scenes>
|
||||
<!--SNS Accounts-->
|
||||
<scene sceneID="3If-81-mNf">
|
||||
@@ -14,7 +43,8 @@
|
||||
<tableView key="view" clipsSubviews="YES" contentMode="scaleToFill" alwaysBounceVertical="YES" dataMode="prototypes" style="plain" separatorStyle="default" rowHeight="44" sectionHeaderHeight="22" sectionFooterHeight="22" id="S3A-lm-AuA">
|
||||
<rect key="frame" x="0.0" y="0.0" width="600" height="600"/>
|
||||
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
|
||||
<color key="backgroundColor" white="1" alpha="1" colorSpace="calibratedWhite"/>
|
||||
<color key="backgroundColor" red="0.20392156859999999" green="0.28627450980000002" blue="0.36862745099999999" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
|
||||
<color key="separatorColor" red="0.20392156859999999" green="0.28627450980000002" blue="0.36862745099999999" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
|
||||
<view key="tableHeaderView" contentMode="scaleToFill" id="yud-WH-MPa">
|
||||
<rect key="frame" x="0.0" y="64" width="600" height="150"/>
|
||||
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMaxY="YES"/>
|
||||
@@ -52,17 +82,21 @@
|
||||
</view>
|
||||
<prototypes>
|
||||
<tableViewCell contentMode="scaleToFill" selectionStyle="default" indentationWidth="10" reuseIdentifier="UITableViewCell" textLabel="8b8-lM-Krq" detailTextLabel="hR1-Zb-BOk" style="IBUITableViewCellStyleValue1" id="dMt-nx-EO5">
|
||||
<rect key="frame" x="0.0" y="236" width="600" height="44"/>
|
||||
<autoresizingMask key="autoresizingMask"/>
|
||||
<tableViewCellContentView key="contentView" opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center" tableViewCell="dMt-nx-EO5" id="gdK-VV-zNb">
|
||||
<rect key="frame" x="0.0" y="0.0" width="600" height="43.5"/>
|
||||
<autoresizingMask key="autoresizingMask"/>
|
||||
<subviews>
|
||||
<label opaque="NO" multipleTouchEnabled="YES" contentMode="left" text="Title" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" id="8b8-lM-Krq">
|
||||
<rect key="frame" x="15" y="13" width="28.5" height="19"/>
|
||||
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMaxY="YES"/>
|
||||
<fontDescription key="fontDescription" name="HelveticaNeue-Light" family="Helvetica Neue" pointSize="16"/>
|
||||
<color key="textColor" red="0.17254901959999999" green="0.24313725489999999" blue="0.31372549020000001" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
|
||||
<nil key="highlightedColor"/>
|
||||
</label>
|
||||
<label opaque="NO" multipleTouchEnabled="YES" contentMode="left" text="Subtitle" textAlignment="right" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" id="hR1-Zb-BOk">
|
||||
<rect key="frame" x="533" y="13" width="52" height="19"/>
|
||||
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMaxY="YES"/>
|
||||
<fontDescription key="fontDescription" name="HelveticaNeue-Light" family="Helvetica Neue" pointSize="16"/>
|
||||
<color key="textColor" red="0.55686274509803924" green="0.55686274509803924" blue="0.57647058823529407" alpha="1" colorSpace="calibratedRGB"/>
|
||||
@@ -88,6 +122,155 @@
|
||||
</objects>
|
||||
<point key="canvasLocation" x="3694" y="650"/>
|
||||
</scene>
|
||||
<!--Evolution-->
|
||||
<scene sceneID="iwU-Hv-zNr">
|
||||
<objects>
|
||||
<viewController automaticallyAdjustsScrollViewInsets="NO" id="iVv-Vc-nCL" customClass="MigrationsDemoViewController" customModule="CoreStoreDemo" customModuleProvider="target" sceneMemberID="viewController">
|
||||
<layoutGuides>
|
||||
<viewControllerLayoutGuide type="top" id="Un6-jI-efh"/>
|
||||
<viewControllerLayoutGuide type="bottom" id="t9A-zf-Iew"/>
|
||||
</layoutGuides>
|
||||
<view key="view" contentMode="scaleToFill" id="75P-2m-6cr">
|
||||
<rect key="frame" x="0.0" y="0.0" width="600" height="600"/>
|
||||
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
|
||||
<subviews>
|
||||
<tableView clipsSubviews="YES" contentMode="scaleToFill" alwaysBounceVertical="YES" dataMode="prototypes" style="plain" separatorStyle="default" rowHeight="44" sectionHeaderHeight="22" sectionFooterHeight="22" translatesAutoresizingMaskIntoConstraints="NO" id="WUc-3Y-Quw">
|
||||
<rect key="frame" x="0.0" y="324" width="600" height="276"/>
|
||||
<color key="backgroundColor" red="0.93725490196078431" green="0.93725490196078431" blue="0.95686274509803926" alpha="1" colorSpace="calibratedRGB"/>
|
||||
<color key="separatorColor" red="0.20392156859999999" green="0.28627450980000002" blue="0.36862745099999999" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
|
||||
<prototypes>
|
||||
<tableViewCell contentMode="scaleToFill" selectionStyle="default" indentationWidth="10" reuseIdentifier="OrganismTableViewCell" id="WVb-th-o8c" customClass="OrganismTableViewCell" customModule="CoreStoreDemo" customModuleProvider="target">
|
||||
<rect key="frame" x="0.0" y="22" width="600" height="44"/>
|
||||
<autoresizingMask key="autoresizingMask"/>
|
||||
<tableViewCellContentView key="contentView" opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center" tableViewCell="WVb-th-o8c" id="JBq-Ml-a9p">
|
||||
<rect key="frame" x="0.0" y="0.0" width="600" height="43.5"/>
|
||||
<autoresizingMask key="autoresizingMask"/>
|
||||
<subviews>
|
||||
<button opaque="NO" contentMode="scaleToFill" horizontalHuggingPriority="750" contentHorizontalAlignment="center" contentVerticalAlignment="center" buttonType="roundedRect" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="OQf-Bd-Zze">
|
||||
<rect key="frame" x="520" y="8" width="72" height="27.5"/>
|
||||
<fontDescription key="fontDescription" type="boldSystem" pointSize="15"/>
|
||||
<inset key="contentEdgeInsets" minX="7" minY="0.0" maxX="7" maxY="0.0"/>
|
||||
<state key="normal" title="mutate!"/>
|
||||
<connections>
|
||||
<action selector="mutateButtonTouchUpInside:" destination="WVb-th-o8c" eventType="touchUpInside" id="REw-UX-rJ0"/>
|
||||
</connections>
|
||||
</button>
|
||||
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="Label" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="VZk-6K-4ut">
|
||||
<rect key="frame" x="15" y="8" width="495" height="27.5"/>
|
||||
<fontDescription key="fontDescription" name="HelveticaNeue-Thin" family="Helvetica Neue" pointSize="17"/>
|
||||
<color key="textColor" red="0.20392156859999999" green="0.28627450980000002" blue="0.36862745099999999" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
|
||||
<nil key="highlightedColor"/>
|
||||
</label>
|
||||
</subviews>
|
||||
<constraints>
|
||||
<constraint firstItem="OQf-Bd-Zze" firstAttribute="top" secondItem="JBq-Ml-a9p" secondAttribute="topMargin" id="39z-i5-EeS"/>
|
||||
<constraint firstItem="VZk-6K-4ut" firstAttribute="top" secondItem="JBq-Ml-a9p" secondAttribute="topMargin" id="WO1-gf-MIu"/>
|
||||
<constraint firstItem="VZk-6K-4ut" firstAttribute="leading" secondItem="JBq-Ml-a9p" secondAttribute="leadingMargin" constant="7" id="X0N-Il-F26"/>
|
||||
<constraint firstAttribute="bottomMargin" secondItem="OQf-Bd-Zze" secondAttribute="bottom" id="YwC-dw-rGI"/>
|
||||
<constraint firstItem="OQf-Bd-Zze" firstAttribute="leading" secondItem="VZk-6K-4ut" secondAttribute="trailing" constant="10" id="mo1-NZ-iPa"/>
|
||||
<constraint firstAttribute="bottomMargin" secondItem="VZk-6K-4ut" secondAttribute="bottom" id="ucK-FJ-7v4"/>
|
||||
<constraint firstItem="OQf-Bd-Zze" firstAttribute="trailing" secondItem="JBq-Ml-a9p" secondAttribute="trailingMargin" id="v3e-PY-3wW"/>
|
||||
</constraints>
|
||||
</tableViewCellContentView>
|
||||
<connections>
|
||||
<outlet property="dnaLabel" destination="VZk-6K-4ut" id="CSU-Ig-qMu"/>
|
||||
<outlet property="mutateButton" destination="OQf-Bd-Zze" id="5gd-Jx-tMT"/>
|
||||
</connections>
|
||||
</tableViewCell>
|
||||
</prototypes>
|
||||
<connections>
|
||||
<outlet property="dataSource" destination="iVv-Vc-nCL" id="yp2-X4-fhE"/>
|
||||
<outlet property="delegate" destination="iVv-Vc-nCL" id="V5b-s8-XOl"/>
|
||||
</connections>
|
||||
</tableView>
|
||||
<view contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="XKA-Ub-c2X">
|
||||
<rect key="frame" x="0.0" y="64" width="600" height="260"/>
|
||||
<subviews>
|
||||
<view contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="i7U-bW-juB" customClass="UIButton">
|
||||
<rect key="frame" x="0.0" y="0.0" width="600" height="260"/>
|
||||
<subviews>
|
||||
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="Organism" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="zxy-nY-P44">
|
||||
<rect key="frame" x="20" y="90.5" width="560" height="26.5"/>
|
||||
<fontDescription key="fontDescription" name="HelveticaNeue-Bold" family="Helvetica Neue" pointSize="22"/>
|
||||
<color key="textColor" red="0.92549019610000005" green="0.94117647059999998" blue="0.94509803920000002" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
|
||||
<nil key="highlightedColor"/>
|
||||
</label>
|
||||
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="attributes" lineBreakMode="wordWrap" numberOfLines="0" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="6Ac-xl-ldZ">
|
||||
<rect key="frame" x="20" y="131.5" width="560" height="20.5"/>
|
||||
<fontDescription key="fontDescription" name="HelveticaNeue-Light" family="Helvetica Neue" pointSize="17"/>
|
||||
<color key="textColor" red="0.92549019610000005" green="0.94117647059999998" blue="0.94509803920000002" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
|
||||
<nil key="highlightedColor"/>
|
||||
</label>
|
||||
<segmentedControl opaque="NO" contentMode="scaleToFill" contentHorizontalAlignment="left" contentVerticalAlignment="top" segmentControlStyle="plain" selectedSegmentIndex="0" translatesAutoresizingMaskIntoConstraints="NO" id="rAZ-eJ-sxy">
|
||||
<rect key="frame" x="20" y="20" width="560" height="29"/>
|
||||
<segments>
|
||||
<segment title="First"/>
|
||||
<segment title="Second"/>
|
||||
<segment title=""/>
|
||||
</segments>
|
||||
<color key="tintColor" red="1" green="1" blue="1" alpha="1" colorSpace="calibratedRGB"/>
|
||||
<connections>
|
||||
<action selector="segmentedControlValueChanged:" destination="iVv-Vc-nCL" eventType="valueChanged" id="RwG-kW-RPg"/>
|
||||
</connections>
|
||||
</segmentedControl>
|
||||
<progressView opaque="NO" clipsSubviews="YES" contentMode="scaleToFill" verticalHuggingPriority="750" progress="0.5" translatesAutoresizingMaskIntoConstraints="NO" id="869-wx-Odb">
|
||||
<rect key="frame" x="20" y="68" width="560" height="2"/>
|
||||
<color key="progressTintColor" red="1" green="1" blue="1" alpha="1" colorSpace="calibratedRGB"/>
|
||||
<color key="trackTintColor" white="1" alpha="0.20000000000000001" colorSpace="calibratedWhite"/>
|
||||
</progressView>
|
||||
</subviews>
|
||||
<color key="backgroundColor" red="0.20392156859999999" green="0.28627450980000002" blue="0.36862745099999999" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
|
||||
<constraints>
|
||||
<constraint firstItem="zxy-nY-P44" firstAttribute="leading" secondItem="i7U-bW-juB" secondAttribute="leading" constant="20" id="1u1-Tq-hRn"/>
|
||||
<constraint firstItem="6Ac-xl-ldZ" firstAttribute="top" secondItem="zxy-nY-P44" secondAttribute="bottom" constant="14.5" id="39B-9l-O3g"/>
|
||||
<constraint firstAttribute="trailing" secondItem="zxy-nY-P44" secondAttribute="trailing" constant="20" id="3d5-Zk-rB1"/>
|
||||
<constraint firstAttribute="trailing" secondItem="6Ac-xl-ldZ" secondAttribute="trailing" constant="20" id="EJq-uA-8dQ"/>
|
||||
<constraint firstItem="rAZ-eJ-sxy" firstAttribute="top" secondItem="i7U-bW-juB" secondAttribute="top" constant="20" id="Ey7-mP-RNA"/>
|
||||
<constraint firstItem="zxy-nY-P44" firstAttribute="top" secondItem="869-wx-Odb" secondAttribute="bottom" constant="20.5" id="GU3-JM-b99"/>
|
||||
<constraint firstItem="rAZ-eJ-sxy" firstAttribute="leading" secondItem="i7U-bW-juB" secondAttribute="leading" constant="20" id="KKJ-gG-pFL"/>
|
||||
<constraint firstAttribute="trailing" secondItem="869-wx-Odb" secondAttribute="trailing" constant="20" id="Lni-gD-7h0"/>
|
||||
<constraint firstItem="869-wx-Odb" firstAttribute="top" secondItem="rAZ-eJ-sxy" secondAttribute="bottom" constant="20" id="QBz-cP-SVZ"/>
|
||||
<constraint firstAttribute="trailing" secondItem="rAZ-eJ-sxy" secondAttribute="trailing" constant="20" id="WoD-cr-aj9"/>
|
||||
<constraint firstAttribute="height" constant="260" id="XTa-ql-yEW"/>
|
||||
<constraint firstItem="6Ac-xl-ldZ" firstAttribute="leading" secondItem="i7U-bW-juB" secondAttribute="leading" constant="20" id="jkv-ow-f0q"/>
|
||||
<constraint firstItem="869-wx-Odb" firstAttribute="leading" secondItem="i7U-bW-juB" secondAttribute="leading" constant="20" id="qgE-y5-uh8"/>
|
||||
</constraints>
|
||||
</view>
|
||||
</subviews>
|
||||
<color key="backgroundColor" white="1" alpha="1" colorSpace="calibratedWhite"/>
|
||||
<constraints>
|
||||
<constraint firstAttribute="height" constant="260" id="90R-Mf-iAB"/>
|
||||
<constraint firstItem="i7U-bW-juB" firstAttribute="leading" secondItem="XKA-Ub-c2X" secondAttribute="leading" id="e9h-f4-c37"/>
|
||||
<constraint firstItem="i7U-bW-juB" firstAttribute="top" secondItem="XKA-Ub-c2X" secondAttribute="top" id="vJV-dl-RLx"/>
|
||||
<constraint firstAttribute="trailing" secondItem="i7U-bW-juB" secondAttribute="trailing" id="wYt-hg-yKM"/>
|
||||
</constraints>
|
||||
</view>
|
||||
</subviews>
|
||||
<color key="backgroundColor" white="1" alpha="1" colorSpace="calibratedWhite"/>
|
||||
<constraints>
|
||||
<constraint firstAttribute="trailing" secondItem="XKA-Ub-c2X" secondAttribute="trailing" id="U0P-51-KT9"/>
|
||||
<constraint firstAttribute="trailing" secondItem="WUc-3Y-Quw" secondAttribute="trailing" id="i7I-7B-97K"/>
|
||||
<constraint firstItem="WUc-3Y-Quw" firstAttribute="leading" secondItem="75P-2m-6cr" secondAttribute="leading" id="i8b-GU-yFg"/>
|
||||
<constraint firstItem="XKA-Ub-c2X" firstAttribute="top" secondItem="Un6-jI-efh" secondAttribute="bottom" id="lU2-wP-RQb"/>
|
||||
<constraint firstItem="XKA-Ub-c2X" firstAttribute="leading" secondItem="75P-2m-6cr" secondAttribute="leading" id="oa7-qv-9am"/>
|
||||
<constraint firstItem="t9A-zf-Iew" firstAttribute="top" secondItem="WUc-3Y-Quw" secondAttribute="bottom" id="tts-uy-w5J"/>
|
||||
<constraint firstItem="WUc-3Y-Quw" firstAttribute="top" secondItem="XKA-Ub-c2X" secondAttribute="bottom" id="vjy-iN-Xi7"/>
|
||||
</constraints>
|
||||
</view>
|
||||
<navigationItem key="navigationItem" title="Evolution" id="uc7-DN-PYG"/>
|
||||
<connections>
|
||||
<outlet property="headerContainer" destination="i7U-bW-juB" id="hpf-7a-yBd"/>
|
||||
<outlet property="organismLabel" destination="6Ac-xl-ldZ" id="pgF-ej-ovy"/>
|
||||
<outlet property="progressView" destination="869-wx-Odb" id="um3-UM-uOP"/>
|
||||
<outlet property="segmentedControl" destination="rAZ-eJ-sxy" id="K3Q-X2-Jrm"/>
|
||||
<outlet property="tableView" destination="WUc-3Y-Quw" id="3Ki-v0-lTb"/>
|
||||
<outlet property="titleLabel" destination="zxy-nY-P44" id="9JO-hP-yVp"/>
|
||||
</connections>
|
||||
</viewController>
|
||||
<placeholder placeholderIdentifier="IBFirstResponder" id="LzB-gZ-6fG" userLabel="First Responder" sceneMemberID="firstResponder"/>
|
||||
</objects>
|
||||
<point key="canvasLocation" x="3694" y="4113"/>
|
||||
</scene>
|
||||
<!--CoreStore Demos-->
|
||||
<scene sceneID="0Be-vc-h1W">
|
||||
<objects>
|
||||
@@ -100,17 +283,21 @@
|
||||
<tableViewSection id="wIP-Hn-YfF">
|
||||
<cells>
|
||||
<tableViewCell contentMode="scaleToFill" selectionStyle="default" accessoryType="disclosureIndicator" indentationWidth="10" textLabel="Q3n-Df-v1t" detailTextLabel="Hbn-cf-Y7m" style="IBUITableViewCellStyleSubtitle" id="AXm-KE-45G">
|
||||
<rect key="frame" x="0.0" y="99" width="600" height="50"/>
|
||||
<autoresizingMask key="autoresizingMask"/>
|
||||
<tableViewCellContentView key="contentView" opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center" tableViewCell="AXm-KE-45G" id="9te-Wx-hkf">
|
||||
<rect key="frame" x="0.0" y="0.0" width="567" height="49.5"/>
|
||||
<autoresizingMask key="autoresizingMask"/>
|
||||
<subviews>
|
||||
<label opaque="NO" multipleTouchEnabled="YES" contentMode="left" text="Accounts" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" id="Q3n-Df-v1t">
|
||||
<rect key="frame" x="15" y="6" width="82" height="24"/>
|
||||
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMaxY="YES"/>
|
||||
<fontDescription key="fontDescription" name="HelveticaNeue-Light" family="Helvetica Neue" pointSize="20"/>
|
||||
<color key="textColor" red="0.17254901960784313" green="0.24313725490196078" blue="0.31372549019607843" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
|
||||
<nil key="highlightedColor"/>
|
||||
</label>
|
||||
<label opaque="NO" multipleTouchEnabled="YES" contentMode="left" text="Setting up multiple persistent store configurations" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" id="Hbn-cf-Y7m">
|
||||
<rect key="frame" x="15" y="30" width="263.5" height="13.5"/>
|
||||
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMaxY="YES"/>
|
||||
<fontDescription key="fontDescription" type="system" pointSize="11"/>
|
||||
<color key="textColor" red="0.17254901959999999" green="0.24313725489999999" blue="0.31372549020000001" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
|
||||
@@ -123,17 +310,21 @@
|
||||
</connections>
|
||||
</tableViewCell>
|
||||
<tableViewCell contentMode="scaleToFill" selectionStyle="default" accessoryType="disclosureIndicator" indentationWidth="10" textLabel="vpt-cT-gMo" detailTextLabel="ou9-TZ-8bf" style="IBUITableViewCellStyleSubtitle" id="fsb-zw-8Ii">
|
||||
<rect key="frame" x="0.0" y="149" width="600" height="50"/>
|
||||
<autoresizingMask key="autoresizingMask"/>
|
||||
<tableViewCellContentView key="contentView" opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center" tableViewCell="fsb-zw-8Ii" id="Upm-AO-Fw3">
|
||||
<rect key="frame" x="0.0" y="0.0" width="567" height="49.5"/>
|
||||
<autoresizingMask key="autoresizingMask"/>
|
||||
<subviews>
|
||||
<label opaque="NO" multipleTouchEnabled="YES" contentMode="left" text="Colors" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" id="vpt-cT-gMo">
|
||||
<rect key="frame" x="15" y="6" width="56" height="24"/>
|
||||
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMaxY="YES"/>
|
||||
<fontDescription key="fontDescription" name="HelveticaNeue-Light" family="Helvetica Neue" pointSize="20"/>
|
||||
<color key="textColor" red="0.17254901959999999" green="0.24313725489999999" blue="0.31372549020000001" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
|
||||
<nil key="highlightedColor"/>
|
||||
</label>
|
||||
<label opaque="NO" multipleTouchEnabled="YES" contentMode="left" text="Observing list changes and single object changes" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" id="ou9-TZ-8bf">
|
||||
<rect key="frame" x="15" y="30" width="260.5" height="13.5"/>
|
||||
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMaxY="YES"/>
|
||||
<fontDescription key="fontDescription" type="system" pointSize="11"/>
|
||||
<color key="textColor" red="0.17254901959999999" green="0.24313725489999999" blue="0.31372549020000001" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
|
||||
@@ -146,17 +337,21 @@
|
||||
</connections>
|
||||
</tableViewCell>
|
||||
<tableViewCell contentMode="scaleToFill" selectionStyle="default" accessoryType="disclosureIndicator" indentationWidth="10" textLabel="UbU-Kd-yrY" detailTextLabel="uP1-Jc-o9v" style="IBUITableViewCellStyleSubtitle" id="ekW-PJ-mbo">
|
||||
<rect key="frame" x="0.0" y="199" width="600" height="50"/>
|
||||
<autoresizingMask key="autoresizingMask"/>
|
||||
<tableViewCellContentView key="contentView" opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center" tableViewCell="ekW-PJ-mbo" id="CYq-mg-PVS">
|
||||
<rect key="frame" x="0.0" y="0.0" width="567" height="49.5"/>
|
||||
<autoresizingMask key="autoresizingMask"/>
|
||||
<subviews>
|
||||
<label opaque="NO" multipleTouchEnabled="YES" contentMode="left" text="Placemarks" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" id="UbU-Kd-yrY">
|
||||
<rect key="frame" x="15" y="6" width="100.5" height="24"/>
|
||||
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMaxY="YES"/>
|
||||
<fontDescription key="fontDescription" name="HelveticaNeue-Light" family="Helvetica Neue" pointSize="20"/>
|
||||
<color key="textColor" red="0.17254901959999999" green="0.24313725489999999" blue="0.31372549020000001" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
|
||||
<nil key="highlightedColor"/>
|
||||
</label>
|
||||
<label opaque="NO" multipleTouchEnabled="YES" contentMode="left" text="Making changes with transactions" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" id="uP1-Jc-o9v">
|
||||
<rect key="frame" x="15" y="30" width="179" height="13.5"/>
|
||||
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMaxY="YES"/>
|
||||
<fontDescription key="fontDescription" type="system" pointSize="11"/>
|
||||
<color key="textColor" red="0.17254901959999999" green="0.24313725489999999" blue="0.31372549020000001" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
|
||||
@@ -169,17 +364,21 @@
|
||||
</connections>
|
||||
</tableViewCell>
|
||||
<tableViewCell contentMode="scaleToFill" selectionStyle="default" accessoryType="disclosureIndicator" indentationWidth="10" textLabel="C8Y-0y-lEG" detailTextLabel="jZw-qE-0ws" style="IBUITableViewCellStyleSubtitle" id="ph1-8z-C1m">
|
||||
<rect key="frame" x="0.0" y="249" width="600" height="50"/>
|
||||
<autoresizingMask key="autoresizingMask"/>
|
||||
<tableViewCellContentView key="contentView" opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center" tableViewCell="ph1-8z-C1m" id="nNz-rd-ksg">
|
||||
<rect key="frame" x="0.0" y="0.0" width="567" height="49.5"/>
|
||||
<autoresizingMask key="autoresizingMask"/>
|
||||
<subviews>
|
||||
<label opaque="NO" multipleTouchEnabled="YES" contentMode="left" text="Time Zones" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" id="C8Y-0y-lEG">
|
||||
<rect key="frame" x="15" y="6" width="101.5" height="24"/>
|
||||
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMaxY="YES"/>
|
||||
<fontDescription key="fontDescription" name="HelveticaNeue-Light" family="Helvetica Neue" pointSize="20"/>
|
||||
<color key="textColor" red="0.17254901959999999" green="0.24313725489999999" blue="0.31372549020000001" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
|
||||
<nil key="highlightedColor"/>
|
||||
</label>
|
||||
<label opaque="NO" multipleTouchEnabled="YES" contentMode="left" text="Fetching objects and raw values" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" id="jZw-qE-0ws">
|
||||
<rect key="frame" x="15" y="30" width="168.5" height="13.5"/>
|
||||
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMaxY="YES"/>
|
||||
<fontDescription key="fontDescription" type="system" pointSize="11"/>
|
||||
<color key="textColor" red="0.17254901959999999" green="0.24313725489999999" blue="0.31372549020000001" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
|
||||
@@ -192,17 +391,21 @@
|
||||
</connections>
|
||||
</tableViewCell>
|
||||
<tableViewCell contentMode="scaleToFill" selectionStyle="default" accessoryType="disclosureIndicator" indentationWidth="10" textLabel="ZfY-Aq-Ykq" detailTextLabel="QzD-9b-k1j" style="IBUITableViewCellStyleSubtitle" id="wyK-rk-3tI">
|
||||
<rect key="frame" x="0.0" y="299" width="600" height="50"/>
|
||||
<autoresizingMask key="autoresizingMask"/>
|
||||
<tableViewCellContentView key="contentView" opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center" tableViewCell="wyK-rk-3tI" id="fLd-KK-QcW">
|
||||
<rect key="frame" x="0.0" y="0.0" width="567" height="49.5"/>
|
||||
<autoresizingMask key="autoresizingMask"/>
|
||||
<subviews>
|
||||
<label opaque="NO" multipleTouchEnabled="YES" contentMode="left" text="Logger" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" id="ZfY-Aq-Ykq">
|
||||
<rect key="frame" x="15" y="6" width="61" height="24"/>
|
||||
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMaxY="YES"/>
|
||||
<fontDescription key="fontDescription" name="HelveticaNeue-Light" family="Helvetica Neue" pointSize="20"/>
|
||||
<color key="textColor" red="0.17254901959999999" green="0.24313725489999999" blue="0.31372549020000001" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
|
||||
<nil key="highlightedColor"/>
|
||||
</label>
|
||||
<label opaque="NO" multipleTouchEnabled="YES" contentMode="left" text="Implementing a custom logger" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" id="QzD-9b-k1j">
|
||||
<rect key="frame" x="15" y="30" width="159" height="13.5"/>
|
||||
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMaxY="YES"/>
|
||||
<fontDescription key="fontDescription" type="system" pointSize="11"/>
|
||||
<color key="textColor" red="0.17254901959999999" green="0.24313725489999999" blue="0.31372549020000001" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
|
||||
@@ -214,6 +417,33 @@
|
||||
<segue destination="5yy-0N-QDU" kind="show" id="5D7-Xp-1HT"/>
|
||||
</connections>
|
||||
</tableViewCell>
|
||||
<tableViewCell contentMode="scaleToFill" selectionStyle="default" accessoryType="disclosureIndicator" indentationWidth="10" textLabel="hSG-mG-YBw" detailTextLabel="X9P-TQ-LYh" style="IBUITableViewCellStyleSubtitle" id="xTM-Cf-0if">
|
||||
<rect key="frame" x="0.0" y="349" width="600" height="50"/>
|
||||
<autoresizingMask key="autoresizingMask"/>
|
||||
<tableViewCellContentView key="contentView" opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center" tableViewCell="xTM-Cf-0if" id="DfO-BW-krd">
|
||||
<rect key="frame" x="0.0" y="0.0" width="567" height="49.5"/>
|
||||
<autoresizingMask key="autoresizingMask"/>
|
||||
<subviews>
|
||||
<label opaque="NO" multipleTouchEnabled="YES" contentMode="left" text="Evolution" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" id="hSG-mG-YBw">
|
||||
<rect key="frame" x="15" y="6" width="78.5" height="24"/>
|
||||
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMaxY="YES"/>
|
||||
<fontDescription key="fontDescription" name="HelveticaNeue-Light" family="Helvetica Neue" pointSize="20"/>
|
||||
<color key="textColor" red="0.17254901959999999" green="0.24313725489999999" blue="0.31372549020000001" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
|
||||
<nil key="highlightedColor"/>
|
||||
</label>
|
||||
<label opaque="NO" multipleTouchEnabled="YES" contentMode="left" text="Migrating and de-migrating stores" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" id="X9P-TQ-LYh">
|
||||
<rect key="frame" x="15" y="30" width="179.5" height="13.5"/>
|
||||
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMaxY="YES"/>
|
||||
<fontDescription key="fontDescription" type="system" pointSize="11"/>
|
||||
<color key="textColor" red="0.17254901959999999" green="0.24313725489999999" blue="0.31372549020000001" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
|
||||
<nil key="highlightedColor"/>
|
||||
</label>
|
||||
</subviews>
|
||||
</tableViewCellContentView>
|
||||
<connections>
|
||||
<segue destination="iVv-Vc-nCL" kind="show" id="HbO-rU-Qfj"/>
|
||||
</connections>
|
||||
</tableViewCell>
|
||||
</cells>
|
||||
</tableViewSection>
|
||||
</sections>
|
||||
@@ -237,18 +467,18 @@
|
||||
<viewControllerLayoutGuide type="bottom" id="aI4-O3-OCi"/>
|
||||
</layoutGuides>
|
||||
<view key="view" contentMode="scaleToFill" id="w8K-eN-RvU">
|
||||
<rect key="frame" x="0.0" y="0.0" width="600" height="268"/>
|
||||
<rect key="frame" x="0.0" y="0.0" width="592" height="268"/>
|
||||
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
|
||||
<subviews>
|
||||
<view contentMode="scaleToFill" verticalCompressionResistancePriority="250" translatesAutoresizingMaskIntoConstraints="NO" id="NhC-oM-bkd">
|
||||
<rect key="frame" x="16" y="70" width="568" height="36"/>
|
||||
<rect key="frame" x="20" y="69.5" width="552" height="36.5"/>
|
||||
<color key="backgroundColor" white="1" alpha="1" colorSpace="calibratedWhite"/>
|
||||
<constraints>
|
||||
<constraint firstAttribute="height" relation="greaterThanOrEqual" id="TIX-qi-B34"/>
|
||||
</constraints>
|
||||
</view>
|
||||
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" verticalCompressionResistancePriority="250" text="Label" textAlignment="center" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" minimumScaleFactor="0.5" adjustsLetterSpacingToFitWidth="YES" translatesAutoresizingMaskIntoConstraints="NO" id="Vfe-Yq-3Xa">
|
||||
<rect key="frame" x="16" y="116" width="568" height="18"/>
|
||||
<rect key="frame" x="20" y="116" width="552" height="18"/>
|
||||
<constraints>
|
||||
<constraint firstAttribute="height" relation="greaterThanOrEqual" id="4h9-ha-EzR"/>
|
||||
</constraints>
|
||||
@@ -257,43 +487,43 @@
|
||||
<nil key="highlightedColor"/>
|
||||
</label>
|
||||
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="Hue" textAlignment="right" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="sgg-Md-Nf3">
|
||||
<rect key="frame" x="16" y="154" width="74" height="18"/>
|
||||
<rect key="frame" x="20" y="154" width="74" height="18"/>
|
||||
<fontDescription key="fontDescription" type="system" pointSize="15"/>
|
||||
<color key="textColor" red="0.0" green="0.0" blue="0.0" alpha="1" colorSpace="calibratedRGB"/>
|
||||
<nil key="highlightedColor"/>
|
||||
</label>
|
||||
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="Saturation" textAlignment="right" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="rry-vh-bRK">
|
||||
<rect key="frame" x="16" y="192" width="74" height="18"/>
|
||||
<rect key="frame" x="20" y="192" width="74" height="18"/>
|
||||
<fontDescription key="fontDescription" type="system" pointSize="15"/>
|
||||
<color key="textColor" red="0.0" green="0.0" blue="0.0" alpha="1" colorSpace="calibratedRGB"/>
|
||||
<nil key="highlightedColor"/>
|
||||
</label>
|
||||
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="Brightness" textAlignment="right" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="vTa-ly-eyO">
|
||||
<rect key="frame" x="16" y="230" width="74" height="18"/>
|
||||
<rect key="frame" x="20" y="230" width="74" height="18"/>
|
||||
<fontDescription key="fontDescription" type="system" pointSize="15"/>
|
||||
<color key="textColor" red="0.0" green="0.0" blue="0.0" alpha="1" colorSpace="calibratedRGB"/>
|
||||
<nil key="highlightedColor"/>
|
||||
</label>
|
||||
<slider opaque="NO" contentMode="scaleToFill" contentHorizontalAlignment="center" contentVerticalAlignment="center" minValue="0.0" maxValue="359" translatesAutoresizingMaskIntoConstraints="NO" id="YQ6-fq-3Wb">
|
||||
<rect key="frame" x="98" y="148" width="488" height="31"/>
|
||||
<rect key="frame" x="102" y="148" width="472" height="31"/>
|
||||
<connections>
|
||||
<action selector="hueSliderValueDidChange:" destination="dX3-kR-CYC" eventType="valueChanged" id="9Hy-3h-llE"/>
|
||||
</connections>
|
||||
</slider>
|
||||
<slider opaque="NO" contentMode="scaleToFill" contentHorizontalAlignment="center" contentVerticalAlignment="center" value="1" minValue="0.0" maxValue="1" translatesAutoresizingMaskIntoConstraints="NO" id="xXz-78-tAd">
|
||||
<rect key="frame" x="98" y="186" width="488" height="31"/>
|
||||
<rect key="frame" x="102" y="186" width="472" height="31"/>
|
||||
<connections>
|
||||
<action selector="saturationSliderValueDidChange:" destination="dX3-kR-CYC" eventType="valueChanged" id="qtU-ua-ZTc"/>
|
||||
</connections>
|
||||
</slider>
|
||||
<slider opaque="NO" contentMode="scaleToFill" contentHorizontalAlignment="center" contentVerticalAlignment="center" value="0.5" minValue="0.0" maxValue="1" translatesAutoresizingMaskIntoConstraints="NO" id="hpy-2d-eOP">
|
||||
<rect key="frame" x="98" y="224" width="488" height="31"/>
|
||||
<rect key="frame" x="102" y="224" width="472" height="31"/>
|
||||
<connections>
|
||||
<action selector="brightnessSliderValueDidChange:" destination="dX3-kR-CYC" eventType="valueChanged" id="F09-EP-2iD"/>
|
||||
</connections>
|
||||
</slider>
|
||||
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="Label" textAlignment="center" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="p4O-tf-dgt">
|
||||
<rect key="frame" x="16" y="49" width="568" height="21"/>
|
||||
<rect key="frame" x="20" y="49" width="552" height="20.5"/>
|
||||
<fontDescription key="fontDescription" type="boldSystem" pointSize="17"/>
|
||||
<color key="textColor" red="0.0" green="0.0" blue="0.0" alpha="1" colorSpace="calibratedRGB"/>
|
||||
<nil key="highlightedColor"/>
|
||||
@@ -361,17 +591,17 @@
|
||||
<viewControllerLayoutGuide type="bottom" id="LNL-mj-D7l"/>
|
||||
</layoutGuides>
|
||||
<view key="view" contentMode="scaleToFill" id="6x3-vn-Egt">
|
||||
<rect key="frame" x="0.0" y="64" width="600" height="600"/>
|
||||
<rect key="frame" x="0.0" y="0.0" width="600" height="600"/>
|
||||
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
|
||||
<subviews>
|
||||
<containerView opaque="NO" contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="L5f-tW-lXf">
|
||||
<rect key="frame" x="0.0" y="64" width="600" height="268"/>
|
||||
<rect key="frame" x="4" y="64" width="592" height="268"/>
|
||||
<connections>
|
||||
<segue destination="5Fw-je-9gI" kind="embed" id="YcI-2Z-ijV"/>
|
||||
</connections>
|
||||
</containerView>
|
||||
<containerView opaque="NO" contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="6So-f3-4Gp">
|
||||
<rect key="frame" x="0.0" y="332" width="600" height="268"/>
|
||||
<rect key="frame" x="4" y="332" width="592" height="268"/>
|
||||
<connections>
|
||||
<segue destination="sll-yo-mBc" kind="embed" id="AAl-HS-dq2"/>
|
||||
</connections>
|
||||
@@ -425,14 +655,16 @@
|
||||
<!--List Observer-->
|
||||
<scene sceneID="gkX-bd-Rel">
|
||||
<objects>
|
||||
<tableViewController id="3AE-ED-0oj" customClass="ObjectListObserverDemoViewController" customModule="CoreStoreDemo" customModuleProvider="target" sceneMemberID="viewController">
|
||||
<tableViewController id="3AE-ED-0oj" customClass="ListObserverDemoViewController" customModule="CoreStoreDemo" customModuleProvider="target" sceneMemberID="viewController">
|
||||
<tableView key="view" clipsSubviews="YES" contentMode="scaleToFill" alwaysBounceVertical="YES" dataMode="prototypes" style="plain" separatorStyle="default" rowHeight="44" sectionHeaderHeight="22" sectionFooterHeight="22" id="DAz-BE-6Ca">
|
||||
<rect key="frame" x="0.0" y="0.0" width="600" height="268"/>
|
||||
<rect key="frame" x="0.0" y="0.0" width="592" height="268"/>
|
||||
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
|
||||
<prototypes>
|
||||
<tableViewCell contentMode="scaleToFill" selectionStyle="default" accessoryType="disclosureIndicator" indentationWidth="10" reuseIdentifier="PaletteTableViewCell" id="G3X-70-BCD" customClass="PaletteTableViewCell" customModule="CoreStoreDemo" customModuleProvider="target">
|
||||
<rect key="frame" x="0.0" y="66" width="592" height="44"/>
|
||||
<autoresizingMask key="autoresizingMask"/>
|
||||
<tableViewCellContentView key="contentView" opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center" tableViewCell="G3X-70-BCD" id="aT8-nz-i5l">
|
||||
<rect key="frame" x="0.0" y="0.0" width="559" height="43.5"/>
|
||||
<autoresizingMask key="autoresizingMask"/>
|
||||
<subviews>
|
||||
<view contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="uQX-PI-UWF">
|
||||
@@ -482,15 +714,17 @@
|
||||
<!--List Observer-->
|
||||
<scene sceneID="iDB-TD-It9">
|
||||
<objects>
|
||||
<tableViewController id="lCE-i6-UCT" customClass="ObjectListObserverDemoViewController" customModule="CoreStoreDemo" customModuleProvider="target" sceneMemberID="viewController">
|
||||
<tableViewController id="lCE-i6-UCT" customClass="ListObserverDemoViewController" customModule="CoreStoreDemo" customModuleProvider="target" sceneMemberID="viewController">
|
||||
<tableView key="view" clipsSubviews="YES" contentMode="scaleToFill" alwaysBounceVertical="YES" dataMode="prototypes" style="plain" separatorStyle="default" rowHeight="44" sectionHeaderHeight="22" sectionFooterHeight="22" id="Zba-8M-Zd7">
|
||||
<rect key="frame" x="0.0" y="0.0" width="600" height="268"/>
|
||||
<rect key="frame" x="0.0" y="0.0" width="592" height="268"/>
|
||||
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
|
||||
<color key="backgroundColor" white="1" alpha="1" colorSpace="calibratedWhite"/>
|
||||
<prototypes>
|
||||
<tableViewCell contentMode="scaleToFill" selectionStyle="default" accessoryType="disclosureIndicator" indentationWidth="10" reuseIdentifier="PaletteTableViewCell" id="zSO-3e-OVq" customClass="PaletteTableViewCell" customModule="CoreStoreDemo" customModuleProvider="target">
|
||||
<rect key="frame" x="0.0" y="66" width="592" height="44"/>
|
||||
<autoresizingMask key="autoresizingMask"/>
|
||||
<tableViewCellContentView key="contentView" opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center" tableViewCell="zSO-3e-OVq" id="cHA-by-n4b">
|
||||
<rect key="frame" x="0.0" y="0.0" width="559" height="43.5"/>
|
||||
<autoresizingMask key="autoresizingMask"/>
|
||||
<subviews>
|
||||
<view contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="5uq-Yi-XwH">
|
||||
@@ -571,7 +805,7 @@
|
||||
<viewControllerLayoutGuide type="bottom" id="RZg-hi-T8O"/>
|
||||
</layoutGuides>
|
||||
<view key="view" contentMode="scaleToFill" id="k4s-iL-Krh">
|
||||
<rect key="frame" x="0.0" y="0.0" width="600" height="536"/>
|
||||
<rect key="frame" x="0.0" y="64" width="600" height="536"/>
|
||||
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
|
||||
<subviews>
|
||||
<mapView clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="scaleToFill" mapType="standard" translatesAutoresizingMaskIntoConstraints="NO" id="V2U-0R-Ts0">
|
||||
@@ -724,12 +958,14 @@
|
||||
</view>
|
||||
<prototypes>
|
||||
<tableViewCell contentMode="scaleToFill" selectionStyle="default" accessoryType="disclosureIndicator" indentationWidth="10" reuseIdentifier="UITableViewCell" textLabel="6db-P0-6Ms" style="IBUITableViewCellStyleDefault" id="vUr-WV-qur">
|
||||
<rect key="frame" x="0.0" y="0.0" width="600" height="44"/>
|
||||
<rect key="frame" x="0.0" y="102" width="600" height="44"/>
|
||||
<autoresizingMask key="autoresizingMask"/>
|
||||
<tableViewCellContentView key="contentView" opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center" tableViewCell="vUr-WV-qur" id="Vr0-hE-cn9">
|
||||
<rect key="frame" x="0.0" y="0.0" width="567" height="43.5"/>
|
||||
<autoresizingMask key="autoresizingMask"/>
|
||||
<subviews>
|
||||
<label opaque="NO" multipleTouchEnabled="YES" contentMode="left" text="Title" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" id="6db-P0-6Ms">
|
||||
<rect key="frame" x="15" y="0.0" width="550" height="43.5"/>
|
||||
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMaxY="YES"/>
|
||||
<fontDescription key="fontDescription" name="HelveticaNeue-Light" family="Helvetica Neue" pointSize="18"/>
|
||||
<color key="textColor" red="0.17254901959999999" green="0.24313725489999999" blue="0.31372549020000001" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
|
||||
@@ -776,17 +1012,21 @@
|
||||
<color key="separatorColor" red="0.20392156859999999" green="0.28627450980000002" blue="0.36862745099999999" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
|
||||
<prototypes>
|
||||
<tableViewCell contentMode="scaleToFill" selectionStyle="none" indentationWidth="10" reuseIdentifier="UITableViewCell" textLabel="RgX-yK-1L2" detailTextLabel="QZ4-A2-x4h" style="IBUITableViewCellStyleSubtitle" id="uBt-Iy-nWP">
|
||||
<rect key="frame" x="0.0" y="100" width="600" height="60"/>
|
||||
<autoresizingMask key="autoresizingMask"/>
|
||||
<tableViewCellContentView key="contentView" opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center" tableViewCell="uBt-Iy-nWP" id="6SD-ur-9zp">
|
||||
<rect key="frame" x="0.0" y="0.0" width="600" height="59.5"/>
|
||||
<autoresizingMask key="autoresizingMask"/>
|
||||
<subviews>
|
||||
<label opaque="NO" multipleTouchEnabled="YES" contentMode="left" text="name" lineBreakMode="wordWrap" numberOfLines="0" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" id="RgX-yK-1L2">
|
||||
<rect key="frame" x="15" y="11" width="48.5" height="24"/>
|
||||
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMaxY="YES"/>
|
||||
<fontDescription key="fontDescription" name="HelveticaNeue-Light" family="Helvetica Neue" pointSize="20"/>
|
||||
<color key="textColor" red="0.17254901959999999" green="0.24313725489999999" blue="0.31372549020000001" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
|
||||
<nil key="highlightedColor"/>
|
||||
</label>
|
||||
<label opaque="NO" multipleTouchEnabled="YES" contentMode="left" text="offset" lineBreakMode="wordWrap" numberOfLines="0" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" id="QZ4-A2-x4h">
|
||||
<rect key="frame" x="15" y="35" width="31" height="13.5"/>
|
||||
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMaxY="YES"/>
|
||||
<fontDescription key="fontDescription" type="system" pointSize="11"/>
|
||||
<color key="textColor" red="0.17254901959999999" green="0.24313725489999999" blue="0.31372549020000001" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
|
||||
@@ -818,17 +1058,21 @@
|
||||
<color key="separatorColor" red="0.20392156859999999" green="0.28627450980000002" blue="0.36862745099999999" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
|
||||
<prototypes>
|
||||
<tableViewCell contentMode="scaleToFill" selectionStyle="none" indentationWidth="10" reuseIdentifier="UITableViewCell" textLabel="Syt-QJ-KXg" detailTextLabel="yHS-dP-IKS" style="IBUITableViewCellStyleSubtitle" id="q7Q-aF-Ftl">
|
||||
<rect key="frame" x="0.0" y="100" width="600" height="60"/>
|
||||
<autoresizingMask key="autoresizingMask"/>
|
||||
<tableViewCellContentView key="contentView" opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center" tableViewCell="q7Q-aF-Ftl" id="fc3-eg-yes">
|
||||
<rect key="frame" x="0.0" y="0.0" width="600" height="59.5"/>
|
||||
<autoresizingMask key="autoresizingMask"/>
|
||||
<subviews>
|
||||
<label opaque="NO" multipleTouchEnabled="YES" contentMode="left" text="name" lineBreakMode="wordWrap" numberOfLines="0" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" id="Syt-QJ-KXg">
|
||||
<rect key="frame" x="15" y="11" width="48.5" height="24"/>
|
||||
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMaxY="YES"/>
|
||||
<fontDescription key="fontDescription" name="HelveticaNeue-Light" family="Helvetica Neue" pointSize="20"/>
|
||||
<color key="textColor" red="0.17254901959999999" green="0.24313725489999999" blue="0.31372549020000001" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
|
||||
<nil key="highlightedColor"/>
|
||||
</label>
|
||||
<label opaque="NO" multipleTouchEnabled="YES" contentMode="left" text="offset" lineBreakMode="wordWrap" numberOfLines="0" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" id="yHS-dP-IKS">
|
||||
<rect key="frame" x="15" y="35" width="31" height="13.5"/>
|
||||
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMaxY="YES"/>
|
||||
<fontDescription key="fontDescription" type="system" pointSize="11"/>
|
||||
<color key="textColor" red="0.17254901959999999" green="0.24313725489999999" blue="0.31372549020000001" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
|
||||
@@ -854,6 +1098,6 @@
|
||||
<image name="second" width="30" height="30"/>
|
||||
</resources>
|
||||
<inferredMetricsTieBreakers>
|
||||
<segue reference="hyN-De-zte"/>
|
||||
<segue reference="fIB-GS-Ppk"/>
|
||||
</inferredMetricsTieBreakers>
|
||||
</document>
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
|
||||
<model userDefinedModelVersionIdentifier="" type="com.apple.IDECoreDataModeler.DataModel" documentVersion="1.0" lastSavedToolsVersion="7701" systemVersion="14D136" minimumToolsVersion="Automatic" macOSVersion="Automatic" iOSVersion="Automatic">
|
||||
<model userDefinedModelVersionIdentifier="" type="com.apple.IDECoreDataModeler.DataModel" documentVersion="1.0" lastSavedToolsVersion="10169.1" systemVersion="15D21" minimumToolsVersion="Automatic">
|
||||
<entity name="Palette" representedClassName="CoreStoreDemo.Palette">
|
||||
<attribute name="brightness" optional="YES" attributeType="Float" defaultValueString="0.0" syncable="YES"/>
|
||||
<attribute name="colorName" optional="YES" transient="YES" attributeType="String" syncable="YES"/>
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
// CoreStoreDemo
|
||||
//
|
||||
// Created by John Rommel Estropia on 2015/06/12.
|
||||
// Copyright (c) 2015 John Rommel Estropia. All rights reserved.
|
||||
// Copyright © 2015 John Rommel Estropia. All rights reserved.
|
||||
//
|
||||
|
||||
import UIKit
|
||||
@@ -15,17 +15,19 @@ private struct Static {
|
||||
static let timeZonesStack: DataStack = {
|
||||
|
||||
let dataStack = DataStack()
|
||||
dataStack.addSQLiteStoreAndWait(
|
||||
"TimeZoneDemo.sqlite",
|
||||
configuration: "FetchingAndQueryingDemo",
|
||||
resetStoreOnMigrationFailure: true
|
||||
try! dataStack.addStorageAndWait(
|
||||
SQLiteStore(
|
||||
fileName: "TimeZoneDemo.sqlite",
|
||||
configuration: "FetchingAndQueryingDemo",
|
||||
localStorageOptions: .RecreateStoreOnModelMismatch
|
||||
)
|
||||
)
|
||||
|
||||
dataStack.beginSynchronous { (transaction) -> Void in
|
||||
|
||||
transaction.deleteAll(From(TimeZone))
|
||||
|
||||
for name in NSTimeZone.knownTimeZoneNames() as! [String] {
|
||||
for name in NSTimeZone.knownTimeZoneNames() {
|
||||
|
||||
let rawTimeZone = NSTimeZone(name: name)!
|
||||
let cachedTimeZone = transaction.create(Into(TimeZone))
|
||||
@@ -37,7 +39,7 @@ private struct Static {
|
||||
cachedTimeZone.daylightSavingTimeOffset = rawTimeZone.daylightSavingTimeOffset
|
||||
}
|
||||
|
||||
transaction.commit()
|
||||
transaction.commitAndWait()
|
||||
}
|
||||
|
||||
return dataStack
|
||||
@@ -97,12 +99,13 @@ class FetchingAndQueryingDemoViewController: UIViewController, UITableViewDataSo
|
||||
// MARK: UITableViewDataSource
|
||||
|
||||
func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
|
||||
|
||||
switch self.segmentedControl?.selectedSegmentIndex {
|
||||
|
||||
case .Some(Section.Fetching.rawValue):
|
||||
case Section.Fetching.rawValue?:
|
||||
return self.fetchingItems.count
|
||||
|
||||
case .Some(Section.Querying.rawValue):
|
||||
case Section.Querying.rawValue?:
|
||||
return self.queryingItems.count
|
||||
|
||||
default:
|
||||
@@ -112,14 +115,14 @@ class FetchingAndQueryingDemoViewController: UIViewController, UITableViewDataSo
|
||||
|
||||
func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
|
||||
|
||||
let cell = tableView.dequeueReusableCellWithIdentifier("UITableViewCell") as! UITableViewCell
|
||||
let cell = tableView.dequeueReusableCellWithIdentifier("UITableViewCell")!
|
||||
|
||||
switch self.segmentedControl?.selectedSegmentIndex {
|
||||
|
||||
case .Some(Section.Fetching.rawValue):
|
||||
case Section.Fetching.rawValue?:
|
||||
cell.textLabel?.text = self.fetchingItems[indexPath.row].title
|
||||
|
||||
case .Some(Section.Querying.rawValue):
|
||||
case Section.Querying.rawValue?:
|
||||
cell.textLabel?.text = self.queryingItems[indexPath.row].title
|
||||
|
||||
default:
|
||||
@@ -138,10 +141,10 @@ class FetchingAndQueryingDemoViewController: UIViewController, UITableViewDataSo
|
||||
|
||||
switch self.segmentedControl?.selectedSegmentIndex {
|
||||
|
||||
case .Some(Section.Fetching.rawValue):
|
||||
case Section.Fetching.rawValue?:
|
||||
self.performSegueWithIdentifier("FetchingResultsViewController", sender: indexPath)
|
||||
|
||||
case .Some(Section.Querying.rawValue):
|
||||
case Section.Querying.rawValue?:
|
||||
self.performSegueWithIdentifier("QueryingResultsViewController", sender: indexPath)
|
||||
|
||||
default:
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
// CoreStoreDemo
|
||||
//
|
||||
// Created by John Rommel Estropia on 2015/06/17.
|
||||
// Copyright (c) 2015 John Rommel Estropia. All rights reserved.
|
||||
// Copyright © 2015 John Rommel Estropia. All rights reserved.
|
||||
//
|
||||
|
||||
import UIKit
|
||||
@@ -43,7 +43,7 @@ class FetchingResultsViewController: UITableViewController {
|
||||
|
||||
override func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
|
||||
|
||||
let cell = tableView.dequeueReusableCellWithIdentifier("UITableViewCell", forIndexPath: indexPath) as! UITableViewCell
|
||||
let cell = tableView.dequeueReusableCellWithIdentifier("UITableViewCell", forIndexPath: indexPath)
|
||||
|
||||
let timeZone = self.timeZones[indexPath.row]
|
||||
cell.textLabel?.text = timeZone.name
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
// CoreStoreDemo
|
||||
//
|
||||
// Created by John Rommel Estropia on 2015/06/17.
|
||||
// Copyright (c) 2015 John Rommel Estropia. All rights reserved.
|
||||
// Copyright © 2015 John Rommel Estropia. All rights reserved.
|
||||
//
|
||||
|
||||
import UIKit
|
||||
@@ -16,19 +16,19 @@ class QueryingResultsViewController: UITableViewController {
|
||||
|
||||
switch value {
|
||||
|
||||
case .Some(let array as [AnyObject]):
|
||||
case (let array as [AnyObject])?:
|
||||
self.values = array.map { (item: AnyObject) -> (title: String, detail: String) in
|
||||
(
|
||||
title: item.description,
|
||||
detail: _stdlib_getDemangledTypeName(item)
|
||||
detail: String(reflecting: item.dynamicType)
|
||||
)
|
||||
}
|
||||
|
||||
case .Some(let item):
|
||||
case let item?:
|
||||
self.values = [
|
||||
(
|
||||
title: item.description,
|
||||
detail: _stdlib_getDemangledTypeName(item)
|
||||
detail: String(reflecting: item.dynamicType)
|
||||
)
|
||||
]
|
||||
|
||||
@@ -62,7 +62,7 @@ class QueryingResultsViewController: UITableViewController {
|
||||
|
||||
override func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
|
||||
|
||||
let cell = tableView.dequeueReusableCellWithIdentifier("UITableViewCell", forIndexPath: indexPath) as! UITableViewCell
|
||||
let cell = tableView.dequeueReusableCellWithIdentifier("UITableViewCell", forIndexPath: indexPath)
|
||||
|
||||
let value = self.values[indexPath.row]
|
||||
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
// CoreStoreDemo
|
||||
//
|
||||
// Created by John Rommel Estropia on 2015/06/15.
|
||||
// Copyright (c) 2015 John Rommel Estropia. All rights reserved.
|
||||
// Copyright © 2015 John Rommel Estropia. All rights reserved.
|
||||
//
|
||||
|
||||
import Foundation
|
||||
|
||||
@@ -21,13 +21,33 @@
|
||||
"scale" : "3x"
|
||||
},
|
||||
{
|
||||
"idiom" : "iphone",
|
||||
"size" : "60x60",
|
||||
"idiom" : "iphone",
|
||||
"filename" : "Icon-60@2x.png",
|
||||
"scale" : "2x"
|
||||
},
|
||||
{
|
||||
"idiom" : "iphone",
|
||||
"size" : "60x60",
|
||||
"idiom" : "iphone",
|
||||
"filename" : "Icon-60@3x-1.png",
|
||||
"scale" : "3x"
|
||||
},
|
||||
{
|
||||
"size" : "76x76",
|
||||
"idiom" : "ipad",
|
||||
"filename" : "Icon-76.png",
|
||||
"scale" : "1x"
|
||||
},
|
||||
{
|
||||
"size" : "76x76",
|
||||
"idiom" : "ipad",
|
||||
"filename" : "Icon-76@2x.png",
|
||||
"scale" : "2x"
|
||||
},
|
||||
{
|
||||
"size" : "60x60",
|
||||
"idiom" : "car",
|
||||
"filename" : "Icon-60@3x.png",
|
||||
"scale" : "3x"
|
||||
}
|
||||
],
|
||||
|
||||
|
After Width: | Height: | Size: 7.1 KiB |
|
After Width: | Height: | Size: 11 KiB |
|
After Width: | Height: | Size: 11 KiB |
|
After Width: | Height: | Size: 4.1 KiB |
|
After Width: | Height: | Size: 9.3 KiB |
@@ -0,0 +1,6 @@
|
||||
{
|
||||
"info" : {
|
||||
"version" : 1,
|
||||
"author" : "xcode"
|
||||
}
|
||||
}
|
||||
21
CoreStoreDemo/CoreStoreDemo/Images.xcassets/CoreStoreIcon.imageset/Contents.json
vendored
Normal file
@@ -0,0 +1,21 @@
|
||||
{
|
||||
"images" : [
|
||||
{
|
||||
"idiom" : "universal",
|
||||
"scale" : "1x"
|
||||
},
|
||||
{
|
||||
"idiom" : "universal",
|
||||
"filename" : "CoreStoreIcon@2x.png",
|
||||
"scale" : "2x"
|
||||
},
|
||||
{
|
||||
"idiom" : "universal",
|
||||
"scale" : "3x"
|
||||
}
|
||||
],
|
||||
"info" : {
|
||||
"version" : 1,
|
||||
"author" : "xcode"
|
||||
}
|
||||
}
|
||||
BIN
CoreStoreDemo/CoreStoreDemo/Images.xcassets/CoreStoreIcon.imageset/CoreStoreIcon@2x.png
vendored
Normal file
|
After Width: | Height: | Size: 28 KiB |
@@ -4,10 +4,12 @@
|
||||
<dict>
|
||||
<key>CFBundleDevelopmentRegion</key>
|
||||
<string>en</string>
|
||||
<key>CFBundleDisplayName</key>
|
||||
<string>CoreStore</string>
|
||||
<key>CFBundleExecutable</key>
|
||||
<string>$(EXECUTABLE_NAME)</string>
|
||||
<key>CFBundleIdentifier</key>
|
||||
<string>com.johnestropia.CoreStoreDemo</string>
|
||||
<string>$(PRODUCT_BUNDLE_IDENTIFIER)</string>
|
||||
<key>CFBundleInfoDictionaryVersion</key>
|
||||
<string>6.0</string>
|
||||
<key>CFBundleName</key>
|
||||
@@ -15,7 +17,7 @@
|
||||
<key>CFBundlePackageType</key>
|
||||
<string>APPL</string>
|
||||
<key>CFBundleShortVersionString</key>
|
||||
<string>1.0</string>
|
||||
<string>1.0.1</string>
|
||||
<key>CFBundleSignature</key>
|
||||
<string>????</string>
|
||||
<key>CFBundleVersion</key>
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
//
|
||||
// ObjectListObserverDemoViewController.swift
|
||||
// ListObserverDemoViewController.swift
|
||||
// CoreStoreDemo
|
||||
//
|
||||
// Created by John Rommel Estropia on 2015/05/02.
|
||||
// Copyright (c) 2015 John Rommel Estropia. All rights reserved.
|
||||
// Copyright © 2015 John Rommel Estropia. All rights reserved.
|
||||
//
|
||||
|
||||
import UIKit
|
||||
@@ -12,26 +12,63 @@ import CoreStore
|
||||
|
||||
private struct Static {
|
||||
|
||||
static let palettes: ManagedObjectListController<Palette> = {
|
||||
enum Filter: String {
|
||||
|
||||
CoreStore.addSQLiteStoreAndWait(
|
||||
"ColorsDemo.sqlite",
|
||||
configuration: "ObservingDemo",
|
||||
resetStoreOnMigrationFailure: true
|
||||
case All = "All Colors"
|
||||
case Light = "Light Colors"
|
||||
case Dark = "Dark Colors"
|
||||
|
||||
func next() -> Filter {
|
||||
|
||||
switch self {
|
||||
|
||||
case All: return .Light
|
||||
case Light: return .Dark
|
||||
case Dark: return .All
|
||||
}
|
||||
}
|
||||
|
||||
func whereClause() -> Where {
|
||||
|
||||
switch self {
|
||||
|
||||
case .All: return Where(true)
|
||||
case .Light: return Where("brightness >= 0.9")
|
||||
case .Dark: return Where("brightness <= 0.4")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static var filter = Filter.All {
|
||||
|
||||
didSet {
|
||||
|
||||
self.palettes.refetch(self.filter.whereClause())
|
||||
}
|
||||
}
|
||||
|
||||
static let palettes: ListMonitor<Palette> = {
|
||||
|
||||
try! CoreStore.addStorageAndWait(
|
||||
SQLiteStore(
|
||||
fileName: "ColorsDemo.sqlite",
|
||||
configuration: "ObservingDemo",
|
||||
localStorageOptions: .RecreateStoreOnModelMismatch
|
||||
)
|
||||
)
|
||||
|
||||
return CoreStore.observeSectionedList(
|
||||
return CoreStore.monitorSectionedList(
|
||||
From(Palette),
|
||||
SectionedBy("colorName"),
|
||||
SectionBy("colorName"),
|
||||
OrderBy(.Ascending("hue"))
|
||||
)
|
||||
}()
|
||||
}
|
||||
|
||||
|
||||
// MARK: - ObjectListObserverDemoViewController
|
||||
// MARK: - ListObserverDemoViewController
|
||||
|
||||
class ObjectListObserverDemoViewController: UITableViewController, ManagedObjectListSectionObserver {
|
||||
class ListObserverDemoViewController: UITableViewController, ListSectionObserver {
|
||||
|
||||
// MARK: NSObject
|
||||
|
||||
@@ -47,21 +84,35 @@ class ObjectListObserverDemoViewController: UITableViewController, ManagedObject
|
||||
|
||||
super.viewDidLoad()
|
||||
|
||||
self.navigationItem.leftBarButtonItems = [
|
||||
let navigationItem = self.navigationItem
|
||||
navigationItem.leftBarButtonItems = [
|
||||
self.editButtonItem(),
|
||||
UIBarButtonItem(
|
||||
barButtonSystemItem: .Trash,
|
||||
target: self,
|
||||
action: "resetBarButtonItemTouched:"
|
||||
action: #selector(self.resetBarButtonItemTouched(_:))
|
||||
)
|
||||
]
|
||||
self.navigationItem.rightBarButtonItem = UIBarButtonItem(
|
||||
barButtonSystemItem: .Add,
|
||||
|
||||
let filterBarButton = UIBarButtonItem(
|
||||
title: Static.filter.rawValue,
|
||||
style: .Plain,
|
||||
target: self,
|
||||
action: "addBarButtonItemTouched:"
|
||||
action: #selector(self.filterBarButtonItemTouched(_:))
|
||||
)
|
||||
navigationItem.rightBarButtonItems = [
|
||||
UIBarButtonItem(
|
||||
barButtonSystemItem: .Add,
|
||||
target: self,
|
||||
action: #selector(self.addBarButtonItemTouched(_:))
|
||||
),
|
||||
filterBarButton
|
||||
]
|
||||
self.filterBarButton = filterBarButton
|
||||
|
||||
Static.palettes.addObserver(self)
|
||||
|
||||
self.setTableEnabled(!Static.palettes.isPendingRefetch)
|
||||
}
|
||||
|
||||
override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) {
|
||||
@@ -70,7 +121,7 @@ class ObjectListObserverDemoViewController: UITableViewController, ManagedObject
|
||||
|
||||
switch (segue.identifier, segue.destinationViewController, sender) {
|
||||
|
||||
case (.Some("ObjectObserverDemoViewController"), let destinationViewController as ObjectObserverDemoViewController, let palette as Palette):
|
||||
case ("ObjectObserverDemoViewController"?, let destinationViewController as ObjectObserverDemoViewController, let palette as Palette):
|
||||
destinationViewController.palette = palette
|
||||
|
||||
default:
|
||||
@@ -138,32 +189,44 @@ class ObjectListObserverDemoViewController: UITableViewController, ManagedObject
|
||||
}
|
||||
|
||||
|
||||
// MARK: ManagedObjectListChangeObserver
|
||||
// MARK: ListObserver
|
||||
|
||||
func managedObjectListWillChange(listController: ManagedObjectListController<Palette>) {
|
||||
func listMonitorWillChange(monitor: ListMonitor<Palette>) {
|
||||
|
||||
self.tableView.beginUpdates()
|
||||
}
|
||||
|
||||
func managedObjectListDidChange(listController: ManagedObjectListController<Palette>) {
|
||||
func listMonitorDidChange(monitor: ListMonitor<Palette>) {
|
||||
|
||||
self.tableView.endUpdates()
|
||||
}
|
||||
|
||||
func listMonitorWillRefetch(monitor: ListMonitor<Palette>) {
|
||||
|
||||
self.setTableEnabled(false)
|
||||
}
|
||||
|
||||
// MARK: ManagedObjectListObjectObserver
|
||||
func listMonitorDidRefetch(monitor: ListMonitor<Palette>) {
|
||||
|
||||
self.filterBarButton?.title = Static.filter.rawValue
|
||||
self.tableView.reloadData()
|
||||
self.setTableEnabled(true)
|
||||
}
|
||||
|
||||
func managedObjectList(listController: ManagedObjectListController<Palette>, didInsertObject object: Palette, toIndexPath indexPath: NSIndexPath) {
|
||||
|
||||
// MARK: ListObjectObserver
|
||||
|
||||
func listMonitor(monitor: ListMonitor<Palette>, didInsertObject object: Palette, toIndexPath indexPath: NSIndexPath) {
|
||||
|
||||
self.tableView.insertRowsAtIndexPaths([indexPath], withRowAnimation: .Automatic)
|
||||
}
|
||||
|
||||
func managedObjectList(listController: ManagedObjectListController<Palette>, didDeleteObject object: Palette, fromIndexPath indexPath: NSIndexPath) {
|
||||
func listMonitor(monitor: ListMonitor<Palette>, didDeleteObject object: Palette, fromIndexPath indexPath: NSIndexPath) {
|
||||
|
||||
self.tableView.deleteRowsAtIndexPaths([indexPath], withRowAnimation: .Automatic)
|
||||
}
|
||||
|
||||
func managedObjectList(listController: ManagedObjectListController<Palette>, didUpdateObject object: Palette, atIndexPath indexPath: NSIndexPath) {
|
||||
func listMonitor(monitor: ListMonitor<Palette>, didUpdateObject object: Palette, atIndexPath indexPath: NSIndexPath) {
|
||||
|
||||
if let cell = self.tableView.cellForRowAtIndexPath(indexPath) as? PaletteTableViewCell {
|
||||
|
||||
@@ -173,21 +236,21 @@ class ObjectListObserverDemoViewController: UITableViewController, ManagedObject
|
||||
}
|
||||
}
|
||||
|
||||
func managedObjectList(listController: ManagedObjectListController<Palette>, didMoveObject object: Palette, fromIndexPath: NSIndexPath, toIndexPath: NSIndexPath) {
|
||||
func listMonitor(monitor: ListMonitor<Palette>, didMoveObject object: Palette, fromIndexPath: NSIndexPath, toIndexPath: NSIndexPath) {
|
||||
|
||||
self.tableView.deleteRowsAtIndexPaths([fromIndexPath], withRowAnimation: .Automatic)
|
||||
self.tableView.insertRowsAtIndexPaths([toIndexPath], withRowAnimation: .Automatic)
|
||||
}
|
||||
|
||||
|
||||
// MARK: ManagedObjectListSectionObserver
|
||||
// MARK: ListSectionObserver
|
||||
|
||||
func managedObjectList(listController: ManagedObjectListController<Palette>, didInsertSection sectionInfo: NSFetchedResultsSectionInfo, toSectionIndex sectionIndex: Int) {
|
||||
func listMonitor(monitor: ListMonitor<Palette>, didInsertSection sectionInfo: NSFetchedResultsSectionInfo, toSectionIndex sectionIndex: Int) {
|
||||
|
||||
self.tableView.insertSections(NSIndexSet(index: sectionIndex), withRowAnimation: .Automatic)
|
||||
}
|
||||
|
||||
func managedObjectList(listController: ManagedObjectListController<Palette>, didDeleteSection sectionInfo: NSFetchedResultsSectionInfo, fromSectionIndex sectionIndex: Int) {
|
||||
func listMonitor(monitor: ListMonitor<Palette>, didDeleteSection sectionInfo: NSFetchedResultsSectionInfo, fromSectionIndex sectionIndex: Int) {
|
||||
|
||||
self.tableView.deleteSections(NSIndexSet(index: sectionIndex), withRowAnimation: .Automatic)
|
||||
}
|
||||
@@ -195,7 +258,9 @@ class ObjectListObserverDemoViewController: UITableViewController, ManagedObject
|
||||
|
||||
// MARK: Private
|
||||
|
||||
@IBAction dynamic func resetBarButtonItemTouched(sender: AnyObject?) {
|
||||
private var filterBarButton: UIBarButtonItem?
|
||||
|
||||
@IBAction private dynamic func resetBarButtonItemTouched(sender: AnyObject?) {
|
||||
|
||||
CoreStore.beginAsynchronous { (transaction) -> Void in
|
||||
|
||||
@@ -204,7 +269,12 @@ class ObjectListObserverDemoViewController: UITableViewController, ManagedObject
|
||||
}
|
||||
}
|
||||
|
||||
@IBAction dynamic func addBarButtonItemTouched(sender: AnyObject?) {
|
||||
@IBAction private dynamic func filterBarButtonItemTouched(sender: AnyObject?) {
|
||||
|
||||
Static.filter = Static.filter.next()
|
||||
}
|
||||
|
||||
@IBAction private dynamic func addBarButtonItemTouched(sender: AnyObject?) {
|
||||
|
||||
CoreStore.beginAsynchronous { (transaction) -> Void in
|
||||
|
||||
@@ -214,5 +284,23 @@ class ObjectListObserverDemoViewController: UITableViewController, ManagedObject
|
||||
transaction.commit()
|
||||
}
|
||||
}
|
||||
|
||||
private func setTableEnabled(enabled: Bool) {
|
||||
|
||||
UIView.animateWithDuration(
|
||||
0.2,
|
||||
delay: 0,
|
||||
options: .BeginFromCurrentState,
|
||||
animations: { () -> Void in
|
||||
|
||||
if let tableView = self.tableView {
|
||||
|
||||
tableView.alpha = enabled ? 1.0 : 0.5
|
||||
tableView.userInteractionEnabled = enabled
|
||||
}
|
||||
},
|
||||
completion: nil
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
// CoreStoreDemo
|
||||
//
|
||||
// Created by John Rommel Estropia on 2015/05/06.
|
||||
// Copyright (c) 2015 John Rommel Estropia. All rights reserved.
|
||||
// Copyright © 2015 John Rommel Estropia. All rights reserved.
|
||||
//
|
||||
|
||||
import UIKit
|
||||
@@ -12,23 +12,28 @@ import CoreStore
|
||||
|
||||
// MARK: - ObjectObserverDemoViewController
|
||||
|
||||
class ObjectObserverDemoViewController: UIViewController, ManagedObjectObserver {
|
||||
class ObjectObserverDemoViewController: UIViewController, ObjectObserver {
|
||||
|
||||
var palette: Palette? {
|
||||
|
||||
get {
|
||||
|
||||
return self.objectController?.object
|
||||
return self.monitor?.object
|
||||
}
|
||||
set {
|
||||
|
||||
guard self.monitor?.object != newValue else {
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
if let palette = newValue {
|
||||
|
||||
self.objectController = CoreStore.observeObject(palette)
|
||||
self.monitor = CoreStore.monitorObject(palette)
|
||||
}
|
||||
else {
|
||||
|
||||
self.objectController = nil
|
||||
self.monitor = nil
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -37,17 +42,17 @@ class ObjectObserverDemoViewController: UIViewController, ManagedObjectObserver
|
||||
|
||||
deinit {
|
||||
|
||||
self.objectController?.removeObserver(self)
|
||||
self.monitor?.removeObserver(self)
|
||||
}
|
||||
|
||||
|
||||
// MARK: UIViewController
|
||||
|
||||
required init(coder aDecoder: NSCoder) {
|
||||
required init?(coder aDecoder: NSCoder) {
|
||||
|
||||
if let palette = CoreStore.fetchOne(From(Palette), OrderBy(.Ascending("hue"))) {
|
||||
|
||||
self.objectController = CoreStore.observeObject(palette)
|
||||
self.monitor = CoreStore.monitorObject(palette)
|
||||
}
|
||||
else {
|
||||
|
||||
@@ -56,11 +61,11 @@ class ObjectObserverDemoViewController: UIViewController, ManagedObjectObserver
|
||||
let palette = transaction.create(Into(Palette))
|
||||
palette.setInitialValues()
|
||||
|
||||
transaction.commit()
|
||||
transaction.commitAndWait()
|
||||
}
|
||||
|
||||
let palette = CoreStore.fetchOne(From(Palette), OrderBy(.Ascending("hue")))!
|
||||
self.objectController = CoreStore.observeObject(palette)
|
||||
self.monitor = CoreStore.monitorObject(palette)
|
||||
}
|
||||
|
||||
super.init(coder: aDecoder)
|
||||
@@ -69,28 +74,23 @@ class ObjectObserverDemoViewController: UIViewController, ManagedObjectObserver
|
||||
override func viewDidLoad() {
|
||||
|
||||
super.viewDidLoad()
|
||||
self.objectController?.addObserver(self)
|
||||
self.monitor?.addObserver(self)
|
||||
|
||||
if let palette = self.objectController?.object {
|
||||
if let palette = self.monitor?.object {
|
||||
|
||||
self.reloadPaletteInfo(palette, changedKeys: nil)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// MARK: ManagedObjectObserver
|
||||
// MARK: ObjectObserver
|
||||
|
||||
func managedObjectWillUpdate(objectController: ManagedObjectController<Palette>, object: Palette) {
|
||||
|
||||
// none
|
||||
}
|
||||
|
||||
func managedObjectWasUpdated(objectController: ManagedObjectController<Palette>, object: Palette, changedPersistentKeys: Set<KeyPath>) {
|
||||
func objectMonitor(monitor: ObjectMonitor<Palette>, didUpdateObject object: Palette, changedPersistentKeys: Set<KeyPath>) {
|
||||
|
||||
self.reloadPaletteInfo(object, changedKeys: changedPersistentKeys)
|
||||
}
|
||||
|
||||
func managedObjectWasDeleted(objectController: ManagedObjectController<Palette>, object: Palette) {
|
||||
func objectMonitor(monitor: ObjectMonitor<Palette>, didDeleteObject object: Palette) {
|
||||
|
||||
self.navigationItem.rightBarButtonItem?.enabled = false
|
||||
|
||||
@@ -108,7 +108,7 @@ class ObjectObserverDemoViewController: UIViewController, ManagedObjectObserver
|
||||
|
||||
// MARK: Private
|
||||
|
||||
var objectController: ManagedObjectController<Palette>?
|
||||
var monitor: ObjectMonitor<Palette>?
|
||||
|
||||
@IBOutlet weak var colorNameLabel: UILabel?
|
||||
@IBOutlet weak var colorView: UIView?
|
||||
@@ -123,7 +123,7 @@ class ObjectObserverDemoViewController: UIViewController, ManagedObjectObserver
|
||||
let hue = self.hueSlider?.value ?? 0
|
||||
CoreStore.beginAsynchronous { [weak self] (transaction) -> Void in
|
||||
|
||||
if let palette = transaction.edit(self?.objectController?.object) {
|
||||
if let palette = transaction.edit(self?.monitor?.object) {
|
||||
|
||||
palette.hue = Int32(hue)
|
||||
transaction.commit()
|
||||
@@ -136,7 +136,7 @@ class ObjectObserverDemoViewController: UIViewController, ManagedObjectObserver
|
||||
let saturation = self.saturationSlider?.value ?? 0
|
||||
CoreStore.beginAsynchronous { [weak self] (transaction) -> Void in
|
||||
|
||||
if let palette = transaction.edit(self?.objectController?.object) {
|
||||
if let palette = transaction.edit(self?.monitor?.object) {
|
||||
|
||||
palette.saturation = saturation
|
||||
transaction.commit()
|
||||
@@ -149,7 +149,7 @@ class ObjectObserverDemoViewController: UIViewController, ManagedObjectObserver
|
||||
let brightness = self.brightnessSlider?.value ?? 0
|
||||
CoreStore.beginAsynchronous { [weak self] (transaction) -> Void in
|
||||
|
||||
if let palette = transaction.edit(self?.objectController?.object) {
|
||||
if let palette = transaction.edit(self?.monitor?.object) {
|
||||
|
||||
palette.brightness = brightness
|
||||
transaction.commit()
|
||||
@@ -161,7 +161,7 @@ class ObjectObserverDemoViewController: UIViewController, ManagedObjectObserver
|
||||
|
||||
CoreStore.beginAsynchronous { [weak self] (transaction) -> Void in
|
||||
|
||||
transaction.delete(self?.objectController?.object)
|
||||
transaction.delete(self?.monitor?.object)
|
||||
transaction.commit()
|
||||
}
|
||||
}
|
||||
@@ -176,10 +176,6 @@ class ObjectObserverDemoViewController: UIViewController, ManagedObjectObserver
|
||||
|
||||
self.hsbLabel?.text = palette.colorText
|
||||
|
||||
let hue = palette.hue
|
||||
let saturation = palette.saturation
|
||||
let brightness = palette.brightness
|
||||
|
||||
if changedKeys == nil || changedKeys?.contains("hue") == true {
|
||||
|
||||
self.hueSlider?.value = Float(palette.hue)
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
// CoreStoreDemo
|
||||
//
|
||||
// Created by John Rommel Estropia on 2015/05/24.
|
||||
// Copyright (c) 2015 John Rommel Estropia. All rights reserved.
|
||||
// Copyright © 2015 John Rommel Estropia. All rights reserved.
|
||||
//
|
||||
|
||||
import UIKit
|
||||
@@ -21,7 +21,7 @@ class ObserversViewController: UIViewController {
|
||||
|
||||
let alert = UIAlertController(
|
||||
title: "Observers Demo",
|
||||
message: "This demo shows how to observe changes to a list of objects. The top and bottom view controllers both observe a single shared \"ManagedObjectListController\" instance.\n\nTap on a row to see how to observe changes made to a single object using a \"ManagedObjectController\".",
|
||||
message: "This demo shows how to observe changes to a list of objects. The top and bottom view controllers both observe a single shared \"ListMonitor\" instance.\n\nTap on a row to see how to observe changes made to a single object using a \"ObjectMonitor\".",
|
||||
preferredStyle: .Alert
|
||||
)
|
||||
alert.addAction(UIAlertAction(title: "OK", style: .Cancel, handler: nil))
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
// CoreStoreDemo
|
||||
//
|
||||
// Created by John Rommel Estropia on 2015/05/05.
|
||||
// Copyright (c) 2015 John Rommel Estropia. All rights reserved.
|
||||
// Copyright © 2015 John Rommel Estropia. All rights reserved.
|
||||
//
|
||||
|
||||
import Foundation
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
// CoreStoreDemo
|
||||
//
|
||||
// Created by John Rommel Estropia on 2015/05/05.
|
||||
// Copyright (c) 2015 John Rommel Estropia. All rights reserved.
|
||||
// Copyright © 2015 John Rommel Estropia. All rights reserved.
|
||||
//
|
||||
|
||||
import UIKit
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
// CoreStoreDemo
|
||||
//
|
||||
// Created by John Rommel Estropia on 2015/06/05.
|
||||
// Copyright (c) 2015 John Rommel Estropia. All rights reserved.
|
||||
// Copyright © 2015 John Rommel Estropia. All rights reserved.
|
||||
//
|
||||
|
||||
import UIKit
|
||||
@@ -30,7 +30,7 @@ class CustomLoggerViewController: UIViewController, CoreStoreLogger {
|
||||
|
||||
super.viewDidLoad()
|
||||
|
||||
self.dataStack.addSQLiteStoreAndWait("emptyStore.sqlite")
|
||||
try! self.dataStack.addStorageAndWait(SQLiteStore(fileName: "emptyStore.sqlite"))
|
||||
CoreStore.logger = self
|
||||
}
|
||||
|
||||
@@ -50,7 +50,7 @@ class CustomLoggerViewController: UIViewController, CoreStoreLogger {
|
||||
|
||||
// MARK: CoreStoreLogger
|
||||
|
||||
func log(#level: LogLevel, message: String, fileName: StaticString, lineNumber: Int, functionName: StaticString) {
|
||||
func log(level level: LogLevel, message: String, fileName: StaticString, lineNumber: Int, functionName: StaticString) {
|
||||
|
||||
GCDQueue.Main.async { [weak self] in
|
||||
|
||||
@@ -62,28 +62,29 @@ class CustomLoggerViewController: UIViewController, CoreStoreLogger {
|
||||
case .Warning: levelString = "Warning"
|
||||
case .Fatal: levelString = "Fatal"
|
||||
}
|
||||
self?.textView?.insertText("\(fileName.stringValue.lastPathComponent):\(lineNumber) \(functionName)\n ↪︎ [Log:\(levelString)] \(message)\n\n")
|
||||
self?.textView?.insertText("\((fileName.stringValue as NSString).lastPathComponent):\(lineNumber) \(functionName)\n ↪︎ [Log:\(levelString)] \(message)\n\n")
|
||||
}
|
||||
}
|
||||
|
||||
func handleError(#error: NSError, message: String, fileName: StaticString, lineNumber: Int, functionName: StaticString) {
|
||||
func log(error error: CoreStoreError, message: String, fileName: StaticString, lineNumber: Int, functionName: StaticString) {
|
||||
|
||||
GCDQueue.Main.async { [weak self] in
|
||||
|
||||
self?.textView?.insertText("\(fileName.stringValue.lastPathComponent):\(lineNumber) \(functionName)\n ↪︎ [Error] \(message): \(error)\n\n")
|
||||
self?.textView?.insertText("\((fileName.stringValue as NSString).lastPathComponent):\(lineNumber) \(functionName)\n ↪︎ [Error] \(message): \(error)\n\n")
|
||||
}
|
||||
}
|
||||
|
||||
func assert(@autoclosure condition: () -> Bool, message: String, fileName: StaticString, lineNumber: Int, functionName: StaticString) {
|
||||
func assert(@autoclosure condition: () -> Bool, @autoclosure message: () -> String, fileName: StaticString, lineNumber: Int, functionName: StaticString) {
|
||||
|
||||
if condition() {
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
let messageString = message()
|
||||
GCDQueue.Main.async { [weak self] in
|
||||
|
||||
self?.textView?.insertText("\(fileName.stringValue.lastPathComponent):\(lineNumber) \(functionName)\n ↪︎ [Assert] \(message)\n\n")
|
||||
self?.textView?.insertText("\((fileName.stringValue as NSString).lastPathComponent):\(lineNumber) \(functionName)\n ↪︎ [Assert] \(messageString)\n\n")
|
||||
}
|
||||
}
|
||||
|
||||
@@ -97,16 +98,21 @@ class CustomLoggerViewController: UIViewController, CoreStoreLogger {
|
||||
|
||||
switch self.segmentedControl?.selectedSegmentIndex {
|
||||
|
||||
case .Some(0):
|
||||
case 0?:
|
||||
self.dataStack.beginAsynchronous { (transaction) -> Void in
|
||||
|
||||
transaction.create(Into(UserAccount))
|
||||
transaction.create(Into(Palette))
|
||||
}
|
||||
|
||||
case .Some(1):
|
||||
self.dataStack.addSQLiteStoreAndWait("emptyStore.sqlite", configuration: "invalidStore")
|
||||
case 1?:
|
||||
_ = try? dataStack.addStorageAndWait(
|
||||
SQLiteStore(
|
||||
fileName: "emptyStore.sqlite",
|
||||
configuration: "invalidStore"
|
||||
)
|
||||
)
|
||||
|
||||
case .Some(2):
|
||||
case 2?:
|
||||
self.dataStack.beginAsynchronous { (transaction) -> Void in
|
||||
|
||||
transaction.commit()
|
||||
|
||||
@@ -0,0 +1,397 @@
|
||||
//
|
||||
// MigrationsDemoViewController.swift
|
||||
// CoreStoreDemo
|
||||
//
|
||||
// Created by John Rommel Estropia on 2015/06/21.
|
||||
// Copyright © 2015 John Rommel Estropia. All rights reserved.
|
||||
//
|
||||
|
||||
import UIKit
|
||||
import CoreStore
|
||||
|
||||
|
||||
// MARK: - MigrationsDemoViewController
|
||||
|
||||
class MigrationsDemoViewController: UIViewController {
|
||||
|
||||
// MARK: UIViewController
|
||||
|
||||
override func viewDidLoad() {
|
||||
|
||||
super.viewDidLoad()
|
||||
|
||||
if let segmentedControl = self.segmentedControl {
|
||||
|
||||
for (index, model) in self.models.enumerate() {
|
||||
|
||||
segmentedControl.setTitle(
|
||||
model.label,
|
||||
forSegmentAtIndex: index
|
||||
)
|
||||
}
|
||||
}
|
||||
self.setDataStack(nil, model: nil, scrollToSelection: false)
|
||||
}
|
||||
|
||||
override func viewDidAppear(animated: Bool) {
|
||||
|
||||
super.viewDidAppear(animated)
|
||||
|
||||
let alert = UIAlertController(
|
||||
title: "Migrations Demo",
|
||||
message: "This demo shows how to run progressive migrations and how to support multiple model versions in a single project.\n\nThe persistent store contains 10000 organisms, which gain/lose properties when the migration evolves/devolves them.\n\nYou can use the \"mutate\" button to change an organism's properties then migrate to a different model to see how its value gets affected.",
|
||||
preferredStyle: .Alert
|
||||
)
|
||||
alert.addAction(UIAlertAction(title: "OK", style: .Cancel, handler: nil))
|
||||
self.presentViewController(alert, animated: true, completion: nil)
|
||||
|
||||
|
||||
let modelMetadata = withExtendedLifetime(DataStack(modelName: "MigrationDemo")) {
|
||||
(dataStack: DataStack) -> ModelMetadata in
|
||||
|
||||
let models = self.models
|
||||
let migrations = try! dataStack.requiredMigrationsForStorage(
|
||||
SQLiteStore(fileName: "MigrationDemo.sqlite")
|
||||
)
|
||||
|
||||
guard let storeVersion = migrations.first?.sourceVersion else {
|
||||
|
||||
return models.first!
|
||||
}
|
||||
for model in models {
|
||||
|
||||
if model.version == storeVersion {
|
||||
|
||||
return model
|
||||
}
|
||||
}
|
||||
|
||||
return models.first!
|
||||
}
|
||||
|
||||
self.selectModelVersion(modelMetadata)
|
||||
}
|
||||
|
||||
|
||||
// MARK: Private
|
||||
|
||||
private typealias ModelMetadata = (label: String, version: String, entityType: AnyClass, migrationChain: MigrationChain)
|
||||
|
||||
private let models: [ModelMetadata] = [
|
||||
(
|
||||
label: "Model V1",
|
||||
version: "MigrationDemo",
|
||||
entityType: OrganismV1.self,
|
||||
migrationChain: ["MigrationDemoV3", "MigrationDemoV2", "MigrationDemo"]
|
||||
),
|
||||
(
|
||||
label: "Model V2",
|
||||
version: "MigrationDemoV2",
|
||||
entityType: OrganismV2.self,
|
||||
migrationChain: [
|
||||
"MigrationDemo": "MigrationDemoV2",
|
||||
"MigrationDemoV3": "MigrationDemoV2"
|
||||
]
|
||||
),
|
||||
(
|
||||
label: "Model V3",
|
||||
version: "MigrationDemoV3",
|
||||
entityType: OrganismV3.self,
|
||||
migrationChain: ["MigrationDemo", "MigrationDemoV2", "MigrationDemoV3"]
|
||||
)
|
||||
]
|
||||
|
||||
private var _listMonitor: ListMonitor<NSManagedObject>?
|
||||
private var listMonitor: ListMonitor<NSManagedObject>? {
|
||||
|
||||
return self._listMonitor
|
||||
}
|
||||
|
||||
private var _dataStack: DataStack?
|
||||
private var dataStack: DataStack? {
|
||||
|
||||
return self._dataStack
|
||||
}
|
||||
|
||||
private var _lastSelectedIndexPath: NSIndexPath?
|
||||
private var lastSelectedIndexPath: NSIndexPath? {
|
||||
|
||||
return self._lastSelectedIndexPath
|
||||
}
|
||||
|
||||
private func setSelectedIndexPath(indexPath: NSIndexPath, scrollToSelection: Bool) {
|
||||
|
||||
self._lastSelectedIndexPath = indexPath
|
||||
self.updateDisplay(reloadData: false, scrollToSelection: scrollToSelection, animated: true)
|
||||
}
|
||||
|
||||
@IBOutlet private dynamic weak var headerContainer: UIView?
|
||||
@IBOutlet private dynamic weak var titleLabel: UILabel?
|
||||
@IBOutlet private dynamic weak var organismLabel: UILabel?
|
||||
@IBOutlet private dynamic weak var segmentedControl: UISegmentedControl?
|
||||
@IBOutlet private dynamic weak var progressView: UIProgressView?
|
||||
@IBOutlet private dynamic weak var tableView: UITableView?
|
||||
|
||||
@IBAction private dynamic func segmentedControlValueChanged(sender: AnyObject?) {
|
||||
|
||||
guard let index = self.segmentedControl?.selectedSegmentIndex else {
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
self.selectModelVersion(self.models[index])
|
||||
}
|
||||
|
||||
private func selectModelVersion(model: ModelMetadata) {
|
||||
|
||||
if self.dataStack?.modelVersion == model.version {
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
self.setDataStack(nil, model: nil, scrollToSelection: false) // explicitly trigger NSPersistentStore cleanup by deallocating the stack
|
||||
|
||||
let dataStack = DataStack(
|
||||
modelName: "MigrationDemo",
|
||||
migrationChain: model.migrationChain
|
||||
)
|
||||
|
||||
self.setEnabled(false)
|
||||
let progress = dataStack.addStorage(
|
||||
SQLiteStore(fileName: "MigrationDemo.sqlite"),
|
||||
completion: { [weak self] (result) -> Void in
|
||||
|
||||
guard let `self` = self else {
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
guard case .Success = result else {
|
||||
|
||||
self.setEnabled(true)
|
||||
return
|
||||
}
|
||||
|
||||
self.setDataStack(dataStack, model: model, scrollToSelection: true)
|
||||
|
||||
let count = dataStack.queryValue(
|
||||
From(model.entityType),
|
||||
Select<Int>(.Count("dna"))
|
||||
)
|
||||
if count > 0 {
|
||||
|
||||
self.setEnabled(true)
|
||||
}
|
||||
else {
|
||||
|
||||
for i: Int64 in 0 ..< 20 {
|
||||
|
||||
dataStack.beginAsynchronous { (transaction) -> Void in
|
||||
|
||||
for j: Int64 in 0 ..< 500 {
|
||||
|
||||
let organism = transaction.create(Into(model.entityType)) as! OrganismProtocol
|
||||
organism.dna = (i * 500) + j + 1
|
||||
organism.mutate()
|
||||
}
|
||||
|
||||
transaction.commit()
|
||||
}
|
||||
}
|
||||
dataStack.beginAsynchronous { [weak self] (transaction) -> Void in
|
||||
|
||||
transaction.commit { _ in
|
||||
|
||||
self?.setEnabled(true)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
)
|
||||
|
||||
if let progress = progress {
|
||||
|
||||
progress.setProgressHandler { [weak self] (progress) -> Void in
|
||||
|
||||
self?.reloadTableHeaderWithProgress(progress)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private func setEnabled(enabled: Bool) {
|
||||
|
||||
UIView.animateWithDuration(
|
||||
0.2,
|
||||
delay: 0,
|
||||
options: .BeginFromCurrentState,
|
||||
animations: { () -> Void in
|
||||
|
||||
let navigationItem = self.navigationItem
|
||||
navigationItem.leftBarButtonItem?.enabled = enabled
|
||||
navigationItem.rightBarButtonItem?.enabled = enabled
|
||||
navigationItem.hidesBackButton = !enabled
|
||||
|
||||
self.segmentedControl?.enabled = enabled
|
||||
|
||||
if let tableView = self.tableView {
|
||||
|
||||
tableView.alpha = enabled ? 1.0 : 0.5
|
||||
tableView.userInteractionEnabled = enabled
|
||||
}
|
||||
},
|
||||
completion: nil
|
||||
)
|
||||
}
|
||||
|
||||
private func setDataStack(dataStack: DataStack?, model: ModelMetadata?, scrollToSelection: Bool) {
|
||||
|
||||
if let dataStack = dataStack, let model = model {
|
||||
|
||||
self.segmentedControl?.selectedSegmentIndex = self.models.map { $0.version }.indexOf(model.version)!
|
||||
|
||||
self._dataStack = dataStack
|
||||
let listMonitor = dataStack.monitorList(From(model.entityType), OrderBy(.Descending("dna")))
|
||||
listMonitor.addObserver(self)
|
||||
self._listMonitor = listMonitor
|
||||
|
||||
if self.lastSelectedIndexPath == nil {
|
||||
|
||||
if listMonitor.numberOfObjectsInSection(0) > 0 {
|
||||
|
||||
self.setSelectedIndexPath(NSIndexPath(forRow: 0, inSection: 0), scrollToSelection: true)
|
||||
}
|
||||
}
|
||||
}
|
||||
else {
|
||||
|
||||
self.segmentedControl?.selectedSegmentIndex = UISegmentedControlNoSegment
|
||||
self._listMonitor = nil
|
||||
self._dataStack = nil
|
||||
}
|
||||
|
||||
self.updateDisplay(reloadData: true, scrollToSelection: scrollToSelection, animated: false)
|
||||
}
|
||||
|
||||
private func reloadTableHeaderWithProgress(progress: NSProgress) {
|
||||
|
||||
self.progressView?.setProgress(Float(progress.fractionCompleted), animated: true)
|
||||
self.titleLabel?.text = "Migrating: \(progress.localizedDescription)"
|
||||
self.organismLabel?.text = "Progressive step \(progress.localizedAdditionalDescription)"
|
||||
}
|
||||
|
||||
private func updateDisplay(reloadData reloadData: Bool, scrollToSelection: Bool, animated: Bool) {
|
||||
|
||||
var lines = [String]()
|
||||
var organismType = ""
|
||||
if let indexPath = self.lastSelectedIndexPath, let organism = self.listMonitor?[indexPath] {
|
||||
|
||||
for property in organism.entity.properties {
|
||||
|
||||
let value: AnyObject = organism.valueForKey(property.name) ?? NSNull()
|
||||
lines.append("\(property.name): \(value)")
|
||||
}
|
||||
organismType = organism.entity.managedObjectClassName
|
||||
}
|
||||
|
||||
self.titleLabel?.text = organismType
|
||||
self.organismLabel?.text = lines.joinWithSeparator("\n")
|
||||
self.progressView?.progress = 0
|
||||
|
||||
self.headerContainer?.setNeedsLayout()
|
||||
|
||||
guard let tableView = self.tableView else {
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
if reloadData {
|
||||
|
||||
tableView.reloadData()
|
||||
}
|
||||
|
||||
tableView.layoutIfNeeded()
|
||||
|
||||
if let indexPath = self.lastSelectedIndexPath where indexPath.row < tableView.numberOfRowsInSection(0) {
|
||||
|
||||
tableView.selectRowAtIndexPath(indexPath,
|
||||
animated: scrollToSelection && animated,
|
||||
scrollPosition: scrollToSelection ? .Middle : .None
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// MARK: - MigrationsDemoViewController: ListObserver
|
||||
|
||||
extension MigrationsDemoViewController: ListObserver {
|
||||
|
||||
// MARK: ListObserver
|
||||
|
||||
func listMonitorWillChange(monitor: ListMonitor<NSManagedObject>) { }
|
||||
|
||||
func listMonitorDidChange(monitor: ListMonitor<NSManagedObject>) {
|
||||
|
||||
if self.lastSelectedIndexPath == nil && self.listMonitor?.numberOfObjectsInSection(0) > 0 {
|
||||
|
||||
self.tableView?.reloadData()
|
||||
self.setSelectedIndexPath(NSIndexPath(forRow: 0, inSection: 0), scrollToSelection: false)
|
||||
}
|
||||
else {
|
||||
|
||||
self.updateDisplay(reloadData: true, scrollToSelection: true, animated: true)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// MARK: - MigrationsDemoViewController: UITableViewDataSource, UITableViewDelegate
|
||||
|
||||
extension MigrationsDemoViewController: UITableViewDataSource, UITableViewDelegate {
|
||||
|
||||
// MARK: UITableViewDataSource
|
||||
|
||||
@objc dynamic func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
|
||||
|
||||
return self.listMonitor?.numberOfObjectsInSection(0) ?? 0
|
||||
}
|
||||
|
||||
@objc dynamic func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
|
||||
|
||||
let cell = tableView.dequeueReusableCellWithIdentifier("OrganismTableViewCell", forIndexPath: indexPath) as! OrganismTableViewCell
|
||||
|
||||
let dna = (self.listMonitor?[indexPath] as? OrganismProtocol)?.dna.description ?? ""
|
||||
cell.dnaLabel?.text = "DNA: \(dna)"
|
||||
cell.mutateButtonHandler = { [weak self] _ -> Void in
|
||||
|
||||
guard let `self` = self,
|
||||
let dataStack = self.dataStack,
|
||||
let organism = self.listMonitor?[indexPath] else {
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
self.setSelectedIndexPath(indexPath, scrollToSelection: false)
|
||||
self.setEnabled(false)
|
||||
dataStack.beginAsynchronous { [weak self] (transaction) -> Void in
|
||||
|
||||
let organism = transaction.edit(organism) as! OrganismProtocol
|
||||
organism.mutate()
|
||||
|
||||
transaction.commit { _ -> Void in
|
||||
|
||||
self?.setEnabled(true)
|
||||
}
|
||||
}
|
||||
}
|
||||
return cell
|
||||
}
|
||||
|
||||
|
||||
// MARK: UITableViewDelegate
|
||||
|
||||
@objc dynamic func tableView(tableView: UITableView, didSelectRowAtIndexPath indexPath: NSIndexPath) {
|
||||
|
||||
self.setSelectedIndexPath(indexPath, scrollToSelection: false)
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,5 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
||||
<plist version="1.0">
|
||||
<dict/>
|
||||
</plist>
|
||||
@@ -0,0 +1,4 @@
|
||||
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
|
||||
<model userDefinedModelVersionIdentifier="" type="com.apple.IDECoreDataModeler.DataModel" documentVersion="1.0" lastSavedToolsVersion="8166.2" systemVersion="14E46" minimumToolsVersion="Xcode 7.0">
|
||||
<elements/>
|
||||
</model>
|
||||
@@ -0,0 +1,16 @@
|
||||
//
|
||||
// OrganismProtocol.swift
|
||||
// CoreStoreDemo
|
||||
//
|
||||
// Created by John Rommel Estropia on 2015/06/27.
|
||||
// Copyright © 2015 John Rommel Estropia. All rights reserved.
|
||||
//
|
||||
|
||||
import Foundation
|
||||
|
||||
protocol OrganismProtocol: class {
|
||||
|
||||
var dna: Int64 { get set }
|
||||
|
||||
func mutate()
|
||||
}
|
||||
@@ -0,0 +1,22 @@
|
||||
//
|
||||
// OrganismTableViewCell.swift
|
||||
// CoreStoreDemo
|
||||
//
|
||||
// Created by John Rommel Estropia on 2015/07/12.
|
||||
// Copyright © 2015 John Rommel Estropia. All rights reserved.
|
||||
//
|
||||
|
||||
import UIKit
|
||||
|
||||
class OrganismTableViewCell: UITableViewCell {
|
||||
|
||||
@IBOutlet weak dynamic var dnaLabel: UILabel?
|
||||
@IBOutlet weak dynamic var mutateButton: UIButton?
|
||||
|
||||
var mutateButtonHandler: (() -> Void)?
|
||||
|
||||
@IBAction dynamic func mutateButtonTouchUpInside(sender: UIButton?) {
|
||||
|
||||
self.mutateButtonHandler?()
|
||||
}
|
||||
}
|
||||
25
CoreStoreDemo/CoreStoreDemo/MIgrations Demo/OrganismV1.swift
Normal file
@@ -0,0 +1,25 @@
|
||||
//
|
||||
// OrganismV1.swift
|
||||
// CoreStoreDemo
|
||||
//
|
||||
// Created by John Rommel Estropia on 2015/06/21.
|
||||
// Copyright © 2015 John Rommel Estropia. All rights reserved.
|
||||
//
|
||||
|
||||
import Foundation
|
||||
import CoreData
|
||||
|
||||
class OrganismV1: NSManagedObject, OrganismProtocol {
|
||||
|
||||
@NSManaged var dna: Int64
|
||||
@NSManaged var hasHead: Bool
|
||||
@NSManaged var hasTail: Bool
|
||||
|
||||
// MARK: OrganismProtocol
|
||||
|
||||
func mutate() {
|
||||
|
||||
self.hasHead = arc4random_uniform(2) == 1
|
||||
self.hasTail = arc4random_uniform(2) == 1
|
||||
}
|
||||
}
|
||||
27
CoreStoreDemo/CoreStoreDemo/MIgrations Demo/OrganismV2.swift
Normal file
@@ -0,0 +1,27 @@
|
||||
//
|
||||
// OrganismV2.swift
|
||||
// CoreStoreDemo
|
||||
//
|
||||
// Created by John Rommel Estropia on 2015/06/21.
|
||||
// Copyright © 2015 John Rommel Estropia. All rights reserved.
|
||||
//
|
||||
|
||||
import Foundation
|
||||
import CoreData
|
||||
|
||||
class OrganismV2: NSManagedObject, OrganismProtocol {
|
||||
|
||||
@NSManaged var dna: Int64
|
||||
@NSManaged var hasHead: Bool
|
||||
@NSManaged var hasTail: Bool
|
||||
@NSManaged var numberOfFlippers: Int32
|
||||
|
||||
// MARK: OrganismProtocol
|
||||
|
||||
func mutate() {
|
||||
|
||||
self.hasHead = arc4random_uniform(2) == 1
|
||||
self.hasTail = arc4random_uniform(2) == 1
|
||||
self.numberOfFlippers = Int32(arc4random_uniform(9) / 2 * 2)
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,23 @@
|
||||
//
|
||||
// OrganismV2ToV3MigrationPolicy.swift
|
||||
// CoreStoreDemo
|
||||
//
|
||||
// Created by John Rommel Estropia on 2015/06/27.
|
||||
// Copyright © 2015 John Rommel Estropia. All rights reserved.
|
||||
//
|
||||
|
||||
import CoreData
|
||||
|
||||
class OrganismV2ToV3MigrationPolicy: NSEntityMigrationPolicy {
|
||||
|
||||
override func createDestinationInstancesForSourceInstance(sInstance: NSManagedObject, entityMapping mapping: NSEntityMapping, manager: NSMigrationManager) throws {
|
||||
|
||||
try super.createDestinationInstancesForSourceInstance(sInstance, entityMapping: mapping, manager: manager)
|
||||
|
||||
for dInstance in manager.destinationInstancesForEntityMappingNamed(mapping.name, sourceInstances: [sInstance]) {
|
||||
|
||||
dInstance.setValue(false, forKey: "hasVertebrae")
|
||||
dInstance.setValue(sInstance.valueForKey("numberOfFlippers"), forKey: "numberOfLimbs")
|
||||
}
|
||||
}
|
||||
}
|
||||
29
CoreStoreDemo/CoreStoreDemo/MIgrations Demo/OrganismV3.swift
Normal file
@@ -0,0 +1,29 @@
|
||||
//
|
||||
// OrganismV3.swift
|
||||
// CoreStoreDemo
|
||||
//
|
||||
// Created by John Rommel Estropia on 2015/06/27.
|
||||
// Copyright © 2015 John Rommel Estropia. All rights reserved.
|
||||
//
|
||||
|
||||
import Foundation
|
||||
import CoreData
|
||||
|
||||
class OrganismV3: NSManagedObject, OrganismProtocol {
|
||||
|
||||
@NSManaged var dna: Int64
|
||||
@NSManaged var hasHead: Bool
|
||||
@NSManaged var hasTail: Bool
|
||||
@NSManaged var numberOfLimbs: Int32
|
||||
@NSManaged var hasVertebrae: Bool
|
||||
|
||||
// MARK: OrganismProtocol
|
||||
|
||||
func mutate() {
|
||||
|
||||
self.hasHead = arc4random_uniform(2) == 1
|
||||
self.hasTail = arc4random_uniform(2) == 1
|
||||
self.numberOfLimbs = Int32(arc4random_uniform(9) / 2 * 2)
|
||||
self.hasVertebrae = arc4random_uniform(2) == 1
|
||||
}
|
||||
}
|
||||
@@ -3,6 +3,6 @@
|
||||
<plist version="1.0">
|
||||
<dict>
|
||||
<key>_XCCurrentVersionName</key>
|
||||
<string>MigrationDemoV2.xcdatamodel</string>
|
||||
<string>MigrationDemoV3.xcdatamodel</string>
|
||||
</dict>
|
||||
</plist>
|
||||
|
||||
@@ -1,7 +1,11 @@
|
||||
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
|
||||
<model userDefinedModelVersionIdentifier="" type="com.apple.IDECoreDataModeler.DataModel" documentVersion="1.0" lastSavedToolsVersion="7701" systemVersion="14D136" minimumToolsVersion="Xcode 4.3" macOSVersion="Automatic" iOSVersion="Automatic">
|
||||
<entity name="Organism" syncable="YES"/>
|
||||
<model userDefinedModelVersionIdentifier="" type="com.apple.IDECoreDataModeler.DataModel" documentVersion="1.0" lastSavedToolsVersion="7701" systemVersion="14E46" minimumToolsVersion="Xcode 4.3">
|
||||
<entity name="Organism" representedClassName="CoreStoreDemo.OrganismV1" syncable="YES">
|
||||
<attribute name="dna" optional="YES" attributeType="Integer 64" syncable="YES"/>
|
||||
<attribute name="hasHead" optional="YES" attributeType="Boolean" syncable="YES"/>
|
||||
<attribute name="hasTail" optional="YES" attributeType="Boolean" syncable="YES"/>
|
||||
</entity>
|
||||
<elements>
|
||||
<element name="Organism" positionX="-36" positionY="9" width="128" height="45"/>
|
||||
<element name="Organism" positionX="-36" positionY="9" width="128" height="90"/>
|
||||
</elements>
|
||||
</model>
|
||||
@@ -1,7 +1,12 @@
|
||||
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
|
||||
<model userDefinedModelVersionIdentifier="" type="com.apple.IDECoreDataModeler.DataModel" documentVersion="1.0" lastSavedToolsVersion="7701" systemVersion="14D136" minimumToolsVersion="Xcode 4.3" macOSVersion="Automatic" iOSVersion="Automatic">
|
||||
<entity name="Organism" syncable="YES"/>
|
||||
<model userDefinedModelVersionIdentifier="" type="com.apple.IDECoreDataModeler.DataModel" documentVersion="1.0" lastSavedToolsVersion="7701" systemVersion="14E46" minimumToolsVersion="Xcode 4.3">
|
||||
<entity name="Organism" representedClassName="CoreStoreDemo.OrganismV2" syncable="YES">
|
||||
<attribute name="dna" optional="YES" attributeType="Integer 64" syncable="YES"/>
|
||||
<attribute name="hasHead" attributeType="Boolean" syncable="YES"/>
|
||||
<attribute name="hasTail" attributeType="Boolean" syncable="YES"/>
|
||||
<attribute name="numberOfFlippers" attributeType="Integer 32" defaultValueString="0" syncable="YES"/>
|
||||
</entity>
|
||||
<elements>
|
||||
<element name="Organism" positionX="-36" positionY="9" width="128" height="45"/>
|
||||
<element name="Organism" positionX="-36" positionY="9" width="128" height="105"/>
|
||||
</elements>
|
||||
</model>
|
||||
@@ -0,0 +1,13 @@
|
||||
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
|
||||
<model userDefinedModelVersionIdentifier="" type="com.apple.IDECoreDataModeler.DataModel" documentVersion="1.0" lastSavedToolsVersion="7701" systemVersion="14E46" minimumToolsVersion="Xcode 4.3">
|
||||
<entity name="Organism" representedClassName="CoreStoreDemo.OrganismV3" syncable="YES">
|
||||
<attribute name="dna" optional="YES" attributeType="Integer 64" syncable="YES"/>
|
||||
<attribute name="hasHead" attributeType="Boolean" syncable="YES"/>
|
||||
<attribute name="hasTail" attributeType="Boolean" syncable="YES"/>
|
||||
<attribute name="hasVertebrae" attributeType="Boolean" syncable="YES"/>
|
||||
<attribute name="numberOfLimbs" attributeType="Integer 32" defaultValueString="0" syncable="YES"/>
|
||||
</entity>
|
||||
<elements>
|
||||
<element name="Organism" positionX="-36" positionY="9" width="128" height="120"/>
|
||||
</elements>
|
||||
</model>
|
||||
@@ -3,7 +3,7 @@
|
||||
// CoreStoreDemo
|
||||
//
|
||||
// Created by John Rommel Estropia on 2015/06/06.
|
||||
// Copyright (c) 2015 John Rommel Estropia. All rights reserved.
|
||||
// Copyright © 2015 John Rommel Estropia. All rights reserved.
|
||||
//
|
||||
|
||||
import Foundation
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
// CoreStoreDemo
|
||||
//
|
||||
// Created by John Rommel Estropia on 2015/06/06.
|
||||
// Copyright (c) 2015 John Rommel Estropia. All rights reserved.
|
||||
// Copyright © 2015 John Rommel Estropia. All rights reserved.
|
||||
//
|
||||
|
||||
import Foundation
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
// CoreStoreDemo
|
||||
//
|
||||
// Created by John Rommel Estropia on 2015/05/24.
|
||||
// Copyright (c) 2015 John Rommel Estropia. All rights reserved.
|
||||
// Copyright © 2015 John Rommel Estropia. All rights reserved.
|
||||
//
|
||||
|
||||
import UIKit
|
||||
@@ -18,15 +18,19 @@ private struct Static {
|
||||
static let facebookStack: DataStack = {
|
||||
|
||||
let dataStack = DataStack(modelName: "StackSetupDemo")
|
||||
dataStack.addSQLiteStoreAndWait(
|
||||
"AccountsDemo_FB_Male.sqlite",
|
||||
configuration: maleConfiguration,
|
||||
resetStoreOnMigrationFailure: true
|
||||
try! dataStack.addStorageAndWait(
|
||||
SQLiteStore(
|
||||
fileName: "AccountsDemo_FB_Male.sqlite",
|
||||
configuration: maleConfiguration,
|
||||
localStorageOptions: .RecreateStoreOnModelMismatch
|
||||
)
|
||||
)
|
||||
dataStack.addSQLiteStoreAndWait(
|
||||
"AccountsDemo_FB_Female.sqlite",
|
||||
configuration: femaleConfiguration,
|
||||
resetStoreOnMigrationFailure: true
|
||||
try! dataStack.addStorageAndWait(
|
||||
SQLiteStore(
|
||||
fileName: "AccountsDemo_FB_Female.sqlite",
|
||||
configuration: femaleConfiguration,
|
||||
localStorageOptions: .RecreateStoreOnModelMismatch
|
||||
)
|
||||
)
|
||||
|
||||
dataStack.beginSynchronous { (transaction) -> Void in
|
||||
@@ -43,7 +47,7 @@ private struct Static {
|
||||
account2.name = "Jane Doe HCD"
|
||||
account2.friends = 314
|
||||
|
||||
transaction.commit()
|
||||
transaction.commitAndWait()
|
||||
}
|
||||
|
||||
return dataStack
|
||||
@@ -52,15 +56,19 @@ private struct Static {
|
||||
static let twitterStack: DataStack = {
|
||||
|
||||
let dataStack = DataStack(modelName: "StackSetupDemo")
|
||||
dataStack.addSQLiteStoreAndWait(
|
||||
"AccountsDemo_TW_Male.sqlite",
|
||||
configuration: maleConfiguration,
|
||||
resetStoreOnMigrationFailure: true
|
||||
try! dataStack.addStorageAndWait(
|
||||
SQLiteStore(
|
||||
fileName: "AccountsDemo_TW_Male.sqlite",
|
||||
configuration: maleConfiguration,
|
||||
localStorageOptions: .RecreateStoreOnModelMismatch
|
||||
)
|
||||
)
|
||||
dataStack.addSQLiteStoreAndWait(
|
||||
"AccountsDemo_TW_Female.sqlite",
|
||||
configuration: femaleConfiguration,
|
||||
resetStoreOnMigrationFailure: true
|
||||
try! dataStack.addStorageAndWait(
|
||||
SQLiteStore(
|
||||
fileName: "AccountsDemo_TW_Female.sqlite",
|
||||
configuration: femaleConfiguration,
|
||||
localStorageOptions: .RecreateStoreOnModelMismatch
|
||||
)
|
||||
)
|
||||
|
||||
dataStack.beginSynchronous { (transaction) -> Void in
|
||||
@@ -77,7 +85,7 @@ private struct Static {
|
||||
account2.name = "#janedoe_hcd"
|
||||
account2.friends = 100
|
||||
|
||||
transaction.commit()
|
||||
transaction.commitAndWait()
|
||||
}
|
||||
|
||||
return dataStack
|
||||
@@ -138,7 +146,7 @@ class StackSetupDemoViewController: UITableViewController {
|
||||
|
||||
override func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
|
||||
|
||||
let cell = tableView.dequeueReusableCellWithIdentifier("UITableViewCell") as! UITableViewCell
|
||||
let cell = tableView.dequeueReusableCellWithIdentifier("UITableViewCell")!
|
||||
|
||||
let account = self.accounts[indexPath.section][indexPath.row]
|
||||
cell.textLabel?.text = account.name
|
||||
@@ -176,11 +184,11 @@ class StackSetupDemoViewController: UITableViewController {
|
||||
|
||||
// MARK: Private
|
||||
|
||||
@IBOutlet weak var accountTypeLabel: UILabel?
|
||||
@IBOutlet weak var nameLabel: UILabel?
|
||||
@IBOutlet weak var friendsLabel: UILabel?
|
||||
@IBOutlet private dynamic weak var accountTypeLabel: UILabel?
|
||||
@IBOutlet private dynamic weak var nameLabel: UILabel?
|
||||
@IBOutlet private dynamic weak var friendsLabel: UILabel?
|
||||
|
||||
func updateDetailsWithAccount(account: UserAccount) {
|
||||
private func updateDetailsWithAccount(account: UserAccount) {
|
||||
|
||||
self.accountTypeLabel?.text = account.accountType
|
||||
self.nameLabel?.text = account.name
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
// CoreStoreDemo
|
||||
//
|
||||
// Created by John Rommel Estropia on 2015/05/24.
|
||||
// Copyright (c) 2015 John Rommel Estropia. All rights reserved.
|
||||
// Copyright © 2015 John Rommel Estropia. All rights reserved.
|
||||
//
|
||||
|
||||
import Foundation
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
// CoreStoreDemo
|
||||
//
|
||||
// Created by John Rommel Estropia on 2015/05/24.
|
||||
// Copyright (c) 2015 John Rommel Estropia. All rights reserved.
|
||||
// Copyright © 2015 John Rommel Estropia. All rights reserved.
|
||||
//
|
||||
|
||||
import Foundation
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
// CoreStoreDemo
|
||||
//
|
||||
// Created by John Rommel Estropia on 2015/05/24.
|
||||
// Copyright (c) 2015 John Rommel Estropia. All rights reserved.
|
||||
// Copyright © 2015 John Rommel Estropia. All rights reserved.
|
||||
//
|
||||
|
||||
import UIKit
|
||||
@@ -16,12 +16,14 @@ import GCDKit
|
||||
|
||||
private struct Static {
|
||||
|
||||
static let placeController: ManagedObjectController<Place> = {
|
||||
static let placeController: ObjectMonitor<Place> = {
|
||||
|
||||
CoreStore.addSQLiteStoreAndWait(
|
||||
"PlaceDemo.sqlite",
|
||||
configuration: "TransactionsDemo",
|
||||
resetStoreOnMigrationFailure: true
|
||||
try! CoreStore.addStorageAndWait(
|
||||
SQLiteStore(
|
||||
fileName: "PlaceDemo.sqlite",
|
||||
configuration: "TransactionsDemo",
|
||||
localStorageOptions: .RecreateStoreOnModelMismatch
|
||||
)
|
||||
)
|
||||
|
||||
var place = CoreStore.fetchOne(From(Place))
|
||||
@@ -32,19 +34,19 @@ private struct Static {
|
||||
let place = transaction.create(Into(Place))
|
||||
place.setInitialValues()
|
||||
|
||||
transaction.commit()
|
||||
transaction.commitAndWait()
|
||||
}
|
||||
place = CoreStore.fetchOne(From(Place))
|
||||
}
|
||||
|
||||
return CoreStore.observeObject(place!)
|
||||
return CoreStore.monitorObject(place!)
|
||||
}()
|
||||
}
|
||||
|
||||
|
||||
// MARK: - TransactionsDemoViewController
|
||||
|
||||
class TransactionsDemoViewController: UIViewController, MKMapViewDelegate, ManagedObjectObserver {
|
||||
class TransactionsDemoViewController: UIViewController, MKMapViewDelegate, ObjectObserver {
|
||||
|
||||
// MARK: NSObject
|
||||
|
||||
@@ -60,7 +62,10 @@ class TransactionsDemoViewController: UIViewController, MKMapViewDelegate, Manag
|
||||
|
||||
super.viewDidLoad()
|
||||
|
||||
let longPressGesture = UILongPressGestureRecognizer(target: self, action: "longPressGestureRecognized:")
|
||||
let longPressGesture = UILongPressGestureRecognizer(
|
||||
target: self,
|
||||
action: #selector(self.longPressGestureRecognized(_:))
|
||||
)
|
||||
self.mapView?.addGestureRecognizer(longPressGesture)
|
||||
|
||||
Static.placeController.addObserver(self)
|
||||
@@ -68,7 +73,7 @@ class TransactionsDemoViewController: UIViewController, MKMapViewDelegate, Manag
|
||||
self.navigationItem.rightBarButtonItem = UIBarButtonItem(
|
||||
barButtonSystemItem: .Refresh,
|
||||
target: self,
|
||||
action: "refreshButtonTapped:"
|
||||
action: #selector(self.refreshButtonTapped(_:))
|
||||
)
|
||||
}
|
||||
|
||||
@@ -78,7 +83,7 @@ class TransactionsDemoViewController: UIViewController, MKMapViewDelegate, Manag
|
||||
|
||||
let alert = UIAlertController(
|
||||
title: "Transactions Demo",
|
||||
message: "This demo shows how to use the 3 types of transactions to save updates: synchronous, asynchronous, and detached.\n\nTap and hold on the map to change the pin location.",
|
||||
message: "This demo shows how to use the 3 types of transactions to save updates: synchronous, asynchronous, and unsafe.\n\nTap and hold on the map to change the pin location.",
|
||||
preferredStyle: .Alert
|
||||
)
|
||||
alert.addAction(UIAlertAction(title: "OK", style: .Cancel, handler: nil))
|
||||
@@ -100,7 +105,7 @@ class TransactionsDemoViewController: UIViewController, MKMapViewDelegate, Manag
|
||||
|
||||
// MARK: MKMapViewDelegate
|
||||
|
||||
func mapView(mapView: MKMapView!, viewForAnnotation annotation: MKAnnotation!) -> MKAnnotationView! {
|
||||
func mapView(mapView: MKMapView, viewForAnnotation annotation: MKAnnotation) -> MKAnnotationView? {
|
||||
|
||||
let identifier = "MKAnnotationView"
|
||||
var annotationView: MKPinAnnotationView! = mapView.dequeueReusableAnnotationViewWithIdentifier(identifier) as? MKPinAnnotationView
|
||||
@@ -120,14 +125,14 @@ class TransactionsDemoViewController: UIViewController, MKMapViewDelegate, Manag
|
||||
}
|
||||
|
||||
|
||||
// MARK: ManagedObjectObserver
|
||||
// MARK: ObjectObserver
|
||||
|
||||
func managedObjectWillUpdate(objectController: ManagedObjectController<Place>, object: Place) {
|
||||
func objectMonitor(monitor: ObjectMonitor<Place>, willUpdateObject object: Place) {
|
||||
|
||||
// none
|
||||
}
|
||||
|
||||
func managedObjectWasUpdated(objectController: ManagedObjectController<Place>, object: Place, changedPersistentKeys: Set<KeyPath>) {
|
||||
func objectMonitor(monitor: ObjectMonitor<Place>, didUpdateObject object: Place, changedPersistentKeys: Set<KeyPath>) {
|
||||
|
||||
if let mapView = self.mapView {
|
||||
|
||||
@@ -143,7 +148,7 @@ class TransactionsDemoViewController: UIViewController, MKMapViewDelegate, Manag
|
||||
}
|
||||
}
|
||||
|
||||
func managedObjectWasDeleted(objectController: ManagedObjectController<Place>, object: Place) {
|
||||
func objectMonitor(monitor: ObjectMonitor<Place>, didDeleteObject object: Place) {
|
||||
|
||||
// none
|
||||
}
|
||||
@@ -159,13 +164,14 @@ class TransactionsDemoViewController: UIViewController, MKMapViewDelegate, Manag
|
||||
|
||||
if let mapView = self.mapView, let gesture = sender as? UILongPressGestureRecognizer where gesture.state == .Began {
|
||||
|
||||
let coordinate = mapView.convertPoint(
|
||||
gesture.locationInView(mapView),
|
||||
toCoordinateFromView: mapView
|
||||
)
|
||||
CoreStore.beginAsynchronous { (transaction) -> Void in
|
||||
|
||||
let place = transaction.edit(Static.placeController.object)
|
||||
place?.coordinate = mapView.convertPoint(
|
||||
gesture.locationInView(mapView),
|
||||
toCoordinateFromView: mapView
|
||||
)
|
||||
place?.coordinate = coordinate
|
||||
transaction.commit { (_) -> Void in }
|
||||
}
|
||||
}
|
||||
@@ -177,27 +183,27 @@ class TransactionsDemoViewController: UIViewController, MKMapViewDelegate, Manag
|
||||
|
||||
let place = transaction.edit(Static.placeController.object)
|
||||
place?.setInitialValues()
|
||||
transaction.commit()
|
||||
transaction.commitAndWait()
|
||||
}
|
||||
}
|
||||
|
||||
func geocodePlace(place: Place) {
|
||||
|
||||
let transaction = CoreStore.beginDetached()
|
||||
let transaction = CoreStore.beginUnsafe()
|
||||
|
||||
self.geocoder?.cancelGeocode()
|
||||
|
||||
var geocoder = CLGeocoder()
|
||||
let geocoder = CLGeocoder()
|
||||
self.geocoder = geocoder
|
||||
geocoder.reverseGeocodeLocation(
|
||||
CLLocation(latitude: place.latitude, longitude: place.longitude),
|
||||
completionHandler: { [weak self] (placemarks, error) -> Void in
|
||||
|
||||
if let strongSelf = self, let placemark = (placemarks as? [CLPlacemark])?.first {
|
||||
if let placemark = placemarks?.first, let addressDictionary = placemark.addressDictionary {
|
||||
|
||||
let place = transaction.edit(Static.placeController.object)
|
||||
place?.title = placemark.name
|
||||
place?.subtitle = ABCreateStringWithAddressDictionary(placemark.addressDictionary, true)
|
||||
place?.subtitle = ABCreateStringWithAddressDictionary(addressDictionary, true)
|
||||
transaction.commit { (_) -> Void in }
|
||||
}
|
||||
|
||||
|
||||
BIN
CoreStoreDemo/appIcons.sketch
Normal file
201
CoreStoreTests/BaseTests/BaseTestCase.swift
Normal file
@@ -0,0 +1,201 @@
|
||||
//
|
||||
// BaseTestCase.swift
|
||||
// CoreStore
|
||||
//
|
||||
// Copyright © 2016 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 XCTest
|
||||
|
||||
@testable
|
||||
import CoreStore
|
||||
|
||||
|
||||
// MARK: - BaseTestCase
|
||||
|
||||
class BaseTestCase: XCTestCase {
|
||||
|
||||
// MARK: Internal
|
||||
|
||||
@nonobjc
|
||||
func prepareStack<T>(configurations configurations: [String?] = [nil], @noescape _ closure: (dataStack: DataStack) -> T) -> T {
|
||||
|
||||
let stack = DataStack(
|
||||
modelName: "Model",
|
||||
bundle: NSBundle(forClass: self.dynamicType)
|
||||
)
|
||||
do {
|
||||
|
||||
try configurations.forEach {
|
||||
|
||||
try stack.addStorageAndWait(
|
||||
SQLiteStore(
|
||||
fileURL: SQLiteStore.defaultRootDirectory
|
||||
.URLByAppendingPathComponent(NSUUID().UUIDString)
|
||||
.URLByAppendingPathComponent("\(self.dynamicType)_\(($0 ?? "-null-")).sqlite"),
|
||||
configuration: $0,
|
||||
localStorageOptions: .RecreateStoreOnModelMismatch
|
||||
)
|
||||
)
|
||||
}
|
||||
}
|
||||
catch let error as NSError {
|
||||
|
||||
XCTFail(error.coreStoreDumpString)
|
||||
}
|
||||
return closure(dataStack: stack)
|
||||
}
|
||||
|
||||
@nonobjc
|
||||
func expectLogger<T>(expectations: [TestLogger.Expectation], @noescape closure: () -> T) -> T {
|
||||
|
||||
CoreStore.logger = TestLogger(self.prepareLoggerExpectations(expectations))
|
||||
defer {
|
||||
|
||||
self.checkExpectationsImmediately()
|
||||
CoreStore.logger = TestLogger([:])
|
||||
}
|
||||
return closure()
|
||||
}
|
||||
|
||||
@nonobjc
|
||||
func expectLogger(expectations: [TestLogger.Expectation: XCTestExpectation]) {
|
||||
|
||||
CoreStore.logger = TestLogger(expectations)
|
||||
}
|
||||
|
||||
@nonobjc
|
||||
func prepareLoggerExpectations(expectations: [TestLogger.Expectation]) -> [TestLogger.Expectation: XCTestExpectation] {
|
||||
|
||||
var testExpectations: [TestLogger.Expectation: XCTestExpectation] = [:]
|
||||
for expectation in expectations {
|
||||
|
||||
testExpectations[expectation] = self.expectationWithDescription("Logger Expectation: \(expectation)")
|
||||
}
|
||||
return testExpectations
|
||||
}
|
||||
|
||||
@nonobjc
|
||||
func checkExpectationsImmediately() {
|
||||
|
||||
self.waitForExpectationsWithTimeout(0, handler: nil)
|
||||
}
|
||||
|
||||
@nonobjc
|
||||
func waitAndCheckExpectations() {
|
||||
|
||||
self.waitForExpectationsWithTimeout(10, handler: nil)
|
||||
}
|
||||
|
||||
// MARK: XCTestCase
|
||||
|
||||
override func setUp() {
|
||||
|
||||
super.setUp()
|
||||
self.deleteStores()
|
||||
CoreStore.logger = TestLogger([:])
|
||||
}
|
||||
|
||||
override func tearDown() {
|
||||
|
||||
CoreStore.logger = DefaultLogger()
|
||||
self.deleteStores()
|
||||
super.tearDown()
|
||||
}
|
||||
|
||||
|
||||
// MARK: Private
|
||||
|
||||
private func deleteStores() {
|
||||
|
||||
_ = try? NSFileManager.defaultManager().removeItemAtURL(SQLiteStore.defaultRootDirectory)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// MARK: - TestLogger
|
||||
|
||||
class TestLogger: CoreStoreLogger {
|
||||
|
||||
enum Expectation {
|
||||
|
||||
case LogWarning
|
||||
case LogFatal
|
||||
case LogError
|
||||
case AssertionFailure
|
||||
case FatalError
|
||||
}
|
||||
|
||||
init(_ expectations: [Expectation: XCTestExpectation]) {
|
||||
|
||||
self.expectations = expectations
|
||||
}
|
||||
|
||||
|
||||
// MARK: CoreStoreLogger
|
||||
|
||||
func log(level level: LogLevel, message: String, fileName: StaticString, lineNumber: Int, functionName: StaticString) {
|
||||
|
||||
switch level {
|
||||
|
||||
case .Warning: self.fulfill(.LogWarning)
|
||||
case .Fatal: self.fulfill(.LogFatal)
|
||||
default: break
|
||||
}
|
||||
}
|
||||
|
||||
func log(error error: CoreStoreError, message: String, fileName: StaticString, lineNumber: Int, functionName: StaticString) {
|
||||
|
||||
self.fulfill(.LogError)
|
||||
}
|
||||
|
||||
func assert(@autoclosure condition: () -> Bool, @autoclosure message: () -> String, fileName: StaticString, lineNumber: Int, functionName: StaticString) {
|
||||
|
||||
if condition() {
|
||||
|
||||
return
|
||||
}
|
||||
self.fulfill(.AssertionFailure)
|
||||
}
|
||||
|
||||
func abort(message: String, fileName: StaticString, lineNumber: Int, functionName: StaticString) {
|
||||
|
||||
self.fulfill(.FatalError)
|
||||
}
|
||||
|
||||
|
||||
// MARK: Private
|
||||
|
||||
private var expectations: [Expectation: XCTestExpectation]
|
||||
|
||||
private func fulfill(expectation: Expectation) {
|
||||
|
||||
if let instance = self.expectations[expectation] {
|
||||
|
||||
instance.fulfill()
|
||||
self.expectations[expectation] = nil
|
||||
}
|
||||
else {
|
||||
|
||||
XCTFail("Unexpected Logger Action: \(expectation)")
|
||||
}
|
||||
}
|
||||
}
|
||||
76
CoreStoreTests/BaseTests/BaseTestDataTestCase.swift
Normal file
@@ -0,0 +1,76 @@
|
||||
//
|
||||
// BaseTestDataTestCase.swift
|
||||
// CoreStore
|
||||
//
|
||||
// Created by John Rommel Estropia on 2016/06/11.
|
||||
// Copyright © 2016 John Rommel Estropia. All rights reserved.
|
||||
//
|
||||
|
||||
import Foundation
|
||||
|
||||
@testable
|
||||
import CoreStore
|
||||
|
||||
|
||||
// MARK: - BaseTestDataTestCase
|
||||
|
||||
class BaseTestDataTestCase: BaseTestCase {
|
||||
|
||||
@nonobjc
|
||||
let dateFormatter: NSDateFormatter = {
|
||||
|
||||
let formatter = NSDateFormatter()
|
||||
formatter.locale = NSLocale(localeIdentifier: "en_US_POSIX")
|
||||
formatter.timeZone = NSTimeZone(name: "UTC")
|
||||
formatter.calendar = NSCalendar(identifier: NSCalendarIdentifierGregorian)
|
||||
formatter.dateFormat = "yyyy'-'MM'-'dd'T'HH':'mm':'ssZ"
|
||||
return formatter
|
||||
}()
|
||||
|
||||
@nonobjc
|
||||
func prepareTestDataForStack(stack: DataStack, configurations: [String?] = [nil]) {
|
||||
|
||||
stack.beginSynchronous { (transaction) in
|
||||
|
||||
for (configurationIndex, configuration) in configurations.enumerate() {
|
||||
|
||||
let configurationOrdinal = configurationIndex + 1
|
||||
if configuration == nil || configuration == "Config1" {
|
||||
|
||||
for idIndex in 1 ... 5 {
|
||||
|
||||
let object = transaction.create(Into<TestEntity1>(configuration))
|
||||
object.testEntityID = NSNumber(integer: (configurationOrdinal * 100) + idIndex)
|
||||
|
||||
object.testNumber = idIndex
|
||||
object.testDate = self.dateFormatter.dateFromString("2000-\(configurationOrdinal)-\(idIndex)T00:00:00Z")
|
||||
object.testBoolean = (idIndex % 2) == 1
|
||||
object.testDecimal = NSDecimalNumber(string: "\(idIndex)")
|
||||
|
||||
let string = "\(configuration ?? "nil"):TestEntity1:\(idIndex)"
|
||||
object.testString = string
|
||||
object.testData = (string as NSString).dataUsingEncoding(NSUTF8StringEncoding)
|
||||
}
|
||||
}
|
||||
if configuration == nil || configuration == "Config2" {
|
||||
|
||||
for idIndex in 1 ... 5 {
|
||||
|
||||
let object = transaction.create(Into<TestEntity2>(configuration))
|
||||
object.testEntityID = NSNumber(integer: (configurationOrdinal * 200) + idIndex)
|
||||
|
||||
object.testNumber = idIndex
|
||||
object.testDate = self.dateFormatter.dateFromString("2000-\(configurationOrdinal)-\(idIndex)T00:00:00Z")
|
||||
object.testBoolean = (idIndex % 2) == 1
|
||||
object.testDecimal = NSDecimalNumber(string: "\(idIndex)")
|
||||
|
||||
let string = "\(configuration ?? "nil"):TestEntity2:\(idIndex)"
|
||||
object.testString = string
|
||||
object.testData = (string as NSString).dataUsingEncoding(NSUTF8StringEncoding)
|
||||
}
|
||||
}
|
||||
}
|
||||
transaction.commitAndWait()
|
||||
}
|
||||
}
|
||||
}
|
||||
30
CoreStoreTests/BridgingTests.h
Normal file
@@ -0,0 +1,30 @@
|
||||
//
|
||||
// BridgingTests.h
|
||||
// CoreStore
|
||||
//
|
||||
// Copyright © 2016 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 <XCTest/XCTest.h>
|
||||
|
||||
@interface BridgingTests : XCTestCase
|
||||
|
||||
@end
|
||||
200
CoreStoreTests/BridgingTests.m
Normal file
@@ -0,0 +1,200 @@
|
||||
//
|
||||
// BridgingTests.m
|
||||
// CoreStore
|
||||
//
|
||||
// Copyright © 2016 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 "BridgingTests.h"
|
||||
#import <CoreStore/CoreStore.h>
|
||||
#import <CoreStore/CoreStore-Swift.h>
|
||||
#import "CoreStoreTests-Swift.h"
|
||||
|
||||
@import CoreData;
|
||||
|
||||
// MARK: - BridgingTests
|
||||
|
||||
@implementation BridgingTests
|
||||
|
||||
- (void)test_ThatFlags_HaveCorrectValues {
|
||||
|
||||
XCTAssertEqual(CSLocalStorageOptionsNone, 0);
|
||||
XCTAssertEqual(CSLocalStorageOptionsRecreateStoreOnModelMismatch, 1);
|
||||
XCTAssertEqual(CSLocalStorageOptionsPreventProgressiveMigration, 2);
|
||||
XCTAssertEqual(CSLocalStorageOptionsAllowSynchronousLightweightMigration, 4);
|
||||
}
|
||||
|
||||
- (void)test_ThatKeyPaths_AreCorrect {
|
||||
|
||||
XCTAssertEqualObjects(CSKeyPath(TestEntity1, testNumber), @"testNumber");
|
||||
XCTAssertEqualObjects(CSKeyPath(TestEntity1, testString), @"testString");
|
||||
XCTAssertEqualObjects(CSKeyPathOperator(count, TestEntity1, testString), @"@count.testString");
|
||||
XCTAssertEqualObjects(CSKeyPathOperator(max, TestEntity1, testNumber), @"@max.testNumber");
|
||||
}
|
||||
|
||||
- (void)test_ThatFromClauses_BridgeCorrectly {
|
||||
|
||||
{
|
||||
CSFrom *from = CSFromClass([TestEntity1 class]);
|
||||
XCTAssertEqualObjects(from.entityClass, [TestEntity1 class]);
|
||||
XCTAssertNil(from.configurations);
|
||||
}
|
||||
{
|
||||
CSFrom *from = CSFromClass([TestEntity1 class], [NSNull null]);
|
||||
XCTAssertEqualObjects(from.entityClass, [TestEntity1 class]);
|
||||
|
||||
NSArray *configurations = @[[NSNull null]];
|
||||
XCTAssertEqualObjects(from.configurations, configurations);
|
||||
}
|
||||
{
|
||||
CSFrom *from = CSFromClass([TestEntity1 class], @"Config1");
|
||||
XCTAssertEqualObjects(from.entityClass, [TestEntity1 class]);
|
||||
|
||||
NSArray *configurations = @[@"Config1"];
|
||||
XCTAssertEqualObjects(from.configurations, configurations);
|
||||
}
|
||||
{
|
||||
CSFrom *from = CSFromClass([TestEntity1 class], @[[NSNull null], @"Config2"]);
|
||||
XCTAssertEqualObjects(from.entityClass, [TestEntity1 class]);
|
||||
|
||||
NSArray *configurations = @[[NSNull null], @"Config2"];
|
||||
XCTAssertEqualObjects(from.configurations, configurations);
|
||||
}
|
||||
}
|
||||
|
||||
- (void)test_ThatWhereClauses_BridgeCorrectly {
|
||||
|
||||
{
|
||||
CSWhere *where = CSWhereFormat(@"%K == %@", @"key", @"value");
|
||||
NSPredicate *predicate = [NSPredicate predicateWithFormat:@"%K == %@", @"key", @"value"];
|
||||
XCTAssertEqualObjects(where.predicate, predicate);
|
||||
}
|
||||
{
|
||||
CSWhere *where = CSWhereValue(YES);
|
||||
NSPredicate *predicate = [NSPredicate predicateWithValue:YES];
|
||||
XCTAssertEqualObjects(where.predicate, predicate);
|
||||
}
|
||||
{
|
||||
CSWhere *where = CSWherePredicate([NSPredicate predicateWithFormat:@"%K == %@", @"key", @"value"]);
|
||||
NSPredicate *predicate = [NSPredicate predicateWithFormat:@"%K == %@", @"key", @"value"];
|
||||
XCTAssertEqualObjects(where.predicate, predicate);
|
||||
}
|
||||
}
|
||||
|
||||
- (void)test_ThatOrderByClauses_BridgeCorrectly {
|
||||
|
||||
{
|
||||
CSOrderBy *orderBy = CSOrderByKey(CSSortAscending(@"key"));
|
||||
XCTAssertEqualObjects(orderBy.sortDescriptors, @[[NSSortDescriptor sortDescriptorWithKey:@"key" ascending:YES]]);
|
||||
}
|
||||
{
|
||||
CSOrderBy *orderBy = CSOrderByKey(CSSortDescending(@"key"));
|
||||
XCTAssertEqualObjects(orderBy.sortDescriptors, @[[NSSortDescriptor sortDescriptorWithKey:@"key" ascending:NO]]);
|
||||
}
|
||||
{
|
||||
CSOrderBy *orderBy = CSOrderByKeys(CSSortAscending(@"key1"), CSSortDescending(@"key2"), nil);
|
||||
NSArray *sortDescriptors = @[[NSSortDescriptor sortDescriptorWithKey:@"key1" ascending:YES],
|
||||
[NSSortDescriptor sortDescriptorWithKey:@"key2" ascending:NO]];
|
||||
XCTAssertEqualObjects(orderBy.sortDescriptors, sortDescriptors);
|
||||
}
|
||||
}
|
||||
|
||||
- (void)test_ThatGroupByClauses_BridgeCorrectly {
|
||||
|
||||
{
|
||||
CSGroupBy *groupBy = CSGroupByKeyPath(@"key");
|
||||
XCTAssertEqualObjects(groupBy.keyPaths, @[@"key"]);
|
||||
}
|
||||
{
|
||||
CSGroupBy *groupBy = CSGroupByKeyPaths(@[@"key1", @"key2"]);
|
||||
|
||||
NSArray *keyPaths = @[@"key1", @"key2"];
|
||||
XCTAssertEqualObjects(groupBy.keyPaths, keyPaths);
|
||||
}
|
||||
}
|
||||
|
||||
- (void)test_ThatTweakClauses_BridgeCorrectly {
|
||||
|
||||
CSTweak *tweak = CSTweakRequest(^(NSFetchRequest * _Nonnull fetchRequest) {
|
||||
|
||||
fetchRequest.fetchLimit = 100;
|
||||
});
|
||||
NSFetchRequest *request = [NSFetchRequest new];
|
||||
tweak.block(request);
|
||||
XCTAssertEqual(request.fetchLimit, 100);
|
||||
}
|
||||
|
||||
- (void)test_ThatIntoClauses_BridgeCorrectly {
|
||||
|
||||
{
|
||||
CSInto *into = CSIntoClass([TestEntity1 class]);
|
||||
XCTAssertEqualObjects(into.entityClass, [TestEntity1 class]);
|
||||
}
|
||||
{
|
||||
CSInto *into = CSIntoClass([TestEntity1 class], [NSNull null]);
|
||||
XCTAssertEqualObjects(into.entityClass, [TestEntity1 class]);
|
||||
XCTAssertNil(into.configuration);
|
||||
}
|
||||
{
|
||||
CSInto *into = CSIntoClass([TestEntity1 class], @"Config1");
|
||||
XCTAssertEqualObjects(into.entityClass, [TestEntity1 class]);
|
||||
XCTAssertEqualObjects(into.configuration, @"Config1");
|
||||
}
|
||||
}
|
||||
|
||||
- (void)test_ThatDataStacks_BridgeCorrectly {
|
||||
|
||||
CSDataStack *dataStack = [[CSDataStack alloc]
|
||||
initWithModelName:@"Model"
|
||||
bundle:[NSBundle bundleForClass:[self class]]
|
||||
versionChain:nil];
|
||||
XCTAssertNotNil(dataStack);
|
||||
|
||||
[CSCoreStore setDefaultStack:dataStack];
|
||||
XCTAssertTrue([dataStack isEqual:[CSCoreStore defaultStack]]);
|
||||
}
|
||||
|
||||
- (void)test_ThatStorages_BridgeCorrectly {
|
||||
|
||||
NSError *memoryError;
|
||||
CSInMemoryStore *memoryStorage = [CSCoreStore
|
||||
addInMemoryStorageAndWait:[CSInMemoryStore new]
|
||||
error:&memoryError];
|
||||
XCTAssertNotNil(memoryStorage);
|
||||
XCTAssertEqualObjects([[memoryStorage class] storeType], [CSInMemoryStore storeType]);
|
||||
XCTAssertEqualObjects([[memoryStorage class] storeType], NSInMemoryStoreType);
|
||||
XCTAssertNil(memoryStorage.configuration);
|
||||
XCTAssertNil(memoryStorage.storeOptions);
|
||||
XCTAssertNil(memoryError);
|
||||
|
||||
NSError *sqliteError;
|
||||
CSSQLiteStore *sqliteStorage = [CSCoreStore
|
||||
addSQLiteStorageAndWait:[CSSQLiteStore new]
|
||||
error:&sqliteError];
|
||||
XCTAssertNotNil(sqliteStorage);
|
||||
XCTAssertEqualObjects([[sqliteStorage class] storeType], [CSSQLiteStore storeType]);
|
||||
XCTAssertEqualObjects([[sqliteStorage class] storeType], NSSQLiteStoreType);
|
||||
XCTAssertNil(sqliteStorage.configuration);
|
||||
XCTAssertEqualObjects(sqliteStorage.storeOptions, @{ NSSQLitePragmasOption: @{ @"journal_mode": @"WAL" } });
|
||||
XCTAssertNil(sqliteError);
|
||||
}
|
||||
|
||||
@end
|
||||
5
CoreStoreTests/CoreStoreTests-Bridging-Header.h
Normal file
@@ -0,0 +1,5 @@
|
||||
//
|
||||
// Use this file to import your target's public headers that you would like to expose to Swift.
|
||||
//
|
||||
|
||||
#import "BridgingTests.h"
|
||||