mirror of
https://github.com/JohnEstropia/CoreStore.git
synced 2026-01-12 04:10:36 +01:00
Compare commits
59 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
d971c3a2ac | ||
|
|
80166a42bb | ||
|
|
3d8bdf1cf3 | ||
|
|
1ddce5aa8d | ||
|
|
7a1600fac4 | ||
|
|
e4e664d8ce | ||
|
|
145edd5a7d | ||
|
|
f5fed063ee | ||
|
|
a267395618 | ||
|
|
326b897b06 | ||
|
|
0b18366ab1 | ||
|
|
ddf599ba85 | ||
|
|
6e3e540d0a | ||
|
|
bd066f0cef | ||
|
|
9764f33086 | ||
|
|
0c19c878c5 | ||
|
|
1b8e517b5a | ||
|
|
2818a778a4 | ||
|
|
64a0264354 | ||
|
|
7932625644 | ||
|
|
4619fbbec3 | ||
|
|
6b64eb7650 | ||
|
|
f5a165d47d | ||
|
|
12c58e3955 | ||
|
|
5af0d17de4 | ||
|
|
81dfb8e3e5 | ||
|
|
d5114fc4bc | ||
|
|
693fc7fbbb | ||
|
|
b073b7e795 | ||
|
|
953c9723a8 | ||
|
|
c5a996d5ed | ||
|
|
53a83d823e | ||
|
|
0345ee9c94 | ||
|
|
4016b5dc83 | ||
|
|
64b5e102aa | ||
|
|
8e3c44c072 | ||
|
|
12dc32f7e6 | ||
|
|
b4c38caf1e | ||
|
|
266b1a9913 | ||
|
|
1740d168c8 | ||
|
|
d42b397090 | ||
|
|
058cc1915b | ||
|
|
02d5bf85ae | ||
|
|
f0dac2454c | ||
|
|
d4deed0cf7 | ||
|
|
79655ffde5 | ||
|
|
cf46b45e8e | ||
|
|
ed3d21db77 | ||
|
|
f16e3593c0 | ||
|
|
67bb9340c7 | ||
|
|
5d49bd79f2 | ||
|
|
9f397b4337 | ||
|
|
7508d150d6 | ||
|
|
239db8168d | ||
|
|
30ab4386bf | ||
|
|
08053ccb15 | ||
|
|
367cfea8a7 | ||
|
|
5d3b7e3dab | ||
|
|
fe7e6e7b84 |
3
.gitignore
vendored
3
.gitignore
vendored
@@ -9,3 +9,6 @@ DerivedData
|
||||
*.orig
|
||||
build
|
||||
Playground_macOS.playground/playground.xcworkspace/xcuserdata
|
||||
.swiftpm/xcode/package.xcworkspace/xcuserdata
|
||||
.swiftpm/xcode/xcuserdata
|
||||
Playground_iOS.playground/playground.xcworkspace/xcuserdata
|
||||
|
||||
7
.swiftpm/xcode/package.xcworkspace/contents.xcworkspacedata
generated
Normal file
7
.swiftpm/xcode/package.xcworkspace/contents.xcworkspacedata
generated
Normal file
@@ -0,0 +1,7 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<Workspace
|
||||
version = "1.0">
|
||||
<FileRef
|
||||
location = "self:">
|
||||
</FileRef>
|
||||
</Workspace>
|
||||
@@ -0,0 +1,8 @@
|
||||
<?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>IDEDidComputeMac32BitWarning</key>
|
||||
<true/>
|
||||
</dict>
|
||||
</plist>
|
||||
@@ -0,0 +1,14 @@
|
||||
<?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>SchemeUserState</key>
|
||||
<dict>
|
||||
<key>CoreStore.xcscheme_^#shared#^_</key>
|
||||
<dict>
|
||||
<key>orderHint</key>
|
||||
<integer>0</integer>
|
||||
</dict>
|
||||
</dict>
|
||||
</dict>
|
||||
</plist>
|
||||
41
.travis.yml
41
.travis.yml
@@ -1,41 +0,0 @@
|
||||
language: objective-c
|
||||
osx_image: xcode10.2
|
||||
sudo: false
|
||||
git:
|
||||
submodules: false
|
||||
notifications:
|
||||
email: false
|
||||
env:
|
||||
global:
|
||||
- LC_CTYPE=en_US.UTF-8
|
||||
- LANG=en_US.UTF-8
|
||||
matrix:
|
||||
- DESTINATION="arch=x86_64" SCHEME="CoreStore OSX" SDK=macosx10.14 RUN_TESTS="YES" POD_LINT="NO"
|
||||
- DESTINATION="OS=12.0,name=iPhone XS" SCHEME="CoreStore iOS" SDK=iphonesimulator12.0 RUN_TESTS="YES" POD_LINT="NO"
|
||||
- DESTINATION="OS=11.0.1,name=iPhone 8" SCHEME="CoreStore iOS" SDK=iphonesimulator12.0 RUN_TESTS="YES" POD_LINT="NO"
|
||||
- DESTINATION="OS=10.3.1,name=iPhone 7" SCHEME="CoreStore iOS" SDK=iphonesimulator12.0 RUN_TESTS="YES" POD_LINT="NO"
|
||||
- DESTINATION="OS=10.1,name=iPhone 7" SCHEME="CoreStore iOS" SDK=iphonesimulator12.0 RUN_TESTS="YES" POD_LINT="NO"
|
||||
- DESTINATION="OS=4.0,name=Apple Watch - 42mm" SCHEME="CoreStore watchOS" SDK=watchsimulator5.0 RUN_TESTS="NO" POD_LINT="NO"
|
||||
- DESTINATION="OS=3.2,name=Apple Watch - 42mm" SCHEME="CoreStore watchOS" SDK=watchsimulator5.0 RUN_TESTS="NO" POD_LINT="NO"
|
||||
- DESTINATION="OS=2.2,name=Apple Watch - 42mm" SCHEME="CoreStore watchOS" SDK=watchsimulator5.0 RUN_TESTS="NO" POD_LINT="NO"
|
||||
- DESTINATION="OS=12.0,name=Apple TV 4K" SCHEME="CoreStore tvOS" SDK=appletvsimulator12.0 RUN_TESTS="YES" POD_LINT="NO"
|
||||
- DESTINATION="OS=11.0,name=Apple TV 4K (at 1080p)" SCHEME="CoreStore tvOS" SDK=appletvsimulator12.0 RUN_TESTS="YES" POD_LINT="NO"
|
||||
- DESTINATION="OS=10.2,name=Apple TV 1080p" SCHEME="CoreStore tvOS" SDK=appletvsimulator12.0 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
|
||||
- npm install ios-sim -g
|
||||
- ios-sim start --devicetypeid "com.apple.CoreSimulator.SimDeviceType.iPhone-8, 11.0"
|
||||
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 "CoreStoreDemo" -sdk "iphonesimulator12.0" -destination "OS=11.0.1,name=iPhone 8" -configuration Debug ONLY_ACTIVE_ARCH=NO build | xcpretty -c;
|
||||
- xcodebuild -workspace "CoreStore.xcworkspace" -scheme "CoreStoreDemo" -sdk "iphonesimulator12.0" -destination "OS=11.0.1,name=iPhone 8" -configuration Release ONLY_ACTIVE_ARCH=NO build | xcpretty -c;
|
||||
- if [ $POD_LINT == "YES" ]; then
|
||||
pod lib lint --quick;
|
||||
fi
|
||||
@@ -1,7 +1,7 @@
|
||||
Pod::Spec.new do |s|
|
||||
s.name = "CoreStore"
|
||||
s.version = "6.3.0"
|
||||
s.swift_version = "5.0"
|
||||
s.version = "7.0.0"
|
||||
s.swift_version = "5.1"
|
||||
s.license = "MIT"
|
||||
s.homepage = "https://github.com/JohnEstropia/CoreStore"
|
||||
s.documentation_url = "https://JohnEstropia.github.io/CoreStore"
|
||||
@@ -18,5 +18,5 @@ Pod::Spec.new do |s|
|
||||
s.public_header_files = "Sources/**/*.h"
|
||||
s.frameworks = "Foundation", "CoreData"
|
||||
s.requires_arc = true
|
||||
s.pod_target_xcconfig = { 'OTHER_SWIFT_FLAGS[config=Debug]' => '-D DEBUG' }
|
||||
s.pod_target_xcconfig = { 'OTHER_SWIFT_FLAGS[config=Debug]' => '-D DEBUG', 'OTHER_LDFLAGS' => '-weak_framework Combine' }
|
||||
end
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -27,6 +27,15 @@
|
||||
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
|
||||
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
|
||||
shouldUseLaunchSchemeArgsEnv = "YES">
|
||||
<MacroExpansion>
|
||||
<BuildableReference
|
||||
BuildableIdentifier = "primary"
|
||||
BlueprintIdentifier = "B52DD1731BE1F8CC00949AFE"
|
||||
BuildableName = "CoreStore.framework"
|
||||
BlueprintName = "CoreStore OSX"
|
||||
ReferencedContainer = "container:CoreStore.xcodeproj">
|
||||
</BuildableReference>
|
||||
</MacroExpansion>
|
||||
<Testables>
|
||||
<TestableReference
|
||||
skipped = "NO">
|
||||
@@ -39,17 +48,6 @@
|
||||
</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"
|
||||
@@ -70,8 +68,6 @@
|
||||
ReferencedContainer = "container:CoreStore.xcodeproj">
|
||||
</BuildableReference>
|
||||
</MacroExpansion>
|
||||
<AdditionalOptions>
|
||||
</AdditionalOptions>
|
||||
</LaunchAction>
|
||||
<ProfileAction
|
||||
buildConfiguration = "Release"
|
||||
|
||||
@@ -41,18 +41,6 @@
|
||||
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"
|
||||
@@ -69,6 +57,18 @@
|
||||
isEnabled = "YES">
|
||||
</AdditionalOption>
|
||||
</AdditionalOptions>
|
||||
<Testables>
|
||||
<TestableReference
|
||||
skipped = "NO">
|
||||
<BuildableReference
|
||||
BuildableIdentifier = "primary"
|
||||
BlueprintIdentifier = "2F03A53A19C5C6DA005002A5"
|
||||
BuildableName = "CoreStoreTests.xctest"
|
||||
BlueprintName = "CoreStoreTests iOS"
|
||||
ReferencedContainer = "container:CoreStore.xcodeproj">
|
||||
</BuildableReference>
|
||||
</TestableReference>
|
||||
</Testables>
|
||||
</TestAction>
|
||||
<LaunchAction
|
||||
buildConfiguration = "Debug"
|
||||
@@ -95,8 +95,6 @@
|
||||
isEnabled = "NO">
|
||||
</CommandLineArgument>
|
||||
</CommandLineArguments>
|
||||
<AdditionalOptions>
|
||||
</AdditionalOptions>
|
||||
</LaunchAction>
|
||||
<ProfileAction
|
||||
buildConfiguration = "Release"
|
||||
|
||||
@@ -27,6 +27,15 @@
|
||||
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
|
||||
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
|
||||
shouldUseLaunchSchemeArgsEnv = "YES">
|
||||
<MacroExpansion>
|
||||
<BuildableReference
|
||||
BuildableIdentifier = "primary"
|
||||
BlueprintIdentifier = "82BA18881C4BBCBA00A0916E"
|
||||
BuildableName = "CoreStore.framework"
|
||||
BlueprintName = "CoreStore tvOS"
|
||||
ReferencedContainer = "container:CoreStore.xcodeproj">
|
||||
</BuildableReference>
|
||||
</MacroExpansion>
|
||||
<Testables>
|
||||
<TestableReference
|
||||
skipped = "NO">
|
||||
@@ -39,17 +48,6 @@
|
||||
</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"
|
||||
@@ -70,8 +68,6 @@
|
||||
ReferencedContainer = "container:CoreStore.xcodeproj">
|
||||
</BuildableReference>
|
||||
</MacroExpansion>
|
||||
<AdditionalOptions>
|
||||
</AdditionalOptions>
|
||||
</LaunchAction>
|
||||
<ProfileAction
|
||||
buildConfiguration = "Release"
|
||||
|
||||
@@ -29,8 +29,6 @@
|
||||
shouldUseLaunchSchemeArgsEnv = "YES">
|
||||
<Testables>
|
||||
</Testables>
|
||||
<AdditionalOptions>
|
||||
</AdditionalOptions>
|
||||
</TestAction>
|
||||
<LaunchAction
|
||||
buildConfiguration = "Debug"
|
||||
@@ -51,8 +49,6 @@
|
||||
ReferencedContainer = "container:CoreStore.xcodeproj">
|
||||
</BuildableReference>
|
||||
</MacroExpansion>
|
||||
<AdditionalOptions>
|
||||
</AdditionalOptions>
|
||||
</LaunchAction>
|
||||
<ProfileAction
|
||||
buildConfiguration = "Release"
|
||||
|
||||
@@ -7,6 +7,9 @@
|
||||
objects = {
|
||||
|
||||
/* Begin PBXBuildFile section */
|
||||
B50132242344E24300FC238B /* SwiftUIView.swift in Sources */ = {isa = PBXBuildFile; fileRef = B50132232344E24300FC238B /* SwiftUIView.swift */; };
|
||||
B50132282344E5E900FC238B /* SwiftUIContainerViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = B50132272344E5E900FC238B /* SwiftUIContainerViewController.swift */; };
|
||||
B501323523477D2300FC238B /* SwiftUI.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = B501323423477D2300FC238B /* SwiftUI.framework */; settings = {ATTRIBUTES = (Weak, ); }; };
|
||||
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 */; };
|
||||
@@ -23,6 +26,8 @@
|
||||
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 */; };
|
||||
B5635D192357F9F700B80E6B /* CollectionViewDemoViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = B5635D182357F9F700B80E6B /* CollectionViewDemoViewController.swift */; };
|
||||
B5635D1B2357FA4B00B80E6B /* PaletteCollectionViewCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = B5635D1A2357FA4B00B80E6B /* PaletteCollectionViewCell.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 */; };
|
||||
@@ -34,6 +39,8 @@
|
||||
B569651A1B30888A0075EE4A /* FetchingResultsViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = B56965191B30888A0075EE4A /* FetchingResultsViewController.swift */; };
|
||||
B569651C1B30889A0075EE4A /* QueryingResultsViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = B569651B1B30889A0075EE4A /* QueryingResultsViewController.swift */; };
|
||||
B56965291B3582D30075EE4A /* MigrationDemo.xcdatamodeld in Sources */ = {isa = PBXBuildFile; fileRef = B56965271B3582D30075EE4A /* MigrationDemo.xcdatamodeld */; };
|
||||
B5AA37EF2357D30300FFD4B9 /* ColorsDemo.swift in Sources */ = {isa = PBXBuildFile; fileRef = B5AA37EE2357D30300FFD4B9 /* ColorsDemo.swift */; };
|
||||
B5C37EE52357FEBE0035A20D /* PaletteCollectionSectionHeaderView.swift in Sources */ = {isa = PBXBuildFile; fileRef = B5C37EE42357FEBE0035A20D /* PaletteCollectionSectionHeaderView.swift */; };
|
||||
B5E599321B5240F50084BD5F /* OrganismTableViewCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = B5E599311B5240F50084BD5F /* OrganismTableViewCell.swift */; };
|
||||
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, ); }; };
|
||||
@@ -59,6 +66,9 @@
|
||||
/* End PBXCopyFilesBuildPhase section */
|
||||
|
||||
/* Begin PBXFileReference section */
|
||||
B50132232344E24300FC238B /* SwiftUIView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SwiftUIView.swift; sourceTree = "<group>"; };
|
||||
B50132272344E5E900FC238B /* SwiftUIContainerViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SwiftUIContainerViewController.swift; sourceTree = "<group>"; };
|
||||
B501323423477D2300FC238B /* SwiftUI.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = SwiftUI.framework; path = System/Library/Frameworks/SwiftUI.framework; sourceTree = SDKROOT; };
|
||||
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>"; };
|
||||
@@ -78,6 +88,8 @@
|
||||
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>"; };
|
||||
B5635D182357F9F700B80E6B /* CollectionViewDemoViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CollectionViewDemoViewController.swift; sourceTree = "<group>"; };
|
||||
B5635D1A2357FA4B00B80E6B /* PaletteCollectionViewCell.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PaletteCollectionViewCell.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>"; };
|
||||
@@ -89,7 +101,9 @@
|
||||
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>"; };
|
||||
B56965281B3582D30075EE4A /* MigrationDemo.xcdatamodel */ = {isa = PBXFileReference; lastKnownFileType = wrapper.xcdatamodel; path = MigrationDemo.xcdatamodel; sourceTree = "<group>"; };
|
||||
B5AA37EE2357D30300FFD4B9 /* ColorsDemo.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ColorsDemo.swift; sourceTree = "<group>"; };
|
||||
B5BDC9211C202429008147CD /* CoreStore.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; path = CoreStore.framework; sourceTree = BUILT_PRODUCTS_DIR; };
|
||||
B5C37EE42357FEBE0035A20D /* PaletteCollectionSectionHeaderView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PaletteCollectionSectionHeaderView.swift; sourceTree = "<group>"; };
|
||||
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>"; };
|
||||
@@ -105,6 +119,7 @@
|
||||
isa = PBXFrameworksBuildPhase;
|
||||
buildActionMask = 2147483647;
|
||||
files = (
|
||||
B501323523477D2300FC238B /* SwiftUI.framework in Frameworks */,
|
||||
B5E89AD01C5292A2003B04A9 /* CoreStore.framework in Frameworks */,
|
||||
B52977E11B120F8A003D50A5 /* CoreLocation.framework in Frameworks */,
|
||||
B52977DF1B120F83003D50A5 /* MapKit.framework in Frameworks */,
|
||||
@@ -114,14 +129,27 @@
|
||||
/* End PBXFrameworksBuildPhase section */
|
||||
|
||||
/* Begin PBXGroup section */
|
||||
B50132222344E20B00FC238B /* SwiftUI Demo */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
B50132232344E24300FC238B /* SwiftUIView.swift */,
|
||||
B50132272344E5E900FC238B /* SwiftUIContainerViewController.swift */,
|
||||
);
|
||||
path = "SwiftUI Demo";
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
B503FADA1AFDC71700F90881 /* List and Object Observers Demo */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
B5AA37EE2357D30300FFD4B9 /* ColorsDemo.swift */,
|
||||
B52977D81B120B80003D50A5 /* ObserversViewController.swift */,
|
||||
B503FADB1AFDC71700F90881 /* ListObserverDemoViewController.swift */,
|
||||
B5635D182357F9F700B80E6B /* CollectionViewDemoViewController.swift */,
|
||||
B503FADC1AFDC71700F90881 /* ObjectObserverDemoViewController.swift */,
|
||||
B503FADD1AFDC71700F90881 /* Palette.swift */,
|
||||
B503FADE1AFDC71700F90881 /* PaletteTableViewCell.swift */,
|
||||
B5635D1A2357FA4B00B80E6B /* PaletteCollectionViewCell.swift */,
|
||||
B5C37EE42357FEBE0035A20D /* PaletteCollectionSectionHeaderView.swift */,
|
||||
);
|
||||
path = "List and Object Observers Demo";
|
||||
sourceTree = "<group>";
|
||||
@@ -138,6 +166,7 @@
|
||||
B52977E21B120F90003D50A5 /* Frameworks */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
B501323423477D2300FC238B /* SwiftUI.framework */,
|
||||
B52977E01B120F8A003D50A5 /* CoreLocation.framework */,
|
||||
B5BDC9211C202429008147CD /* CoreStore.framework */,
|
||||
B52977DE1B120F83003D50A5 /* MapKit.framework */,
|
||||
@@ -166,6 +195,7 @@
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
B54AAD4E1AF4D26E00848AE0 /* AppDelegate.swift */,
|
||||
B50132222344E20B00FC238B /* SwiftUI Demo */,
|
||||
B566E3271B117AE700F4F0C6 /* Stack Setup Demo */,
|
||||
B503FADA1AFDC71700F90881 /* List and Object Observers Demo */,
|
||||
B52977DB1B120F2C003D50A5 /* Transactions Demo */,
|
||||
@@ -270,6 +300,7 @@
|
||||
TargetAttributes = {
|
||||
B54AAD481AF4D26E00848AE0 = {
|
||||
CreatedOnToolsVersion = 6.3;
|
||||
DevelopmentTeam = 2JT32EJ5BH;
|
||||
LastSwiftMigration = 0900;
|
||||
};
|
||||
};
|
||||
@@ -311,6 +342,7 @@
|
||||
buildActionMask = 2147483647;
|
||||
files = (
|
||||
B56965181B2E20CC0075EE4A /* TimeZone.swift in Sources */,
|
||||
B5C37EE52357FEBE0035A20D /* PaletteCollectionSectionHeaderView.swift in Sources */,
|
||||
B56965291B3582D30075EE4A /* MigrationDemo.xcdatamodeld in Sources */,
|
||||
B5E599321B5240F50084BD5F /* OrganismTableViewCell.swift in Sources */,
|
||||
B5EE25851B36E23C0000406B /* OrganismV1.swift in Sources */,
|
||||
@@ -322,6 +354,7 @@
|
||||
B503FAE01AFDC71700F90881 /* ObjectObserverDemoViewController.swift in Sources */,
|
||||
B52977D91B120B80003D50A5 /* ObserversViewController.swift in Sources */,
|
||||
B56964C91B20AC780075EE4A /* CustomLoggerViewController.swift in Sources */,
|
||||
B5635D192357F9F700B80E6B /* CollectionViewDemoViewController.swift in Sources */,
|
||||
B566E32A1B117B1F00F4F0C6 /* StackSetupDemoViewController.swift in Sources */,
|
||||
B56964DA1B231BCA0075EE4A /* MaleAccount.swift in Sources */,
|
||||
B566E3321B11DF3200F4F0C6 /* UserAccount.swift in Sources */,
|
||||
@@ -332,10 +365,14 @@
|
||||
B560070F1B3EC90F00A9A8F9 /* OrganismV2ToV3MigrationPolicy.swift in Sources */,
|
||||
B503FADF1AFDC71700F90881 /* ListObserverDemoViewController.swift in Sources */,
|
||||
B54AAD4F1AF4D26E00848AE0 /* AppDelegate.swift in Sources */,
|
||||
B50132282344E5E900FC238B /* SwiftUIContainerViewController.swift in Sources */,
|
||||
B5635D1B2357FA4B00B80E6B /* PaletteCollectionViewCell.swift in Sources */,
|
||||
B56964D71B231AE90075EE4A /* StackSetupDemo.xcdatamodeld in Sources */,
|
||||
B56964DC1B231BCB0075EE4A /* FemaleAccount.swift in Sources */,
|
||||
B5AA37EF2357D30300FFD4B9 /* ColorsDemo.swift in Sources */,
|
||||
B5EE259E1B3EC1B20000406B /* OrganismProtocol.swift in Sources */,
|
||||
B5EE258C1B36E40D0000406B /* MigrationsDemoViewController.swift in Sources */,
|
||||
B50132242344E24300FC238B /* SwiftUIView.swift in Sources */,
|
||||
B569651C1B30889A0075EE4A /* QueryingResultsViewController.swift in Sources */,
|
||||
B5125C121B521B78003A42C7 /* OrganismV2ToV3.xcmappingmodel in Sources */,
|
||||
);
|
||||
@@ -473,6 +510,7 @@
|
||||
isa = XCBuildConfiguration;
|
||||
buildSettings = {
|
||||
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
|
||||
DEVELOPMENT_TEAM = 2JT32EJ5BH;
|
||||
INFOPLIST_FILE = CoreStoreDemo/Info.plist;
|
||||
LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks";
|
||||
PRODUCT_BUNDLE_IDENTIFIER = com.johnestropia.corestore.demo;
|
||||
@@ -485,6 +523,7 @@
|
||||
isa = XCBuildConfiguration;
|
||||
buildSettings = {
|
||||
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
|
||||
DEVELOPMENT_TEAM = 2JT32EJ5BH;
|
||||
INFOPLIST_FILE = CoreStoreDemo/Info.plist;
|
||||
LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks";
|
||||
PRODUCT_BUNDLE_IDENTIFIER = com.johnestropia.corestore.demo;
|
||||
|
||||
@@ -27,8 +27,6 @@
|
||||
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
|
||||
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
|
||||
shouldUseLaunchSchemeArgsEnv = "YES">
|
||||
<Testables>
|
||||
</Testables>
|
||||
<MacroExpansion>
|
||||
<BuildableReference
|
||||
BuildableIdentifier = "primary"
|
||||
@@ -38,8 +36,8 @@
|
||||
ReferencedContainer = "container:CoreStoreDemo.xcodeproj">
|
||||
</BuildableReference>
|
||||
</MacroExpansion>
|
||||
<AdditionalOptions>
|
||||
</AdditionalOptions>
|
||||
<Testables>
|
||||
</Testables>
|
||||
</TestAction>
|
||||
<LaunchAction
|
||||
buildConfiguration = "Debug"
|
||||
@@ -61,8 +59,6 @@
|
||||
ReferencedContainer = "container:CoreStoreDemo.xcodeproj">
|
||||
</BuildableReference>
|
||||
</BuildableProductRunnable>
|
||||
<AdditionalOptions>
|
||||
</AdditionalOptions>
|
||||
</LaunchAction>
|
||||
<ProfileAction
|
||||
buildConfiguration = "Release"
|
||||
|
||||
@@ -1,11 +1,10 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<document type="com.apple.InterfaceBuilder3.CocoaTouch.Storyboard.XIB" version="3.0" toolsVersion="14460.31" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" useTraitCollections="YES" colorMatched="YES" initialViewController="Ni8-QF-XHB">
|
||||
<device id="retina4_7" orientation="portrait">
|
||||
<adaptation id="fullscreen"/>
|
||||
</device>
|
||||
<document type="com.apple.InterfaceBuilder3.CocoaTouch.Storyboard.XIB" version="3.0" toolsVersion="15400" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" useTraitCollections="YES" colorMatched="YES" initialViewController="Ni8-QF-XHB">
|
||||
<device id="retina4_7" orientation="portrait" appearance="light"/>
|
||||
<dependencies>
|
||||
<deployment identifier="iOS"/>
|
||||
<plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="14460.20"/>
|
||||
<plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="15404"/>
|
||||
<capability name="collection view cell content view" minToolsVersion="11.0"/>
|
||||
<capability name="documents saved in the Xcode 8 format" minToolsVersion="8.0"/>
|
||||
</dependencies>
|
||||
<customFonts key="customFonts">
|
||||
@@ -68,10 +67,10 @@
|
||||
</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="172" width="375" height="44"/>
|
||||
<rect key="frame" x="0.0" y="178" width="375" 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="375" height="43.5"/>
|
||||
<rect key="frame" x="0.0" y="0.0" width="375" height="44"/>
|
||||
<autoresizingMask key="autoresizingMask"/>
|
||||
<subviews>
|
||||
<label opaque="NO" multipleTouchEnabled="YES" contentMode="left" text="Title" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" id="8b8-lM-Krq">
|
||||
@@ -121,15 +120,15 @@
|
||||
<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="375" height="343"/>
|
||||
<rect key="frame" x="0.0" y="304" width="375" height="363"/>
|
||||
<color key="backgroundColor" red="0.93725490196078431" green="0.93725490196078431" blue="0.95686274509803926" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
|
||||
<color key="separatorColor" red="0.15542715787887573" green="0.2203737199306488" blue="0.2959403395652771" 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="375" height="44"/>
|
||||
<rect key="frame" x="0.0" y="28" width="375" 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="375" height="43.5"/>
|
||||
<rect key="frame" x="0.0" y="0.0" width="375" height="44"/>
|
||||
<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">
|
||||
@@ -170,25 +169,25 @@
|
||||
</connections>
|
||||
</tableView>
|
||||
<view contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="XKA-Ub-c2X">
|
||||
<rect key="frame" x="0.0" y="64" width="375" height="260"/>
|
||||
<rect key="frame" x="0.0" y="44" width="375" height="260"/>
|
||||
<subviews>
|
||||
<view contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="i7U-bW-juB" customClass="UIButton">
|
||||
<rect key="frame" x="0.0" y="0.0" width="375" 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="335" height="26.5"/>
|
||||
<rect key="frame" x="20" y="93.5" width="335" height="26.5"/>
|
||||
<fontDescription key="fontDescription" name="HelveticaNeue-Bold" family="Helvetica Neue" pointSize="22"/>
|
||||
<color key="textColor" red="0.90744441747665405" green="0.9265514612197876" blue="0.93116652965545654" 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="335" height="20.5"/>
|
||||
<rect key="frame" x="20" y="134.5" width="335" height="20.5"/>
|
||||
<fontDescription key="fontDescription" name="HelveticaNeue-Light" family="Helvetica Neue" pointSize="17"/>
|
||||
<color key="textColor" red="0.90744441747665405" green="0.9265514612197876" blue="0.93116652965545654" 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="335" height="29"/>
|
||||
<rect key="frame" x="20" y="20" width="335" height="32"/>
|
||||
<segments>
|
||||
<segment title="First"/>
|
||||
<segment title="Second"/>
|
||||
@@ -200,7 +199,7 @@
|
||||
</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="335" height="2"/>
|
||||
<rect key="frame" x="20" y="71" width="335" height="2"/>
|
||||
<color key="progressTintColor" red="1" green="1" blue="1" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
|
||||
<color key="trackTintColor" red="1" green="1" blue="1" alpha="0.20000000000000001" colorSpace="custom" customColorSpace="sRGB"/>
|
||||
</progressView>
|
||||
@@ -269,21 +268,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="35" width="375" height="50"/>
|
||||
<rect key="frame" x="0.0" y="10" width="375" 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="341" height="49.5"/>
|
||||
<rect key="frame" x="0.0" y="0.0" width="348" height="50"/>
|
||||
<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="16" y="6" width="82" height="24"/>
|
||||
<rect key="frame" x="16" y="7" 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.13079629838466644" green="0.184075728058815" blue="0.24594299495220184" 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="16" y="30" width="263.5" height="13.5"/>
|
||||
<rect key="frame" x="16" y="31" 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.13079629838466644" green="0.184075728058815" blue="0.24594299495220184" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
|
||||
@@ -296,21 +295,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="85" width="375" height="50"/>
|
||||
<rect key="frame" x="0.0" y="60" width="375" 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="341" height="49.5"/>
|
||||
<rect key="frame" x="0.0" y="0.0" width="348" height="50"/>
|
||||
<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="16" y="6" width="56" height="24"/>
|
||||
<rect key="frame" x="16" y="7" 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.13079629838466644" green="0.184075728058815" blue="0.24594299495220184" 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="16" y="30" width="260.5" height="13.5"/>
|
||||
<rect key="frame" x="16" y="31" 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.13079629838466644" green="0.184075728058815" blue="0.24594299495220184" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
|
||||
@@ -323,21 +322,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="135" width="375" height="50"/>
|
||||
<rect key="frame" x="0.0" y="110" width="375" 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="341" height="49.5"/>
|
||||
<rect key="frame" x="0.0" y="0.0" width="348" height="50"/>
|
||||
<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="16" y="6" width="100.5" height="24"/>
|
||||
<rect key="frame" x="16" y="7" 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.13079629838466644" green="0.184075728058815" blue="0.24594299495220184" 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="16" y="30" width="179" height="13.5"/>
|
||||
<rect key="frame" x="16" y="31" width="179" height="13.5"/>
|
||||
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMaxY="YES"/>
|
||||
<fontDescription key="fontDescription" type="system" pointSize="11"/>
|
||||
<color key="textColor" red="0.13079629838466644" green="0.184075728058815" blue="0.24594299495220184" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
|
||||
@@ -350,21 +349,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="185" width="375" height="50"/>
|
||||
<rect key="frame" x="0.0" y="160" width="375" 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="341" height="49.5"/>
|
||||
<rect key="frame" x="0.0" y="0.0" width="348" height="50"/>
|
||||
<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="16" y="6" width="101.5" height="24"/>
|
||||
<rect key="frame" x="16" y="7" 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.13079629838466644" green="0.184075728058815" blue="0.24594299495220184" 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="16" y="30" width="168.5" height="13.5"/>
|
||||
<rect key="frame" x="16" y="31" 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.13079629838466644" green="0.184075728058815" blue="0.24594299495220184" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
|
||||
@@ -377,21 +376,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="235" width="375" height="50"/>
|
||||
<rect key="frame" x="0.0" y="210" width="375" 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="341" height="49.5"/>
|
||||
<rect key="frame" x="0.0" y="0.0" width="348" height="50"/>
|
||||
<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="16" y="6" width="61" height="24"/>
|
||||
<rect key="frame" x="16" y="7" 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.13079629838466644" green="0.184075728058815" blue="0.24594299495220184" 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="16" y="30" width="159" height="13.5"/>
|
||||
<rect key="frame" x="16" y="31" width="159" height="13.5"/>
|
||||
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMaxY="YES"/>
|
||||
<fontDescription key="fontDescription" type="system" pointSize="11"/>
|
||||
<color key="textColor" red="0.13079629838466644" green="0.184075728058815" blue="0.24594299495220184" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
|
||||
@@ -404,21 +403,21 @@
|
||||
</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="285" width="375" height="50"/>
|
||||
<rect key="frame" x="0.0" y="260" width="375" 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="341" height="49.5"/>
|
||||
<rect key="frame" x="0.0" y="0.0" width="348" height="50"/>
|
||||
<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="16" y="6" width="78.5" height="24"/>
|
||||
<rect key="frame" x="16" y="7" 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.13079629838466644" green="0.184075728058815" blue="0.24594299495220184" 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="16" y="30" width="179.5" height="13.5"/>
|
||||
<rect key="frame" x="16" y="31" 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.13079629838466644" green="0.184075728058815" blue="0.24594299495220184" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
|
||||
@@ -430,6 +429,33 @@
|
||||
<segue destination="iVv-Vc-nCL" kind="show" id="HbO-rU-Qfj"/>
|
||||
</connections>
|
||||
</tableViewCell>
|
||||
<tableViewCell contentMode="scaleToFill" selectionStyle="default" accessoryType="disclosureIndicator" indentationWidth="10" textLabel="o2r-2N-Xda" detailTextLabel="2hh-MM-Oea" style="IBUITableViewCellStyleSubtitle" id="f25-dJ-AuT">
|
||||
<rect key="frame" x="0.0" y="310" width="375" height="50"/>
|
||||
<autoresizingMask key="autoresizingMask"/>
|
||||
<tableViewCellContentView key="contentView" opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center" tableViewCell="f25-dJ-AuT" id="86t-0w-JT9">
|
||||
<rect key="frame" x="0.0" y="0.0" width="348" height="50"/>
|
||||
<autoresizingMask key="autoresizingMask"/>
|
||||
<subviews>
|
||||
<label opaque="NO" multipleTouchEnabled="YES" contentMode="left" text="SwiftUI" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" id="o2r-2N-Xda">
|
||||
<rect key="frame" x="16" y="7" width="60.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.13079629840000001" green="0.1840757281" blue="0.245942995" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
|
||||
<nil key="highlightedColor"/>
|
||||
</label>
|
||||
<label opaque="NO" multipleTouchEnabled="YES" contentMode="left" text="Binding with SwiftUI and Combine" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" id="2hh-MM-Oea">
|
||||
<rect key="frame" x="16" y="31" width="178" height="13.5"/>
|
||||
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMaxY="YES"/>
|
||||
<fontDescription key="fontDescription" type="system" pointSize="11"/>
|
||||
<color key="textColor" red="0.13079629840000001" green="0.1840757281" blue="0.245942995" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
|
||||
<nil key="highlightedColor"/>
|
||||
</label>
|
||||
</subviews>
|
||||
</tableViewCellContentView>
|
||||
<connections>
|
||||
<segue destination="rhi-tx-cSW" kind="show" id="kb3-NX-Aao"/>
|
||||
</connections>
|
||||
</tableViewCell>
|
||||
</cells>
|
||||
</tableViewSection>
|
||||
</sections>
|
||||
@@ -444,6 +470,38 @@
|
||||
</objects>
|
||||
<point key="canvasLocation" x="2634" y="2013"/>
|
||||
</scene>
|
||||
<!--SwiftUI-->
|
||||
<scene sceneID="Uiz-5a-tKq">
|
||||
<objects>
|
||||
<viewController id="rhi-tx-cSW" customClass="SwiftUIContainerViewController" customModule="CoreStoreDemo" customModuleProvider="target" sceneMemberID="viewController">
|
||||
<layoutGuides>
|
||||
<viewControllerLayoutGuide type="top" id="0Nq-lg-kDJ"/>
|
||||
<viewControllerLayoutGuide type="bottom" id="72Q-TT-uXH"/>
|
||||
</layoutGuides>
|
||||
<view key="view" contentMode="scaleToFill" id="JvO-3D-U2t">
|
||||
<rect key="frame" x="0.0" y="0.0" width="375" height="667"/>
|
||||
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
|
||||
<subviews>
|
||||
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" verticalCompressionResistancePriority="250" text="Not supported on this device/OS version" textAlignment="center" lineBreakMode="tailTruncation" numberOfLines="0" baselineAdjustment="alignBaselines" minimumScaleFactor="0.5" adjustsLetterSpacingToFitWidth="YES" translatesAutoresizingMaskIntoConstraints="NO" id="Z0H-X0-3xA">
|
||||
<rect key="frame" x="36" y="274.5" width="303" height="118.5"/>
|
||||
<fontDescription key="fontDescription" name="HelveticaNeue-Bold" family="Helvetica Neue" pointSize="33"/>
|
||||
<color key="textColor" white="0.66666666666666663" alpha="1" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
|
||||
<nil key="highlightedColor"/>
|
||||
</label>
|
||||
</subviews>
|
||||
<color key="backgroundColor" systemColor="systemBackgroundColor" cocoaTouchSystemColor="whiteColor"/>
|
||||
<constraints>
|
||||
<constraint firstItem="Z0H-X0-3xA" firstAttribute="centerY" secondItem="JvO-3D-U2t" secondAttribute="centerY" id="8Hp-yB-ciV"/>
|
||||
<constraint firstItem="Z0H-X0-3xA" firstAttribute="leading" secondItem="JvO-3D-U2t" secondAttribute="leadingMargin" constant="20" id="l7i-J0-oG5"/>
|
||||
<constraint firstAttribute="trailingMargin" secondItem="Z0H-X0-3xA" secondAttribute="trailing" constant="20" id="mrq-pp-Q06"/>
|
||||
</constraints>
|
||||
</view>
|
||||
<navigationItem key="navigationItem" title="SwiftUI" id="gFf-uX-EUI"/>
|
||||
</viewController>
|
||||
<placeholder placeholderIdentifier="IBFirstResponder" id="HSp-lA-NAM" userLabel="First Responder" customClass="UIResponder" sceneMemberID="firstResponder"/>
|
||||
</objects>
|
||||
<point key="canvasLocation" x="3694" y="4816"/>
|
||||
</scene>
|
||||
<!--Object Observer-->
|
||||
<scene sceneID="Y7v-tc-8cX">
|
||||
<objects>
|
||||
@@ -453,18 +511,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="375" height="301.5"/>
|
||||
<rect key="frame" x="0.0" y="0.0" width="375" height="311.5"/>
|
||||
<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="69.5" width="343" height="70"/>
|
||||
<rect key="frame" x="16" y="69.5" width="343" height="80"/>
|
||||
<color key="backgroundColor" red="1" green="1" blue="1" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
|
||||
<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="149.5" width="343" height="18"/>
|
||||
<rect key="frame" x="16" y="159.5" width="343" height="18"/>
|
||||
<constraints>
|
||||
<constraint firstAttribute="height" relation="greaterThanOrEqual" id="4h9-ha-EzR"/>
|
||||
</constraints>
|
||||
@@ -473,37 +531,37 @@
|
||||
<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="187.5" width="74" height="18"/>
|
||||
<rect key="frame" x="16" y="197.5" 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="custom" customColorSpace="sRGB"/>
|
||||
<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="225.5" width="74" height="18"/>
|
||||
<rect key="frame" x="16" y="235.5" 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="custom" customColorSpace="sRGB"/>
|
||||
<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="263.5" width="74" height="18"/>
|
||||
<rect key="frame" x="16" y="273.5" 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="custom" customColorSpace="sRGB"/>
|
||||
<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="181.5" width="263" height="31"/>
|
||||
<rect key="frame" x="98" y="191.5" width="263" 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="219.5" width="263" height="31"/>
|
||||
<rect key="frame" x="98" y="229.5" width="263" 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="257.5" width="263" height="31"/>
|
||||
<rect key="frame" x="98" y="267.5" width="263" height="31"/>
|
||||
<connections>
|
||||
<action selector="brightnessSliderValueDidChange:" destination="dX3-kR-CYC" eventType="valueChanged" id="F09-EP-2iD"/>
|
||||
</connections>
|
||||
@@ -566,7 +624,7 @@
|
||||
</viewController>
|
||||
<placeholder placeholderIdentifier="IBFirstResponder" id="49t-Sy-Rq7" userLabel="First Responder" sceneMemberID="firstResponder"/>
|
||||
</objects>
|
||||
<point key="canvasLocation" x="5864" y="1324.5"/>
|
||||
<point key="canvasLocation" x="6316" y="1267"/>
|
||||
</scene>
|
||||
<!--Colors-->
|
||||
<scene sceneID="3lD-lX-hIc">
|
||||
@@ -580,34 +638,55 @@
|
||||
<rect key="frame" x="0.0" y="0.0" width="375" height="667"/>
|
||||
<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="375" height="301.5"/>
|
||||
<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="365.5" width="375" height="301.5"/>
|
||||
<connections>
|
||||
<segue destination="sll-yo-mBc" kind="embed" id="AAl-HS-dq2"/>
|
||||
</connections>
|
||||
</containerView>
|
||||
<stackView opaque="NO" contentMode="scaleToFill" axis="vertical" distribution="fillEqually" translatesAutoresizingMaskIntoConstraints="NO" id="cce-yT-4dn">
|
||||
<rect key="frame" x="0.0" y="44" width="375" height="623"/>
|
||||
<subviews>
|
||||
<containerView opaque="NO" contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="L5f-tW-lXf">
|
||||
<rect key="frame" x="0.0" y="0.0" width="375" height="311.5"/>
|
||||
<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="311.5" width="375" height="311.5"/>
|
||||
<connections>
|
||||
<segue destination="Rdw-NU-NaK" kind="embed" id="3Ob-Bj-yvz"/>
|
||||
</connections>
|
||||
</containerView>
|
||||
</subviews>
|
||||
</stackView>
|
||||
</subviews>
|
||||
<color key="backgroundColor" red="1" green="1" blue="1" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
|
||||
<constraints>
|
||||
<constraint firstItem="6So-f3-4Gp" firstAttribute="top" secondItem="L5f-tW-lXf" secondAttribute="bottom" id="3m8-tj-Nd4"/>
|
||||
<constraint firstAttribute="trailingMargin" secondItem="6So-f3-4Gp" secondAttribute="trailing" constant="-16" id="4L8-wZ-F59"/>
|
||||
<constraint firstItem="L5f-tW-lXf" firstAttribute="height" secondItem="6So-f3-4Gp" secondAttribute="height" id="8XS-L3-hvN"/>
|
||||
<constraint firstItem="LNL-mj-D7l" firstAttribute="top" secondItem="6So-f3-4Gp" secondAttribute="bottom" id="8wL-zm-wnt"/>
|
||||
<constraint firstItem="L5f-tW-lXf" firstAttribute="leading" secondItem="6x3-vn-Egt" secondAttribute="leadingMargin" constant="-16" id="CbE-2f-7wk"/>
|
||||
<constraint firstAttribute="trailingMargin" secondItem="L5f-tW-lXf" secondAttribute="trailing" constant="-16" id="dso-2g-fgA"/>
|
||||
<constraint firstItem="6So-f3-4Gp" firstAttribute="leading" secondItem="6x3-vn-Egt" secondAttribute="leadingMargin" constant="-16" id="eXM-D3-NLv"/>
|
||||
<constraint firstItem="L5f-tW-lXf" firstAttribute="top" secondItem="IML-3o-caw" secondAttribute="bottom" id="zJ5-sE-iJA"/>
|
||||
<constraint firstAttribute="trailing" secondItem="cce-yT-4dn" secondAttribute="trailing" id="DE1-u6-1mr"/>
|
||||
<constraint firstItem="LNL-mj-D7l" firstAttribute="top" secondItem="cce-yT-4dn" secondAttribute="bottom" id="WIZ-M3-bdr"/>
|
||||
<constraint firstItem="cce-yT-4dn" firstAttribute="leading" secondItem="6x3-vn-Egt" secondAttribute="leading" id="ZiS-j0-ANp"/>
|
||||
<constraint firstItem="cce-yT-4dn" firstAttribute="top" secondItem="IML-3o-caw" secondAttribute="bottom" id="zjs-CM-7r5"/>
|
||||
</constraints>
|
||||
</view>
|
||||
<extendedEdge key="edgesForExtendedLayout" top="YES"/>
|
||||
<navigationItem key="navigationItem" title="Colors" id="7Gd-Ad-Bzu"/>
|
||||
<navigationItem key="navigationItem" title="Colors" id="7Gd-Ad-Bzu">
|
||||
<rightBarButtonItems>
|
||||
<barButtonItem title="▼" width="36" id="aPM-OC-EB8">
|
||||
<connections>
|
||||
<action selector="toggleBottomContainerView" destination="YOI-b7-Nxn" id="7fn-z6-pne"/>
|
||||
</connections>
|
||||
</barButtonItem>
|
||||
<barButtonItem title="▲" width="36" id="6q3-Zk-A9p">
|
||||
<connections>
|
||||
<action selector="toggleTopContainerView" destination="YOI-b7-Nxn" id="APN-Kk-C3n"/>
|
||||
</connections>
|
||||
</barButtonItem>
|
||||
</rightBarButtonItems>
|
||||
</navigationItem>
|
||||
<nil key="simulatedBottomBarMetrics"/>
|
||||
<connections>
|
||||
<outlet property="bottomContainerView" destination="6So-f3-4Gp" id="C7O-e2-k0l"/>
|
||||
<outlet property="stackView" destination="cce-yT-4dn" id="r5B-BT-mUM"/>
|
||||
<outlet property="toggleBottomBarButtonItem" destination="aPM-OC-EB8" id="kEV-gg-XOX"/>
|
||||
<outlet property="toggleTopBarButtonItem" destination="6q3-Zk-A9p" id="usC-Zu-DQm"/>
|
||||
<outlet property="topContainerView" destination="L5f-tW-lXf" id="DRV-mm-rBY"/>
|
||||
</connections>
|
||||
</viewController>
|
||||
<placeholder placeholderIdentifier="IBFirstResponder" id="C9h-Ba-WoL" userLabel="First Responder" sceneMemberID="firstResponder"/>
|
||||
</objects>
|
||||
@@ -620,7 +699,7 @@
|
||||
<tabBarItem key="tabBarItem" title="Demo" image="second" id="3iQ-I2-4LW"/>
|
||||
<toolbarItems/>
|
||||
<navigationBar key="navigationBar" contentMode="scaleToFill" id="00L-5k-Eno">
|
||||
<rect key="frame" x="0.0" y="20" width="375" height="44"/>
|
||||
<rect key="frame" x="0.0" y="0.0" width="375" height="44"/>
|
||||
<autoresizingMask key="autoresizingMask"/>
|
||||
<color key="tintColor" red="0.90744441747665405" green="0.9265514612197876" blue="0.93116652965545654" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
|
||||
<color key="barTintColor" red="0.15542715787887573" green="0.2203737199306488" blue="0.2959403395652771" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
|
||||
@@ -638,19 +717,19 @@
|
||||
</objects>
|
||||
<point key="canvasLocation" x="1822" y="2013"/>
|
||||
</scene>
|
||||
<!--List Observer-->
|
||||
<!--ListPublisher-->
|
||||
<scene sceneID="gkX-bd-Rel">
|
||||
<objects>
|
||||
<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="375" height="301.5"/>
|
||||
<rect key="frame" x="0.0" y="0.0" width="375" height="311.5"/>
|
||||
<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="22" width="375" height="44"/>
|
||||
<rect key="frame" x="0.0" y="28" width="375" 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="341" height="43.5"/>
|
||||
<rect key="frame" x="0.0" y="0.0" width="348" height="44"/>
|
||||
<autoresizingMask key="autoresizingMask"/>
|
||||
<subviews>
|
||||
<view contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="uQX-PI-UWF">
|
||||
@@ -668,6 +747,7 @@
|
||||
</label>
|
||||
</subviews>
|
||||
<constraints>
|
||||
<constraint firstAttribute="trailing" relation="greaterThanOrEqual" secondItem="HJC-5w-lIN" secondAttribute="trailing" id="8FZ-9e-AdN"/>
|
||||
<constraint firstItem="HJC-5w-lIN" firstAttribute="height" secondItem="uQX-PI-UWF" secondAttribute="height" id="8Py-Ub-gQD"/>
|
||||
<constraint firstItem="uQX-PI-UWF" firstAttribute="top" secondItem="aT8-nz-i5l" secondAttribute="topMargin" id="9e4-wD-lwf"/>
|
||||
<constraint firstAttribute="centerY" secondItem="HJC-5w-lIN" secondAttribute="centerY" id="AeC-j4-DBE"/>
|
||||
@@ -688,99 +768,14 @@
|
||||
</connections>
|
||||
</tableView>
|
||||
<extendedEdge key="edgesForExtendedLayout" top="YES"/>
|
||||
<navigationItem key="navigationItem" title="List Observer" id="JjF-x3-ixG"/>
|
||||
<navigationItem key="navigationItem" title="ListPublisher" id="5kj-jr-HoL"/>
|
||||
<connections>
|
||||
<segue destination="dX3-kR-CYC" kind="show" identifier="ObjectObserverDemoViewController" id="hyN-De-zte"/>
|
||||
</connections>
|
||||
</tableViewController>
|
||||
<placeholder placeholderIdentifier="IBFirstResponder" id="P5L-49-pOr" userLabel="First Responder" sceneMemberID="firstResponder"/>
|
||||
</objects>
|
||||
<point key="canvasLocation" x="5085" y="1144.5"/>
|
||||
</scene>
|
||||
<!--List Observer-->
|
||||
<scene sceneID="iDB-TD-It9">
|
||||
<objects>
|
||||
<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="375" height="301.5"/>
|
||||
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
|
||||
<color key="backgroundColor" red="1" green="1" blue="1" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
|
||||
<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="22" width="375" 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="341" height="43.5"/>
|
||||
<autoresizingMask key="autoresizingMask"/>
|
||||
<subviews>
|
||||
<view contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="5uq-Yi-XwH">
|
||||
<rect key="frame" x="16" y="11" width="22" height="22"/>
|
||||
<color key="backgroundColor" red="1" green="1" blue="1" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
|
||||
<constraints>
|
||||
<constraint firstAttribute="width" secondItem="5uq-Yi-XwH" secondAttribute="height" multiplier="1:1" id="oOe-HC-VyN"/>
|
||||
</constraints>
|
||||
</view>
|
||||
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="Label" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="Zyu-PC-WmO">
|
||||
<rect key="frame" x="48" y="11" width="34.5" height="22"/>
|
||||
<fontDescription key="fontDescription" name="HelveticaNeue" family="Helvetica Neue" pointSize="14"/>
|
||||
<color key="textColor" red="0.13079629838466644" green="0.184075728058815" blue="0.24594299495220184" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
|
||||
<nil key="highlightedColor"/>
|
||||
</label>
|
||||
</subviews>
|
||||
<constraints>
|
||||
<constraint firstAttribute="bottomMargin" secondItem="5uq-Yi-XwH" secondAttribute="bottom" id="2Bf-dJ-VmS"/>
|
||||
<constraint firstItem="Zyu-PC-WmO" firstAttribute="leading" secondItem="5uq-Yi-XwH" secondAttribute="trailing" constant="10" id="6uD-S1-gkb"/>
|
||||
<constraint firstAttribute="centerY" secondItem="Zyu-PC-WmO" secondAttribute="centerY" id="KQ6-bN-Og6"/>
|
||||
<constraint firstItem="5uq-Yi-XwH" firstAttribute="top" secondItem="cHA-by-n4b" secondAttribute="topMargin" id="NqW-uA-mqj"/>
|
||||
<constraint firstItem="Zyu-PC-WmO" firstAttribute="height" secondItem="5uq-Yi-XwH" secondAttribute="height" id="Yd5-bt-R8q"/>
|
||||
<constraint firstItem="5uq-Yi-XwH" firstAttribute="leading" secondItem="cHA-by-n4b" secondAttribute="leadingMargin" id="a2a-Ol-0HV"/>
|
||||
</constraints>
|
||||
</tableViewCellContentView>
|
||||
<connections>
|
||||
<outlet property="colorView" destination="5uq-Yi-XwH" id="tgl-W1-A55"/>
|
||||
<outlet property="label" destination="Zyu-PC-WmO" id="Oda-gD-ElI"/>
|
||||
</connections>
|
||||
</tableViewCell>
|
||||
</prototypes>
|
||||
<connections>
|
||||
<outlet property="dataSource" destination="lCE-i6-UCT" id="vTv-9f-P8U"/>
|
||||
<outlet property="delegate" destination="lCE-i6-UCT" id="Ken-sI-O2f"/>
|
||||
</connections>
|
||||
</tableView>
|
||||
<extendedEdge key="edgesForExtendedLayout" top="YES"/>
|
||||
<navigationItem key="navigationItem" title="List Observer" id="koc-aK-cgD"/>
|
||||
<connections>
|
||||
<segue destination="dX3-kR-CYC" kind="show" identifier="ObjectObserverDemoViewController" id="fIB-GS-Ppk"/>
|
||||
</connections>
|
||||
</tableViewController>
|
||||
<placeholder placeholderIdentifier="IBFirstResponder" id="QAS-su-ZdM" userLabel="First Responder" sceneMemberID="firstResponder"/>
|
||||
</objects>
|
||||
<point key="canvasLocation" x="5085" y="1546"/>
|
||||
</scene>
|
||||
<!--Navigation Controller-->
|
||||
<scene sceneID="DTD-lH-nr5">
|
||||
<objects>
|
||||
<navigationController automaticallyAdjustsScrollViewInsets="NO" id="sll-yo-mBc" sceneMemberID="viewController">
|
||||
<extendedEdge key="edgesForExtendedLayout" bottom="YES"/>
|
||||
<toolbarItems/>
|
||||
<navigationBar key="navigationBar" contentMode="scaleToFill" id="6XA-6M-yvZ">
|
||||
<rect key="frame" x="0.0" y="0.0" width="375" height="44"/>
|
||||
<autoresizingMask key="autoresizingMask"/>
|
||||
<color key="tintColor" red="0.68773996829986572" green="0.71417498588562012" blue="0.73246318101882935" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
|
||||
<color key="barTintColor" red="0.13079629838466644" green="0.184075728058815" blue="0.24594299495220184" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
|
||||
<textAttributes key="titleTextAttributes">
|
||||
<fontDescription key="fontDescription" name="HelveticaNeue-Thin" family="Helvetica Neue" pointSize="20"/>
|
||||
<color key="textColor" red="0.68773996829986572" green="0.71417498588562012" blue="0.73246318101882935" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
|
||||
</textAttributes>
|
||||
</navigationBar>
|
||||
<nil name="viewControllers"/>
|
||||
<connections>
|
||||
<segue destination="lCE-i6-UCT" kind="relationship" relationship="rootViewController" id="4Vz-ah-FHX"/>
|
||||
</connections>
|
||||
</navigationController>
|
||||
<placeholder placeholderIdentifier="IBFirstResponder" id="wJg-s1-Dpr" userLabel="First Responder" sceneMemberID="firstResponder"/>
|
||||
</objects>
|
||||
<point key="canvasLocation" x="4404" y="1546"/>
|
||||
<point key="canvasLocation" x="5156" y="1144"/>
|
||||
</scene>
|
||||
<!--Placemarks-->
|
||||
<scene sceneID="LRD-q1-hw1">
|
||||
@@ -791,11 +786,11 @@
|
||||
<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="375" height="603"/>
|
||||
<rect key="frame" x="0.0" y="0.0" width="375" height="623"/>
|
||||
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
|
||||
<subviews>
|
||||
<mapView verifyAmbiguity="ignoreSizes" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="scaleToFill" mapType="standard" translatesAutoresizingMaskIntoConstraints="NO" id="V2U-0R-Ts0">
|
||||
<rect key="frame" x="0.0" y="0.0" width="375" height="603"/>
|
||||
<rect key="frame" x="0.0" y="0.0" width="375" height="623"/>
|
||||
<connections>
|
||||
<outlet property="delegate" destination="jPl-fH-NlD" id="Sjn-YC-haS"/>
|
||||
</connections>
|
||||
@@ -832,14 +827,14 @@
|
||||
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
|
||||
<subviews>
|
||||
<textView clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="scaleToFill" directionalLockEnabled="YES" alwaysBounceVertical="YES" indicatorStyle="white" editable="NO" translatesAutoresizingMaskIntoConstraints="NO" id="TpK-gX-CTN">
|
||||
<rect key="frame" x="0.0" y="142" width="375" height="525"/>
|
||||
<rect key="frame" x="0.0" y="125" width="375" height="542"/>
|
||||
<color key="backgroundColor" red="0.15542715787887573" green="0.2203737199306488" blue="0.2959403395652771" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
|
||||
<color key="textColor" red="0.92706394195556641" green="0.72759377956390381" blue="0.064024783670902252" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
|
||||
<fontDescription key="fontDescription" name="AppleSDGothicNeo-Regular" family="Apple SD Gothic Neo" pointSize="15"/>
|
||||
<textInputTraits key="textInputTraits" autocapitalizationType="sentences"/>
|
||||
</textView>
|
||||
<segmentedControl opaque="NO" contentMode="scaleToFill" contentHorizontalAlignment="left" contentVerticalAlignment="top" segmentControlStyle="bordered" momentary="YES" translatesAutoresizingMaskIntoConstraints="NO" id="4iq-B4-k0p">
|
||||
<rect key="frame" x="20" y="94" width="335" height="29"/>
|
||||
<rect key="frame" x="20" y="74" width="335" height="32"/>
|
||||
<segments>
|
||||
<segment title="Log"/>
|
||||
<segment title="Error"/>
|
||||
@@ -887,8 +882,8 @@
|
||||
<navigationBar key="navigationBar" contentMode="scaleToFill" id="wJo-mp-1pS">
|
||||
<rect key="frame" x="0.0" y="0.0" width="375" height="44"/>
|
||||
<autoresizingMask key="autoresizingMask"/>
|
||||
<color key="tintColor" red="0.68773996829986572" green="0.71417498588562012" blue="0.73246318101882935" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
|
||||
<color key="barTintColor" red="0.13079629838466644" green="0.184075728058815" blue="0.24594299495220184" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
|
||||
<color key="tintColor" red="0.68627450980392157" green="0.71372549019607845" blue="0.73333333333333328" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
|
||||
<color key="barTintColor" red="0.12941176470588234" green="0.18431372549019609" blue="0.24705882352941178" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
|
||||
<textAttributes key="titleTextAttributes">
|
||||
<fontDescription key="fontDescription" name="HelveticaNeue-Thin" family="Helvetica Neue" pointSize="20"/>
|
||||
<color key="textColor" red="0.68773996829986572" green="0.71417498588562012" blue="0.73246318101882935" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
|
||||
@@ -903,6 +898,80 @@
|
||||
</objects>
|
||||
<point key="canvasLocation" x="4404" y="1144.5"/>
|
||||
</scene>
|
||||
<!--ListPublisher-->
|
||||
<scene sceneID="CXQ-vG-dtK">
|
||||
<objects>
|
||||
<collectionViewController id="EKY-1g-ALK" customClass="CollectionViewDemoViewController" customModule="CoreStoreDemo" customModuleProvider="target" sceneMemberID="viewController">
|
||||
<collectionView key="view" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="scaleToFill" dataMode="prototypes" id="hx3-j3-Q80">
|
||||
<rect key="frame" x="0.0" y="0.0" width="375" height="311.5"/>
|
||||
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
|
||||
<color key="backgroundColor" systemColor="systemBackgroundColor" cocoaTouchSystemColor="whiteColor"/>
|
||||
<collectionViewFlowLayout key="collectionViewLayout" automaticEstimatedItemSize="YES" minimumLineSpacing="10" minimumInteritemSpacing="10" id="X6n-f9-yEl">
|
||||
<size key="itemSize" width="50" height="50"/>
|
||||
<size key="headerReferenceSize" width="50" height="50"/>
|
||||
<size key="footerReferenceSize" width="0.0" height="0.0"/>
|
||||
<inset key="sectionInset" minX="0.0" minY="0.0" maxX="0.0" maxY="0.0"/>
|
||||
</collectionViewFlowLayout>
|
||||
<cells>
|
||||
<collectionViewCell opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center" reuseIdentifier="PaletteCollectionViewCell" id="x2U-Yq-KAx" customClass="PaletteCollectionViewCell" customModule="CoreStoreDemo" customModuleProvider="target">
|
||||
<rect key="frame" x="0.0" y="50" width="50" height="50"/>
|
||||
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMaxY="YES"/>
|
||||
<collectionViewCellContentView key="contentView" opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center" insetsLayoutMarginsFromSafeArea="NO" id="Alc-Is-Hc1">
|
||||
<rect key="frame" x="0.0" y="0.0" width="50" height="50"/>
|
||||
<autoresizingMask key="autoresizingMask"/>
|
||||
<subviews>
|
||||
<view contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="NxF-xt-nas">
|
||||
<rect key="frame" x="2" y="2" width="46" height="46"/>
|
||||
<color key="backgroundColor" systemColor="systemBackgroundColor" cocoaTouchSystemColor="whiteColor"/>
|
||||
</view>
|
||||
</subviews>
|
||||
<constraints>
|
||||
<constraint firstItem="NxF-xt-nas" firstAttribute="leading" secondItem="Alc-Is-Hc1" secondAttribute="leading" constant="2" id="Hjb-0k-4HP"/>
|
||||
<constraint firstAttribute="trailing" secondItem="NxF-xt-nas" secondAttribute="trailing" constant="2" id="fKI-q8-bbI"/>
|
||||
<constraint firstItem="NxF-xt-nas" firstAttribute="top" secondItem="Alc-Is-Hc1" secondAttribute="top" constant="2" id="qS6-eD-5T1"/>
|
||||
<constraint firstAttribute="bottom" secondItem="NxF-xt-nas" secondAttribute="bottom" constant="2" id="uWP-o0-nzA"/>
|
||||
</constraints>
|
||||
</collectionViewCellContentView>
|
||||
<connections>
|
||||
<outlet property="colorView" destination="NxF-xt-nas" id="ywq-kB-ycp"/>
|
||||
</connections>
|
||||
</collectionViewCell>
|
||||
</cells>
|
||||
<collectionReusableView key="sectionHeaderView" opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center" reuseIdentifier="PaletteCollectionSectionHeaderView" id="bRa-K0-IUz" customClass="PaletteCollectionSectionHeaderView" customModule="CoreStoreDemo" customModuleProvider="target">
|
||||
<rect key="frame" x="0.0" y="0.0" width="375" height="50"/>
|
||||
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMaxY="YES"/>
|
||||
<subviews>
|
||||
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="Label" textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="KHu-XO-jxd">
|
||||
<rect key="frame" x="10" y="2" width="363" height="46"/>
|
||||
<fontDescription key="fontDescription" name="HelveticaNeue-Medium" family="Helvetica Neue" pointSize="17"/>
|
||||
<nil key="textColor"/>
|
||||
<nil key="highlightedColor"/>
|
||||
</label>
|
||||
</subviews>
|
||||
<constraints>
|
||||
<constraint firstAttribute="trailing" secondItem="KHu-XO-jxd" secondAttribute="trailing" constant="2" id="Meb-ZG-6uP"/>
|
||||
<constraint firstAttribute="bottom" secondItem="KHu-XO-jxd" secondAttribute="bottom" constant="2" id="SL5-cA-7nf"/>
|
||||
<constraint firstItem="KHu-XO-jxd" firstAttribute="top" secondItem="bRa-K0-IUz" secondAttribute="top" constant="2" id="VFE-35-4gg"/>
|
||||
<constraint firstItem="KHu-XO-jxd" firstAttribute="leading" secondItem="bRa-K0-IUz" secondAttribute="leading" constant="10" id="pzx-h0-rZd"/>
|
||||
</constraints>
|
||||
<connections>
|
||||
<outlet property="label" destination="KHu-XO-jxd" id="qqK-Rm-eww"/>
|
||||
</connections>
|
||||
</collectionReusableView>
|
||||
<connections>
|
||||
<outlet property="dataSource" destination="EKY-1g-ALK" id="way-Q8-Xhb"/>
|
||||
<outlet property="delegate" destination="EKY-1g-ALK" id="r9k-Fz-mWc"/>
|
||||
</connections>
|
||||
</collectionView>
|
||||
<navigationItem key="navigationItem" title="ListPublisher" id="goy-Zu-94A"/>
|
||||
<connections>
|
||||
<segue destination="dX3-kR-CYC" kind="show" identifier="ObjectObserverDemoViewController" id="k4E-dJ-1lz"/>
|
||||
</connections>
|
||||
</collectionViewController>
|
||||
<placeholder placeholderIdentifier="IBFirstResponder" id="Fmi-gN-RXz" userLabel="First Responder" customClass="UIResponder" sceneMemberID="firstResponder"/>
|
||||
</objects>
|
||||
<point key="canvasLocation" x="5156" y="1484"/>
|
||||
</scene>
|
||||
<!--Time Zones-->
|
||||
<scene sceneID="nFT-bo-7y9">
|
||||
<objects>
|
||||
@@ -916,7 +985,7 @@
|
||||
<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="WGY-kX-mAx">
|
||||
<rect key="frame" x="0.0" y="64" width="375" height="603"/>
|
||||
<rect key="frame" x="0.0" y="44" width="375" height="623"/>
|
||||
<color key="backgroundColor" red="0.15542715787887573" green="0.2203737199306488" blue="0.2959403395652771" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
|
||||
<color key="separatorColor" red="0.15542715787887573" green="0.2203737199306488" blue="0.2959403395652771" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
|
||||
<view key="tableHeaderView" contentMode="scaleToFill" id="iaH-1W-Sbo">
|
||||
@@ -924,7 +993,7 @@
|
||||
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMaxY="YES"/>
|
||||
<subviews>
|
||||
<segmentedControl opaque="NO" contentMode="scaleToFill" contentHorizontalAlignment="left" contentVerticalAlignment="top" segmentControlStyle="bordered" selectedSegmentIndex="0" translatesAutoresizingMaskIntoConstraints="NO" id="YVj-dA-fyV">
|
||||
<rect key="frame" x="20" y="26" width="335" height="29"/>
|
||||
<rect key="frame" x="20" y="24.5" width="335" height="32"/>
|
||||
<segments>
|
||||
<segment title="Fetch"/>
|
||||
<segment title="Query"/>
|
||||
@@ -944,14 +1013,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="102" width="375" height="44"/>
|
||||
<rect key="frame" x="0.0" y="108" width="375" 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="342" height="43.5"/>
|
||||
<rect key="frame" x="0.0" y="0.0" width="349" height="44"/>
|
||||
<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="325" height="43.5"/>
|
||||
<rect key="frame" x="15" y="0.0" width="326" height="44"/>
|
||||
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMaxY="YES"/>
|
||||
<fontDescription key="fontDescription" name="HelveticaNeue-Light" family="Helvetica Neue" pointSize="18"/>
|
||||
<color key="textColor" red="0.13079629838466644" green="0.184075728058815" blue="0.24594299495220184" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
|
||||
@@ -998,21 +1067,21 @@
|
||||
<color key="separatorColor" red="0.15542715787887573" green="0.2203737199306488" blue="0.2959403395652771" 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="36" width="375" height="60"/>
|
||||
<rect key="frame" x="0.0" y="28" width="375" 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="375" height="59.5"/>
|
||||
<rect key="frame" x="0.0" y="0.0" width="375" height="60"/>
|
||||
<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="16" y="11" width="48.5" height="24"/>
|
||||
<rect key="frame" x="16" y="12" 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.13079629838466644" green="0.184075728058815" blue="0.24594299495220184" 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="16" y="35" width="31" height="13.5"/>
|
||||
<rect key="frame" x="16" y="36" width="31" height="13.5"/>
|
||||
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMaxY="YES"/>
|
||||
<fontDescription key="fontDescription" type="system" pointSize="11"/>
|
||||
<color key="textColor" red="0.13079629838466644" green="0.184075728058815" blue="0.24594299495220184" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
|
||||
@@ -1044,21 +1113,21 @@
|
||||
<color key="separatorColor" red="0.15542715787887573" green="0.2203737199306488" blue="0.2959403395652771" 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="36" width="375" height="60"/>
|
||||
<rect key="frame" x="0.0" y="28" width="375" 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="375" height="59.5"/>
|
||||
<rect key="frame" x="0.0" y="0.0" width="375" height="60"/>
|
||||
<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="16" y="11" width="48.5" height="24"/>
|
||||
<rect key="frame" x="16" y="12" 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.13079629838466644" green="0.184075728058815" blue="0.24594299495220184" 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="16" y="35" width="31" height="13.5"/>
|
||||
<rect key="frame" x="16" y="36" width="31" height="13.5"/>
|
||||
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMaxY="YES"/>
|
||||
<fontDescription key="fontDescription" type="system" pointSize="11"/>
|
||||
<color key="textColor" red="0.13079629838466644" green="0.184075728058815" blue="0.24594299495220184" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
|
||||
@@ -1079,11 +1148,35 @@
|
||||
</objects>
|
||||
<point key="canvasLocation" x="4404" y="3055"/>
|
||||
</scene>
|
||||
<!--Navigation Controller-->
|
||||
<scene sceneID="s0N-is-CU8">
|
||||
<objects>
|
||||
<navigationController automaticallyAdjustsScrollViewInsets="NO" id="Rdw-NU-NaK" sceneMemberID="viewController">
|
||||
<toolbarItems/>
|
||||
<navigationBar key="navigationBar" contentMode="scaleToFill" insetsLayoutMarginsFromSafeArea="NO" id="clN-r9-yIR">
|
||||
<rect key="frame" x="0.0" y="0.0" width="375" height="44"/>
|
||||
<autoresizingMask key="autoresizingMask"/>
|
||||
<color key="tintColor" red="0.68627450980000004" green="0.71372549019999998" blue="0.73333333329999995" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
|
||||
<color key="barTintColor" red="0.12941176469999999" green="0.1840757281" blue="0.245942995" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
|
||||
<textAttributes key="titleTextAttributes">
|
||||
<fontDescription key="fontDescription" name="HelveticaNeue-Thin" family="Helvetica Neue" pointSize="21"/>
|
||||
<color key="textColor" red="0.68627450980000004" green="0.71372549019999998" blue="0.73333333329999995" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
|
||||
</textAttributes>
|
||||
</navigationBar>
|
||||
<nil name="viewControllers"/>
|
||||
<connections>
|
||||
<segue destination="EKY-1g-ALK" kind="relationship" relationship="rootViewController" id="CG7-LF-MHV"/>
|
||||
</connections>
|
||||
</navigationController>
|
||||
<placeholder placeholderIdentifier="IBFirstResponder" id="qAN-O1-Rn4" userLabel="First Responder" customClass="UIResponder" sceneMemberID="firstResponder"/>
|
||||
</objects>
|
||||
<point key="canvasLocation" x="4404" y="1484"/>
|
||||
</scene>
|
||||
</scenes>
|
||||
<resources>
|
||||
<image name="second" width="30" height="30"/>
|
||||
</resources>
|
||||
<inferredMetricsTieBreakers>
|
||||
<segue reference="fIB-GS-Ppk"/>
|
||||
<segue reference="k4E-dJ-1lz"/>
|
||||
</inferredMetricsTieBreakers>
|
||||
</document>
|
||||
|
||||
@@ -17,7 +17,7 @@
|
||||
<key>CFBundlePackageType</key>
|
||||
<string>APPL</string>
|
||||
<key>CFBundleShortVersionString</key>
|
||||
<string>6.3.0</string>
|
||||
<string>6.3.2</string>
|
||||
<key>CFBundleSignature</key>
|
||||
<string>????</string>
|
||||
<key>CFBundleVersion</key>
|
||||
@@ -50,5 +50,7 @@
|
||||
</array>
|
||||
<key>UIViewControllerBasedStatusBarAppearance</key>
|
||||
<false/>
|
||||
<key>UIUserInterfaceStyle</key>
|
||||
<string>Light</string>
|
||||
</dict>
|
||||
</plist>
|
||||
|
||||
@@ -0,0 +1,169 @@
|
||||
//
|
||||
// CollectionViewDemoViewController.swift
|
||||
// CoreStoreDemo
|
||||
//
|
||||
// Created by John Estropia on 2019/10/17.
|
||||
// Copyright © 2019 John Rommel Estropia. All rights reserved.
|
||||
//
|
||||
|
||||
import UIKit
|
||||
import CoreStore
|
||||
|
||||
|
||||
// MARK: - CollectionViewDemoViewController
|
||||
|
||||
final class CollectionViewDemoViewController: UICollectionViewController {
|
||||
|
||||
// MARK: UIViewController
|
||||
|
||||
override func viewDidLoad() {
|
||||
|
||||
super.viewDidLoad()
|
||||
|
||||
let navigationItem = self.navigationItem
|
||||
navigationItem.leftBarButtonItems = [
|
||||
self.editButtonItem,
|
||||
UIBarButtonItem(
|
||||
barButtonSystemItem: .trash,
|
||||
target: self,
|
||||
action: #selector(self.resetBarButtonItemTouched(_:))
|
||||
)
|
||||
]
|
||||
|
||||
let filterBarButton = UIBarButtonItem(
|
||||
title: ColorsDemo.filter.rawValue,
|
||||
style: .plain,
|
||||
target: self,
|
||||
action: #selector(self.filterBarButtonItemTouched(_:))
|
||||
)
|
||||
navigationItem.rightBarButtonItems = [
|
||||
UIBarButtonItem(
|
||||
barButtonSystemItem: .add,
|
||||
target: self,
|
||||
action: #selector(self.addBarButtonItemTouched(_:))
|
||||
),
|
||||
UIBarButtonItem(
|
||||
barButtonSystemItem: .refresh,
|
||||
target: self,
|
||||
action: #selector(self.shuffleBarButtonItemTouched(_:))
|
||||
),
|
||||
filterBarButton
|
||||
]
|
||||
self.filterBarButton = filterBarButton
|
||||
|
||||
self.dataSource = DiffableDataSource.CollectionView<Palette>(
|
||||
collectionView: self.collectionView,
|
||||
dataStack: ColorsDemo.stack,
|
||||
cellProvider: { (collectionView, indexPath, palette) in
|
||||
|
||||
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "PaletteCollectionViewCell", for: indexPath) as! PaletteCollectionViewCell
|
||||
cell.colorView?.backgroundColor = palette.color
|
||||
cell.label?.text = palette.colorText
|
||||
return cell
|
||||
},
|
||||
supplementaryViewProvider: { (collectionView, kind, indexPath) in
|
||||
|
||||
switch kind {
|
||||
|
||||
case UICollectionView.elementKindSectionHeader:
|
||||
let view = collectionView.dequeueReusableSupplementaryView(ofKind: kind, withReuseIdentifier: "PaletteCollectionSectionHeaderView", for: indexPath) as! PaletteCollectionSectionHeaderView
|
||||
view.label?.text = ColorsDemo.palettes.snapshot.sectionIDs[indexPath.section]
|
||||
return view
|
||||
|
||||
default:
|
||||
return nil
|
||||
}
|
||||
}
|
||||
)
|
||||
ColorsDemo.palettes.addObserver(self) { [weak self] (listPublisher) in
|
||||
|
||||
guard let self = self else {
|
||||
|
||||
return
|
||||
}
|
||||
self.filterBarButton?.title = ColorsDemo.filter.rawValue
|
||||
self.dataSource?.apply(listPublisher.snapshot, animatingDifferences: true)
|
||||
}
|
||||
self.dataSource?.apply(ColorsDemo.palettes.snapshot, animatingDifferences: false)
|
||||
}
|
||||
|
||||
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
|
||||
|
||||
super.prepare(for: segue, sender: sender)
|
||||
|
||||
switch (segue.identifier, segue.destination, sender) {
|
||||
|
||||
case ("ObjectObserverDemoViewController"?, let destinationViewController as ObjectObserverDemoViewController, let palette as ObjectPublisher<Palette>):
|
||||
destinationViewController.setPalette(palette)
|
||||
|
||||
default:
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// MARK: UICollectionViewDelegate
|
||||
|
||||
override func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath) {
|
||||
|
||||
collectionView.deselectItem(at: indexPath, animated: true)
|
||||
|
||||
self.performSegue(
|
||||
withIdentifier: "ObjectObserverDemoViewController",
|
||||
sender: ColorsDemo.palettes.snapshot[indexPath]
|
||||
)
|
||||
}
|
||||
|
||||
|
||||
// MARK: Private
|
||||
|
||||
private var filterBarButton: UIBarButtonItem?
|
||||
private var dataSource: DiffableDataSource.CollectionView<Palette>?
|
||||
|
||||
deinit {
|
||||
|
||||
ColorsDemo.palettes.removeObserver(self)
|
||||
}
|
||||
|
||||
@IBAction private dynamic func resetBarButtonItemTouched(_ sender: AnyObject?) {
|
||||
|
||||
ColorsDemo.stack.perform(
|
||||
asynchronous: { (transaction) in
|
||||
|
||||
try transaction.deleteAll(From<Palette>())
|
||||
},
|
||||
completion: { _ in }
|
||||
)
|
||||
}
|
||||
|
||||
@IBAction private dynamic func filterBarButtonItemTouched(_ sender: AnyObject?) {
|
||||
|
||||
ColorsDemo.filter = ColorsDemo.filter.next()
|
||||
}
|
||||
|
||||
@IBAction private dynamic func addBarButtonItemTouched(_ sender: AnyObject?) {
|
||||
|
||||
ColorsDemo.stack.perform(
|
||||
asynchronous: { (transaction) in
|
||||
|
||||
let palette = transaction.create(Into<Palette>())
|
||||
palette.setInitialValues(in: transaction)
|
||||
},
|
||||
completion: { _ in }
|
||||
)
|
||||
}
|
||||
|
||||
@IBAction private dynamic func shuffleBarButtonItemTouched(_ sender: AnyObject?) {
|
||||
ColorsDemo.stack.perform(
|
||||
asynchronous: { (transaction) in
|
||||
|
||||
for palette in try transaction.fetchAll(From<Palette>()) {
|
||||
|
||||
palette.hue .= Palette.randomHue()
|
||||
palette.colorName .= nil
|
||||
}
|
||||
},
|
||||
completion: { _ in }
|
||||
)
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,88 @@
|
||||
//
|
||||
// ColorsDemo.swift
|
||||
// CoreStoreDemo
|
||||
//
|
||||
// Created by John Rommel Estropia on 2019/10/17.
|
||||
// Copyright © 2019 John Rommel Estropia. All rights reserved.
|
||||
//
|
||||
|
||||
import Foundation
|
||||
import CoreStore
|
||||
|
||||
|
||||
// MARK: - ColorsDemo
|
||||
|
||||
struct ColorsDemo {
|
||||
|
||||
enum Filter: String {
|
||||
|
||||
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<Palette> {
|
||||
|
||||
switch self {
|
||||
|
||||
case .all: return .init()
|
||||
case .light: return (\Palette.brightness >= 0.9)
|
||||
case .dark: return (\Palette.brightness <= 0.4)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static var filter = Filter.all {
|
||||
|
||||
didSet {
|
||||
|
||||
try! self.palettes.refetch(
|
||||
From<Palette>()
|
||||
.sectionBy(\.colorName)
|
||||
.where(self.filter.whereClause())
|
||||
.orderBy(.ascending(\.hue))
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
static let stack: DataStack = {
|
||||
|
||||
let dataStack = DataStack(
|
||||
CoreStoreSchema(
|
||||
modelVersion: "ColorsDemo",
|
||||
entities: [
|
||||
Entity<Palette>("Palette"),
|
||||
],
|
||||
versionLock: [
|
||||
"Palette": [0x8c25aa53c7c90a28, 0xa243a34d25f1a3a7, 0x56565b6935b6055a, 0x4f988bb257bf274f]
|
||||
]
|
||||
)
|
||||
)
|
||||
|
||||
try! dataStack.addStorageAndWait(
|
||||
SQLiteStore(
|
||||
fileName: "ColorsDemo.sqlite",
|
||||
localStorageOptions: .recreateStoreOnModelMismatch
|
||||
)
|
||||
)
|
||||
return dataStack
|
||||
}()
|
||||
|
||||
static let palettes: ListPublisher<Palette> = {
|
||||
|
||||
return ColorsDemo.stack.listPublisher(
|
||||
From<Palette>()
|
||||
.sectionBy(\.colorName)
|
||||
.orderBy(.ascending(\.hue))
|
||||
)
|
||||
}()
|
||||
}
|
||||
@@ -10,89 +10,34 @@ import UIKit
|
||||
import CoreStore
|
||||
|
||||
|
||||
struct ColorsDemo {
|
||||
|
||||
enum Filter: String {
|
||||
|
||||
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<Palette> {
|
||||
|
||||
switch self {
|
||||
|
||||
case .all: return .init()
|
||||
case .light: return (\Palette.brightness >= 0.9)
|
||||
case .dark: return (\Palette.brightness <= 0.4)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static var filter = Filter.all {
|
||||
|
||||
didSet {
|
||||
|
||||
self.palettes.refetch(
|
||||
self.filter.whereClause(),
|
||||
OrderBy<Palette>(.ascending(\.hue))
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
static let stack: DataStack = {
|
||||
|
||||
return DataStack(
|
||||
CoreStoreSchema(
|
||||
modelVersion: "ColorsDemo",
|
||||
entities: [
|
||||
Entity<Palette>("Palette"),
|
||||
],
|
||||
versionLock: [
|
||||
"Palette": [0x8c25aa53c7c90a28, 0xa243a34d25f1a3a7, 0x56565b6935b6055a, 0x4f988bb257bf274f]
|
||||
]
|
||||
)
|
||||
)
|
||||
}()
|
||||
|
||||
static let palettes: ListMonitor<Palette> = {
|
||||
|
||||
try! ColorsDemo.stack.addStorageAndWait(
|
||||
SQLiteStore(
|
||||
fileName: "ColorsDemo.sqlite",
|
||||
localStorageOptions: .recreateStoreOnModelMismatch
|
||||
)
|
||||
)
|
||||
return ColorsDemo.stack.monitorSectionedList(
|
||||
From<Palette>()
|
||||
.sectionBy(\.colorName)
|
||||
.orderBy(.ascending(\.hue))
|
||||
)
|
||||
}()
|
||||
}
|
||||
|
||||
|
||||
// MARK: - ListObserverDemoViewController
|
||||
|
||||
class ListObserverDemoViewController: UITableViewController, ListSectionObserver {
|
||||
|
||||
// MARK: NSObject
|
||||
|
||||
deinit {
|
||||
|
||||
ColorsDemo.palettes.removeObserver(self)
|
||||
final class ListObserverDemoViewController: UITableViewController {
|
||||
|
||||
// MARK: - EditableDataSource
|
||||
|
||||
final class EditableDataSource: DiffableDataSource.TableView<Palette> {
|
||||
|
||||
override func tableView(_ tableView: UITableView, commit editingStyle: UITableViewCell.EditingStyle, forRowAt indexPath: IndexPath) {
|
||||
|
||||
switch editingStyle {
|
||||
|
||||
case .delete:
|
||||
let palette = ColorsDemo.palettes.snapshot[indexPath]
|
||||
ColorsDemo.stack.perform(
|
||||
asynchronous: { (transaction) in
|
||||
|
||||
transaction.delete(palette)
|
||||
},
|
||||
completion: { _ in }
|
||||
)
|
||||
|
||||
default:
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
// MARK: UIViewController
|
||||
|
||||
@@ -130,10 +75,28 @@ class ListObserverDemoViewController: UITableViewController, ListSectionObserver
|
||||
filterBarButton
|
||||
]
|
||||
self.filterBarButton = filterBarButton
|
||||
|
||||
ColorsDemo.palettes.addObserver(self)
|
||||
|
||||
self.setTable(enabled: !ColorsDemo.palettes.isPendingRefetch)
|
||||
|
||||
self.dataSource = EditableDataSource(
|
||||
tableView: self.tableView,
|
||||
dataStack: ColorsDemo.stack,
|
||||
cellProvider: { (tableView, indexPath, palette) in
|
||||
|
||||
let cell = tableView.dequeueReusableCell(withIdentifier: "PaletteTableViewCell") as! PaletteTableViewCell
|
||||
cell.colorView?.backgroundColor = palette.color
|
||||
cell.label?.text = palette.colorText
|
||||
return cell
|
||||
}
|
||||
)
|
||||
ColorsDemo.palettes.addObserver(self) { [weak self] (listPublisher) in
|
||||
|
||||
guard let self = self else {
|
||||
|
||||
return
|
||||
}
|
||||
self.filterBarButton?.title = ColorsDemo.filter.rawValue
|
||||
self.dataSource?.apply(listPublisher.snapshot, animatingDifferences: true)
|
||||
}
|
||||
self.dataSource?.apply(ColorsDemo.palettes.snapshot, animatingDifferences: false)
|
||||
}
|
||||
|
||||
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
|
||||
@@ -142,8 +105,8 @@ class ListObserverDemoViewController: UITableViewController, ListSectionObserver
|
||||
|
||||
switch (segue.identifier, segue.destination, sender) {
|
||||
|
||||
case ("ObjectObserverDemoViewController"?, let destinationViewController as ObjectObserverDemoViewController, let palette as Palette):
|
||||
destinationViewController.palette = palette
|
||||
case ("ObjectObserverDemoViewController"?, let destinationViewController as ObjectObserverDemoViewController, let palette as ObjectPublisher<Palette>):
|
||||
destinationViewController.setPalette(palette)
|
||||
|
||||
default:
|
||||
break
|
||||
@@ -151,30 +114,6 @@ class ListObserverDemoViewController: UITableViewController, ListSectionObserver
|
||||
}
|
||||
|
||||
|
||||
// MARK: UITableViewDataSource
|
||||
|
||||
override func numberOfSections(in tableView: UITableView) -> Int {
|
||||
|
||||
return ColorsDemo.palettes.numberOfSections()
|
||||
}
|
||||
|
||||
override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
|
||||
|
||||
return ColorsDemo.palettes.numberOfObjects(in: section)
|
||||
}
|
||||
|
||||
override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
|
||||
|
||||
let cell = tableView.dequeueReusableCell(withIdentifier: "PaletteTableViewCell") as! PaletteTableViewCell
|
||||
|
||||
let palette = ColorsDemo.palettes[indexPath]
|
||||
cell.colorView?.backgroundColor = palette.color
|
||||
cell.label?.text = palette.colorText
|
||||
|
||||
return cell
|
||||
}
|
||||
|
||||
|
||||
// MARK: UITableViewDelegate
|
||||
|
||||
override func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
|
||||
@@ -183,105 +122,20 @@ class ListObserverDemoViewController: UITableViewController, ListSectionObserver
|
||||
|
||||
self.performSegue(
|
||||
withIdentifier: "ObjectObserverDemoViewController",
|
||||
sender: ColorsDemo.palettes[indexPath]
|
||||
sender: ColorsDemo.palettes.snapshot[indexPath]
|
||||
)
|
||||
}
|
||||
|
||||
override func tableView(_ tableView: UITableView, commit editingStyle: UITableViewCell.EditingStyle, forRowAt indexPath: IndexPath) {
|
||||
|
||||
switch editingStyle {
|
||||
|
||||
case .delete:
|
||||
let palette = ColorsDemo.palettes[indexPath]
|
||||
ColorsDemo.stack.perform(
|
||||
asynchronous: { (transaction) in
|
||||
|
||||
transaction.delete(palette)
|
||||
},
|
||||
completion: { _ in }
|
||||
)
|
||||
|
||||
default:
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
override func tableView(_ tableView: UITableView, titleForHeaderInSection section: Int) -> String? {
|
||||
|
||||
return ColorsDemo.palettes.sectionInfo(at: section).name
|
||||
}
|
||||
|
||||
|
||||
// MARK: ListObserver
|
||||
|
||||
func listMonitorWillChange(_ monitor: ListMonitor<Palette>) {
|
||||
|
||||
self.tableView.beginUpdates()
|
||||
}
|
||||
|
||||
func listMonitorDidChange(_ monitor: ListMonitor<Palette>) {
|
||||
|
||||
self.tableView.endUpdates()
|
||||
}
|
||||
|
||||
func listMonitorWillRefetch(_ monitor: ListMonitor<Palette>) {
|
||||
|
||||
self.setTable(enabled: false)
|
||||
}
|
||||
|
||||
func listMonitorDidRefetch(_ monitor: ListMonitor<Palette>) {
|
||||
|
||||
self.filterBarButton?.title = ColorsDemo.filter.rawValue
|
||||
self.tableView.reloadData()
|
||||
self.setTable(enabled: true)
|
||||
}
|
||||
|
||||
|
||||
// MARK: ListObjectObserver
|
||||
|
||||
func listMonitor(_ monitor: ListMonitor<Palette>, didInsertObject object: Palette, toIndexPath indexPath: IndexPath) {
|
||||
|
||||
self.tableView.insertRows(at: [indexPath], with: .automatic)
|
||||
}
|
||||
|
||||
func listMonitor(_ monitor: ListMonitor<Palette>, didDeleteObject object: Palette, fromIndexPath indexPath: IndexPath) {
|
||||
|
||||
self.tableView.deleteRows(at: [indexPath], with: .automatic)
|
||||
}
|
||||
|
||||
func listMonitor(_ monitor: ListMonitor<Palette>, didUpdateObject object: Palette, atIndexPath indexPath: IndexPath) {
|
||||
|
||||
if let cell = self.tableView.cellForRow(at: indexPath) as? PaletteTableViewCell {
|
||||
|
||||
let palette = ColorsDemo.palettes[indexPath]
|
||||
cell.colorView?.backgroundColor = palette.color
|
||||
cell.label?.text = palette.colorText
|
||||
}
|
||||
}
|
||||
|
||||
func listMonitor(_ monitor: ListMonitor<Palette>, didMoveObject object: Palette, fromIndexPath: IndexPath, toIndexPath: IndexPath) {
|
||||
|
||||
self.tableView.deleteRows(at: [fromIndexPath], with: .automatic)
|
||||
self.tableView.insertRows(at: [toIndexPath], with: .automatic)
|
||||
}
|
||||
|
||||
|
||||
// MARK: ListSectionObserver
|
||||
|
||||
func listMonitor(_ monitor: ListMonitor<Palette>, didInsertSection sectionInfo: NSFetchedResultsSectionInfo, toSectionIndex sectionIndex: Int) {
|
||||
|
||||
self.tableView.insertSections(IndexSet(integer: sectionIndex), with: .automatic)
|
||||
}
|
||||
|
||||
func listMonitor(_ monitor: ListMonitor<Palette>, didDeleteSection sectionInfo: NSFetchedResultsSectionInfo, fromSectionIndex sectionIndex: Int) {
|
||||
|
||||
self.tableView.deleteSections(IndexSet(integer: sectionIndex), with: .automatic)
|
||||
}
|
||||
|
||||
|
||||
// MARK: Private
|
||||
|
||||
private var filterBarButton: UIBarButtonItem?
|
||||
private var dataSource: DiffableDataSource.TableView<Palette>?
|
||||
|
||||
deinit {
|
||||
|
||||
ColorsDemo.palettes.removeObserver(self)
|
||||
}
|
||||
|
||||
@IBAction private dynamic func resetBarButtonItemTouched(_ sender: AnyObject?) {
|
||||
|
||||
@@ -312,8 +166,6 @@ class ListObserverDemoViewController: UITableViewController, ListSectionObserver
|
||||
}
|
||||
|
||||
@IBAction private dynamic func shuffleBarButtonItemTouched(_ sender: AnyObject?) {
|
||||
|
||||
self.setTable(enabled: false)
|
||||
ColorsDemo.stack.perform(
|
||||
asynchronous: { (transaction) in
|
||||
|
||||
@@ -323,28 +175,7 @@ class ListObserverDemoViewController: UITableViewController, ListSectionObserver
|
||||
palette.colorName .= nil
|
||||
}
|
||||
},
|
||||
completion: { _ in
|
||||
|
||||
self.setTable(enabled: true)
|
||||
}
|
||||
)
|
||||
}
|
||||
|
||||
private func setTable(enabled: Bool) {
|
||||
|
||||
tableView.isUserInteractionEnabled = enabled
|
||||
UIView.animate(
|
||||
withDuration: 0.2,
|
||||
delay: 0,
|
||||
options: .beginFromCurrentState,
|
||||
animations: { () -> Void in
|
||||
|
||||
if let tableView = self.tableView {
|
||||
|
||||
tableView.alpha = enabled ? 1.0 : 0.5
|
||||
}
|
||||
},
|
||||
completion: nil
|
||||
completion: { _ in }
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -14,30 +14,23 @@ import CoreStore
|
||||
|
||||
class ObjectObserverDemoViewController: UIViewController, ObjectObserver {
|
||||
|
||||
var palette: Palette? {
|
||||
func setPalette<O: ObjectRepresentation>(_ newValue: O?) where O.ObjectType == Palette {
|
||||
|
||||
get {
|
||||
guard self.monitor?.object?.objectID() != newValue?.objectID() else {
|
||||
|
||||
return self.monitor?.object
|
||||
return
|
||||
}
|
||||
set {
|
||||
if let newValue = newValue {
|
||||
|
||||
guard self.monitor?.object != newValue else {
|
||||
|
||||
return
|
||||
}
|
||||
self.monitor = newValue.asReadOnly(in: ColorsDemo.stack).map(ColorsDemo.stack.monitorObject(_:))
|
||||
}
|
||||
else {
|
||||
|
||||
if let palette = newValue {
|
||||
|
||||
self.monitor = ColorsDemo.stack.monitorObject(palette)
|
||||
}
|
||||
else {
|
||||
|
||||
self.monitor = nil
|
||||
}
|
||||
self.monitor = nil
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// MARK: NSObject
|
||||
|
||||
deinit {
|
||||
|
||||
@@ -27,4 +27,33 @@ class ObserversViewController: UIViewController {
|
||||
alert.addAction(UIAlertAction(title: "OK", style: .cancel, handler: nil))
|
||||
self.present(alert, animated: true, completion: nil)
|
||||
}
|
||||
|
||||
|
||||
// MARK: Private
|
||||
|
||||
@IBOutlet private dynamic weak var toggleTopBarButtonItem: UIBarButtonItem?
|
||||
@IBOutlet private dynamic weak var toggleBottomBarButtonItem: UIBarButtonItem?
|
||||
@IBOutlet private dynamic weak var stackView: UIStackView?
|
||||
@IBOutlet private dynamic weak var topContainerView: UIView?
|
||||
@IBOutlet private dynamic weak var bottomContainerView: UIView?
|
||||
|
||||
@IBAction private dynamic func toggleTopContainerView() {
|
||||
|
||||
UIView.animate(withDuration: 0.2) {
|
||||
|
||||
self.topContainerView!.isHidden.toggle()
|
||||
}
|
||||
self.toggleTopBarButtonItem!.isEnabled = !self.bottomContainerView!.isHidden
|
||||
self.toggleBottomBarButtonItem!.isEnabled = !self.topContainerView!.isHidden
|
||||
}
|
||||
|
||||
@IBAction private dynamic func toggleBottomContainerView() {
|
||||
|
||||
UIView.animate(withDuration: 0.2) {
|
||||
|
||||
self.bottomContainerView!.isHidden.toggle()
|
||||
}
|
||||
self.toggleTopBarButtonItem!.isEnabled = !self.bottomContainerView!.isHidden
|
||||
self.toggleBottomBarButtonItem!.isEnabled = !self.topContainerView!.isHidden
|
||||
}
|
||||
}
|
||||
|
||||
@@ -73,9 +73,12 @@ extension Palette {
|
||||
|
||||
return "H: \(self.hue.value)˚, S: \(round(self.saturation.value * 100.0))%, B: \(round(self.brightness.value * 100.0))%"
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
extension Palette {
|
||||
|
||||
func setInitialValues(in transaction: BaseDataTransaction) {
|
||||
|
||||
|
||||
self.hue .= Palette.randomHue()
|
||||
self.saturation .= Float(1.0)
|
||||
self.brightness .= Float(arc4random_uniform(70) + 30) / 100.0
|
||||
|
||||
@@ -0,0 +1,17 @@
|
||||
//
|
||||
// PaletteCollectionSectionHeaderView.swift
|
||||
// CoreStoreDemo
|
||||
//
|
||||
// Created by John Estropia on 2019/10/17.
|
||||
// Copyright © 2019 John Rommel Estropia. All rights reserved.
|
||||
//
|
||||
|
||||
import UIKit
|
||||
|
||||
|
||||
// MARK: - PaletteCollectionSectionHeaderView
|
||||
|
||||
final class PaletteCollectionSectionHeaderView: UICollectionReusableView {
|
||||
|
||||
@IBOutlet weak var label: UILabel?
|
||||
}
|
||||
@@ -0,0 +1,18 @@
|
||||
//
|
||||
// PaletteCollectionViewCell.swift
|
||||
// CoreStoreDemo
|
||||
//
|
||||
// Created by John Estropia on 2019/10/17.
|
||||
// Copyright © 2019 John Rommel Estropia. All rights reserved.
|
||||
//
|
||||
|
||||
import UIKit
|
||||
|
||||
|
||||
// MARK: - PaletteCollectionViewCell
|
||||
|
||||
final class PaletteCollectionViewCell: UICollectionViewCell {
|
||||
|
||||
@IBOutlet weak var colorView: UIView?
|
||||
@IBOutlet weak var label: UILabel?
|
||||
}
|
||||
@@ -8,7 +8,10 @@
|
||||
|
||||
import UIKit
|
||||
|
||||
class PaletteTableViewCell: UITableViewCell {
|
||||
|
||||
// MARK: - PaletteTableViewCell
|
||||
|
||||
final class PaletteTableViewCell: UITableViewCell {
|
||||
|
||||
@IBOutlet weak var colorView: UIView?
|
||||
@IBOutlet weak var label: UILabel?
|
||||
|
||||
@@ -31,7 +31,7 @@ class CustomLoggerViewController: UIViewController, CoreStoreLogger {
|
||||
|
||||
super.viewDidAppear(animated)
|
||||
|
||||
CoreStore.logger = self
|
||||
CoreStoreDefaults.logger = self
|
||||
|
||||
let alert = UIAlertController(
|
||||
title: "Logger Demo",
|
||||
@@ -46,7 +46,7 @@ class CustomLoggerViewController: UIViewController, CoreStoreLogger {
|
||||
|
||||
super.viewDidDisappear(animated)
|
||||
|
||||
CoreStore.logger = DefaultLogger()
|
||||
CoreStoreDefaults.logger = DefaultLogger()
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -8,7 +8,7 @@
|
||||
|
||||
import Foundation
|
||||
|
||||
protocol OrganismProtocol: class {
|
||||
protocol OrganismProtocol: AnyObject {
|
||||
|
||||
var dna: Int64 { get set }
|
||||
|
||||
|
||||
@@ -0,0 +1,53 @@
|
||||
//
|
||||
// SwiftUIContainerViewController.swift
|
||||
// CoreStoreDemo
|
||||
//
|
||||
// Created by John Rommel Estropia on 2019/10/02.
|
||||
// Copyright © 2019 John Rommel Estropia. All rights reserved.
|
||||
//
|
||||
|
||||
import UIKit
|
||||
import CoreStore
|
||||
|
||||
#if canImport(SwiftUI)
|
||||
import SwiftUI
|
||||
|
||||
#endif
|
||||
|
||||
#if canImport(Combine)
|
||||
import Combine
|
||||
|
||||
#endif
|
||||
|
||||
import Compression
|
||||
final class SwiftUIContainerViewController: UIViewController {
|
||||
|
||||
override func viewDidLoad() {
|
||||
super.viewDidLoad()
|
||||
|
||||
#if canImport(SwiftUI) && canImport(Combine)
|
||||
|
||||
if #available(iOS 13, *) {
|
||||
|
||||
let hostingController = UIHostingController(
|
||||
rootView: SwiftUIView(
|
||||
palettes: ColorsDemo.stack.listPublisher(
|
||||
From<Palette>()
|
||||
.sectionBy(\.colorName)
|
||||
.orderBy(.ascending(\.hue))
|
||||
)
|
||||
)
|
||||
.environment(\.dataStack, ColorsDemo.stack)
|
||||
)
|
||||
self.addChild(hostingController)
|
||||
|
||||
hostingController.view.autoresizingMask = [.flexibleWidth, .flexibleHeight]
|
||||
hostingController.view.frame = self.view.bounds.inset(by: self.view.safeAreaInsets)
|
||||
self.view.addSubview(hostingController.view)
|
||||
|
||||
hostingController.didMove(toParent: self)
|
||||
}
|
||||
|
||||
#endif
|
||||
}
|
||||
}
|
||||
184
CoreStoreDemo/CoreStoreDemo/SwiftUI Demo/SwiftUIView.swift
Normal file
184
CoreStoreDemo/CoreStoreDemo/SwiftUI Demo/SwiftUIView.swift
Normal file
@@ -0,0 +1,184 @@
|
||||
//
|
||||
// SwiftUIView.swift
|
||||
// CoreStoreDemo
|
||||
//
|
||||
// Created by John Rommel Estropia on 2019/10/02.
|
||||
// Copyright © 2019 John Rommel Estropia. All rights reserved.
|
||||
//
|
||||
|
||||
#if canImport(SwiftUI) && canImport(Combine)
|
||||
import SwiftUI
|
||||
import Combine
|
||||
|
||||
import CoreStore
|
||||
|
||||
|
||||
@available(iOS 13.0.0, *)
|
||||
struct SwiftUIView: View {
|
||||
|
||||
@Environment(\.dataStack)
|
||||
var dataStack: DataStack
|
||||
|
||||
@ObservedObject
|
||||
var palettes: ListPublisher<Palette>
|
||||
|
||||
var body: some View {
|
||||
NavigationView {
|
||||
List {
|
||||
ForEach(palettes.snapshot.sectionIDs, id: \.self) { (sectionID) in
|
||||
Section(header: Text(sectionID)) {
|
||||
ForEach(self.palettes.snapshot.items(inSectionWithID: sectionID), id: \.self) { palette in
|
||||
NavigationLink(
|
||||
destination: DetailView(palette: palette),
|
||||
label: { ColorCell(palette: palette) }
|
||||
)
|
||||
}
|
||||
.onDelete { itemIndices in
|
||||
let objectIDsToDelete = self.palettes.snapshot.itemIDs(
|
||||
inSectionWithID: sectionID,
|
||||
atIndices: itemIndices
|
||||
)
|
||||
self.dataStack.perform(
|
||||
asynchronous: { transaction in
|
||||
|
||||
transaction.delete(objectIDs: objectIDsToDelete)
|
||||
},
|
||||
completion: { _ in }
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
.navigationBarTitle(Text("SwiftUI (\(palettes.snapshot.numberOfItems) objects)"))
|
||||
.navigationBarItems(
|
||||
leading: EditButton(),
|
||||
trailing: HStack {
|
||||
Button(
|
||||
action: {
|
||||
|
||||
self.dataStack.perform(
|
||||
asynchronous: { transaction in
|
||||
|
||||
for palette in try transaction.fetchAll(From<Palette>()) {
|
||||
|
||||
palette.hue .= Palette.randomHue()
|
||||
palette.colorName .= nil
|
||||
}
|
||||
},
|
||||
completion: { _ in }
|
||||
)
|
||||
},
|
||||
label: {
|
||||
Image(systemName: "goforward")
|
||||
}
|
||||
)
|
||||
.frame(width: 30)
|
||||
Button(
|
||||
action: {
|
||||
|
||||
self.dataStack.perform(
|
||||
asynchronous: { transaction in
|
||||
|
||||
let palette = transaction.create(Into<Palette>())
|
||||
palette.setInitialValues(in: transaction)
|
||||
},
|
||||
completion: { _ in }
|
||||
)
|
||||
},
|
||||
label: {
|
||||
Image(systemName: "plus")
|
||||
}
|
||||
)
|
||||
.frame(width: 30)
|
||||
}
|
||||
)
|
||||
.alert(
|
||||
isPresented: $needsShowAlert,
|
||||
content: {
|
||||
Alert(
|
||||
title: Text("SwiftUI Binding Demo"),
|
||||
message: Text("This demo shows how to bind to ListPublisher and to CoreStoreObject when using SwiftUI"),
|
||||
dismissButton: .cancel(Text("OK"))
|
||||
)
|
||||
}
|
||||
)
|
||||
.onAppear {
|
||||
|
||||
self.needsShowAlert = true
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@State
|
||||
private var needsShowAlert = false
|
||||
}
|
||||
|
||||
@available(iOS 13.0.0, *)
|
||||
struct ColorCell: View {
|
||||
|
||||
@ObservedObject
|
||||
var palette: ObjectPublisher<Palette>
|
||||
|
||||
var body: some View {
|
||||
HStack {
|
||||
Color(palette.color ?? UIColor.clear)
|
||||
.cornerRadius(5)
|
||||
.frame(width: 30, height: 30, alignment: .leading)
|
||||
Text(palette.colorText ?? "<Deleted>")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@available(iOS 13.0.0, *)
|
||||
struct DetailView: View {
|
||||
|
||||
@Environment(\.dataStack)
|
||||
var dataStack: DataStack
|
||||
|
||||
@ObservedObject
|
||||
var palette: ObjectPublisher<Palette>
|
||||
|
||||
@State var hue: Float = 0
|
||||
@State var saturation: Float = 0
|
||||
@State var brightness: Float = 0
|
||||
|
||||
init(palette: ObjectPublisher<Palette>) {
|
||||
|
||||
self.palette = palette
|
||||
self.hue = Float(palette.hue ?? 0)
|
||||
self.saturation = palette.saturation ?? 0
|
||||
self.brightness = palette.brightness ?? 0
|
||||
}
|
||||
|
||||
var body: some View {
|
||||
ZStack {
|
||||
Color(palette.color ?? UIColor.clear)
|
||||
.cornerRadius(20)
|
||||
.padding(20)
|
||||
VStack {
|
||||
Text(palette.colorText ?? "<Deleted>")
|
||||
.navigationBarTitle(Text("Color"))
|
||||
Slider(value: $hue, in: 0.0 ... 359.0 as ClosedRange<Float>)
|
||||
Slider(value: $saturation, in: 0.0 ... 1.0 as ClosedRange<Float>)
|
||||
Slider(value: $brightness, in: 0.0 ... 0.1 as ClosedRange<Float>)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@available(iOS 13.0.0, *)
|
||||
struct SwiftUIView_Previews: PreviewProvider {
|
||||
|
||||
static var previews: some View {
|
||||
SwiftUIView(
|
||||
palettes: ColorsDemo.stack.listPublisher(
|
||||
From<Palette>()
|
||||
.sectionBy(\.colorName)
|
||||
.orderBy(.ascending(\.hue))
|
||||
)
|
||||
)
|
||||
.environment(\.dataStack, ColorsDemo.stack)
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
@@ -15,10 +15,12 @@ import CoreStore
|
||||
|
||||
|
||||
private struct Static {
|
||||
|
||||
|
||||
static let dataStack = DataStack()
|
||||
|
||||
static let placeController: ObjectMonitor<Place> = {
|
||||
|
||||
try! CoreStore.addStorageAndWait(
|
||||
try! Static.dataStack.addStorageAndWait(
|
||||
SQLiteStore(
|
||||
fileName: "PlaceDemo.sqlite",
|
||||
configuration: "TransactionsDemo",
|
||||
@@ -26,20 +28,20 @@ private struct Static {
|
||||
)
|
||||
)
|
||||
|
||||
var place = try! CoreStore.fetchOne(From<Place>())
|
||||
var place = try! Static.dataStack.fetchOne(From<Place>())
|
||||
if place == nil {
|
||||
|
||||
_ = try? CoreStore.perform(
|
||||
_ = try? Static.dataStack.perform(
|
||||
synchronous: { (transaction) in
|
||||
|
||||
let place = transaction.create(Into<Place>())
|
||||
place.setInitialValues()
|
||||
}
|
||||
)
|
||||
place = try! CoreStore.fetchOne(From<Place>())
|
||||
place = try! Static.dataStack.fetchOne(From<Place>())
|
||||
}
|
||||
|
||||
return CoreStore.monitorObject(place!)
|
||||
return Static.dataStack.monitorObject(place!)
|
||||
}()
|
||||
}
|
||||
|
||||
@@ -170,7 +172,7 @@ class TransactionsDemoViewController: UIViewController, MKMapViewDelegate, Objec
|
||||
gesture.location(in: mapView),
|
||||
toCoordinateFrom: mapView
|
||||
)
|
||||
CoreStore.perform(
|
||||
Static.dataStack.perform(
|
||||
asynchronous: { (transaction) in
|
||||
|
||||
let place = transaction.edit(Static.placeController.object)
|
||||
@@ -183,7 +185,7 @@ class TransactionsDemoViewController: UIViewController, MKMapViewDelegate, Objec
|
||||
|
||||
@IBAction dynamic func refreshButtonTapped(_ sender: AnyObject?) {
|
||||
|
||||
_ = try? CoreStore.perform(
|
||||
_ = try? Static.dataStack.perform(
|
||||
synchronous: { (transaction) in
|
||||
|
||||
let place = transaction.edit(Static.placeController.object)
|
||||
@@ -194,7 +196,7 @@ class TransactionsDemoViewController: UIViewController, MKMapViewDelegate, Objec
|
||||
|
||||
func geocode(place: Place) {
|
||||
|
||||
let transaction = CoreStore.beginUnsafe()
|
||||
let transaction = Static.dataStack.beginUnsafe()
|
||||
|
||||
self.geocoder?.cancelGeocode()
|
||||
|
||||
|
||||
@@ -40,7 +40,7 @@ class BaseTestCase: XCTestCase {
|
||||
|
||||
let stack = DataStack(
|
||||
xcodeModelName: "Model",
|
||||
bundle: Bundle(for: type(of: self))
|
||||
bundle: Bundle(for: Self.self)
|
||||
)
|
||||
do {
|
||||
|
||||
@@ -50,7 +50,7 @@ class BaseTestCase: XCTestCase {
|
||||
SQLiteStore(
|
||||
fileURL: SQLiteStore.defaultRootDirectory
|
||||
.appendingPathComponent(UUID().uuidString)
|
||||
.appendingPathComponent("\(type(of: self))_\(($0 ?? "-null-")).sqlite"),
|
||||
.appendingPathComponent("\(Self.self)_\(($0 ?? "-null-")).sqlite"),
|
||||
configuration: $0,
|
||||
localStorageOptions: .recreateStoreOnModelMismatch
|
||||
)
|
||||
@@ -67,11 +67,11 @@ class BaseTestCase: XCTestCase {
|
||||
@nonobjc
|
||||
func expectLogger<T>(_ expectations: [TestLogger.Expectation], closure: () throws -> T) rethrows -> T {
|
||||
|
||||
CoreStore.logger = TestLogger(self.prepareLoggerExpectations(expectations))
|
||||
CoreStoreDefaults.logger = TestLogger(self.prepareLoggerExpectations(expectations))
|
||||
defer {
|
||||
|
||||
self.checkExpectationsImmediately()
|
||||
CoreStore.logger = TestLogger([:])
|
||||
CoreStoreDefaults.logger = TestLogger([:])
|
||||
}
|
||||
return try closure()
|
||||
}
|
||||
@@ -79,17 +79,17 @@ class BaseTestCase: XCTestCase {
|
||||
@nonobjc
|
||||
func expectLogger(_ expectations: [TestLogger.Expectation: XCTestExpectation]) {
|
||||
|
||||
CoreStore.logger = TestLogger(expectations)
|
||||
CoreStoreDefaults.logger = TestLogger(expectations)
|
||||
}
|
||||
|
||||
@nonobjc
|
||||
func expectError<T>(code: CoreStoreErrorCode, closure: () throws -> T) {
|
||||
|
||||
CoreStore.logger = TestLogger(self.prepareLoggerExpectations([.logError]))
|
||||
CoreStoreDefaults.logger = TestLogger(self.prepareLoggerExpectations([.logError]))
|
||||
defer {
|
||||
|
||||
self.checkExpectationsImmediately()
|
||||
CoreStore.logger = TestLogger([:])
|
||||
CoreStoreDefaults.logger = TestLogger([:])
|
||||
}
|
||||
do {
|
||||
|
||||
@@ -105,7 +105,7 @@ class BaseTestCase: XCTestCase {
|
||||
}
|
||||
catch {
|
||||
|
||||
XCTFail("Error not wrapped as \(cs_typeName(CoreStoreError.self)): \((error as NSError).coreStoreDumpString)")
|
||||
XCTFail("Error not wrapped as \(Internals.typeName(CoreStoreError.self)): \((error as NSError).coreStoreDumpString)")
|
||||
}
|
||||
}
|
||||
|
||||
@@ -138,12 +138,12 @@ class BaseTestCase: XCTestCase {
|
||||
|
||||
super.setUp()
|
||||
self.deleteStores()
|
||||
CoreStore.logger = TestLogger([:])
|
||||
CoreStoreDefaults.logger = TestLogger([:])
|
||||
}
|
||||
|
||||
override func tearDown() {
|
||||
|
||||
CoreStore.logger = DefaultLogger()
|
||||
CoreStoreDefaults.logger = DefaultLogger()
|
||||
self.deleteStores()
|
||||
super.tearDown()
|
||||
}
|
||||
@@ -34,7 +34,7 @@ import CoreStore
|
||||
class BaseTestDataTestCase: BaseTestCase {
|
||||
|
||||
@nonobjc
|
||||
let dateFormatter: DateFormatter = cs_lazy {
|
||||
let dateFormatter: DateFormatter = Internals.with {
|
||||
|
||||
let formatter = DateFormatter()
|
||||
formatter.locale = Locale(identifier: "en_US_POSIX")
|
||||
@@ -168,14 +168,8 @@
|
||||
versionChain:nil];
|
||||
XCTAssertNotNil(dataStack);
|
||||
|
||||
[CSCoreStore setDefaultStack:dataStack];
|
||||
XCTAssertTrue([dataStack isEqual:[CSCoreStore defaultStack]]);
|
||||
}
|
||||
|
||||
- (void)test_ThatStorages_BridgeCorrectly {
|
||||
|
||||
NSError *memoryError;
|
||||
CSInMemoryStore *memoryStorage = [CSCoreStore
|
||||
CSInMemoryStore *memoryStorage = [dataStack
|
||||
addInMemoryStorageAndWait:[CSInMemoryStore new]
|
||||
error:&memoryError];
|
||||
XCTAssertNotNil(memoryStorage);
|
||||
@@ -186,7 +180,7 @@
|
||||
XCTAssertNil(memoryError);
|
||||
|
||||
NSError *sqliteError;
|
||||
CSSQLiteStore *sqliteStorage = [CSCoreStore
|
||||
CSSQLiteStore *sqliteStorage = [dataStack
|
||||
addSQLiteStorageAndWait:[CSSQLiteStore new]
|
||||
error:&sqliteError];
|
||||
XCTAssertNotNil(sqliteStorage);
|
||||
@@ -208,18 +202,19 @@
|
||||
}
|
||||
|
||||
- (void)test_ThatTransactions_BridgeCorrectly {
|
||||
|
||||
[CSCoreStore
|
||||
setDefaultStack:[[CSDataStack alloc]
|
||||
initWithXcodeModelName:@"Model"
|
||||
bundle:[NSBundle bundleForClass:[self class]]
|
||||
versionChain:nil]];
|
||||
[CSCoreStore
|
||||
|
||||
CSDataStack *dataStack = [[CSDataStack alloc]
|
||||
initWithXcodeModelName:@"Model"
|
||||
bundle:[NSBundle bundleForClass:[self class]]
|
||||
versionChain:nil];
|
||||
XCTAssertNotNil(dataStack);
|
||||
|
||||
[dataStack
|
||||
addInMemoryStorageAndWait:[CSInMemoryStore new]
|
||||
error:nil];
|
||||
|
||||
{
|
||||
CSUnsafeDataTransaction *transaction = [CSCoreStore beginUnsafe];
|
||||
CSUnsafeDataTransaction *transaction = [dataStack beginUnsafe];
|
||||
XCTAssertNotNil(transaction);
|
||||
XCTAssert([transaction isKindOfClass:[CSUnsafeDataTransaction class]]);
|
||||
NSError *error;
|
||||
@@ -230,23 +225,24 @@
|
||||
{
|
||||
XCTestExpectation *expectation = [self expectationWithDescription:@"sync"];
|
||||
NSError *error;
|
||||
BOOL result = [CSCoreStore
|
||||
BOOL result =
|
||||
[dataStack
|
||||
beginSynchronous:^(CSSynchronousDataTransaction * _Nonnull transaction) {
|
||||
|
||||
XCTAssertNotNil(transaction);
|
||||
XCTAssert([transaction isKindOfClass:[CSSynchronousDataTransaction class]]);
|
||||
NSError *error;
|
||||
XCTAssertTrue([transaction commitAndWaitWithError:&error]);
|
||||
XCTAssertNil(error);
|
||||
[expectation fulfill];
|
||||
}
|
||||
error:&error];
|
||||
|
||||
XCTAssertNotNil(transaction);
|
||||
XCTAssert([transaction isKindOfClass:[CSSynchronousDataTransaction class]]);
|
||||
NSError *error;
|
||||
XCTAssertTrue([transaction commitAndWaitWithError:&error]);
|
||||
XCTAssertNil(error);
|
||||
[expectation fulfill];
|
||||
}
|
||||
error:&error];
|
||||
XCTAssertTrue(result);
|
||||
XCTAssertNil(error);
|
||||
}
|
||||
{
|
||||
XCTestExpectation *expectation = [self expectationWithDescription:@"async"];
|
||||
[CSCoreStore beginAsynchronous:^(CSAsynchronousDataTransaction * _Nonnull transaction) {
|
||||
[dataStack beginAsynchronous:^(CSAsynchronousDataTransaction * _Nonnull transaction) {
|
||||
|
||||
XCTAssertNotNil(transaction);
|
||||
XCTAssert([transaction isKindOfClass:[CSAsynchronousDataTransaction class]]);
|
||||
|
||||
@@ -164,12 +164,73 @@ class DynamicModelTests: BaseTestDataTestCase {
|
||||
|
||||
animal.color .= .yellow
|
||||
XCTAssertEqual(animal.color.value, Color.yellow)
|
||||
|
||||
for property in Animal.metaProperties(includeSuperclasses: true) {
|
||||
|
||||
switch property.keyPath {
|
||||
|
||||
case String(keyPath: \Animal.species):
|
||||
XCTAssertTrue(property is ValueContainer<Animal>.Required<String>)
|
||||
|
||||
case String(keyPath: \Animal.master):
|
||||
XCTAssertTrue(property is RelationshipContainer<Animal>.ToOne<Person>)
|
||||
|
||||
case String(keyPath: \Animal.color):
|
||||
XCTAssertTrue(property is TransformableContainer<Animal>.Optional<Color>)
|
||||
|
||||
default:
|
||||
XCTFail("Unknown KeyPath: \"\(property.keyPath)\"")
|
||||
}
|
||||
}
|
||||
|
||||
let dog = transaction.create(Into<Dog>())
|
||||
XCTAssertEqual(dog.species.value, "Swift")
|
||||
XCTAssertEqual(dog.nickname.value, nil)
|
||||
XCTAssertEqual(dog.age.value, 1)
|
||||
|
||||
for property in Dog.metaProperties(includeSuperclasses: true) {
|
||||
|
||||
switch property.keyPath {
|
||||
|
||||
case String(keyPath: \Dog.species):
|
||||
XCTAssertTrue(property is ValueContainer<Animal>.Required<String>)
|
||||
|
||||
case String(keyPath: \Dog.master):
|
||||
XCTAssertTrue(property is RelationshipContainer<Animal>.ToOne<Person>)
|
||||
|
||||
case String(keyPath: \Dog.color):
|
||||
XCTAssertTrue(property is TransformableContainer<Animal>.Optional<Color>)
|
||||
|
||||
case String(keyPath: \Dog.nickname):
|
||||
XCTAssertTrue(property is ValueContainer<Dog>.Optional<String>)
|
||||
|
||||
case String(keyPath: \Dog.age):
|
||||
XCTAssertTrue(property is ValueContainer<Dog>.Required<Int>)
|
||||
|
||||
case String(keyPath: \Dog.friends):
|
||||
XCTAssertTrue(property is RelationshipContainer<Dog>.ToManyOrdered<Dog>)
|
||||
|
||||
case String(keyPath: \Dog.friendedBy):
|
||||
XCTAssertTrue(property is RelationshipContainer<Dog>.ToManyUnordered<Dog>)
|
||||
|
||||
default:
|
||||
XCTFail("Unknown KeyPath: \"\(property.keyPath)\"")
|
||||
}
|
||||
}
|
||||
|
||||
// #if swift(>=5.1)
|
||||
//
|
||||
// let dogKeyPathBuilder = Dog.keyPathBuilder()
|
||||
// XCTAssertEqual(dogKeyPathBuilder.species.keyPathString, "SELF.species")
|
||||
// XCTAssertEqual(dogKeyPathBuilder.master.title.keyPathString, "SELF.master.title")
|
||||
// let a = dogKeyPathBuilder.master
|
||||
// let b = dogKeyPathBuilder.master.spouse
|
||||
// let c = dogKeyPathBuilder.master.spouse.pets
|
||||
// let d = dogKeyPathBuilder.master.spouse.pets.color
|
||||
// XCTAssertEqual(dogKeyPathBuilder.master.spouse.pets.color.keyPathString, "SELF.master.spouse.pets.color")
|
||||
//
|
||||
// #endif
|
||||
|
||||
let didSetObserver = dog.species.observe(options: [.new, .old]) { (object, change) in
|
||||
|
||||
XCTAssertEqual(object, dog)
|
||||
@@ -213,7 +274,9 @@ class DynamicModelTests: BaseTestDataTestCase {
|
||||
XCTAssertTrue(person.pets.value.isEmpty)
|
||||
|
||||
XCTAssertEqual(
|
||||
cs_dynamicType(of: person.rawObject!).keyPathsForValuesAffectingValue(forKey: "displayName"),
|
||||
person.rawObject!
|
||||
.runtimeType()
|
||||
.keyPathsForValuesAffectingValue(forKey: "displayName"),
|
||||
["title", "name"]
|
||||
)
|
||||
|
||||
@@ -229,9 +292,33 @@ class DynamicModelTests: BaseTestDataTestCase {
|
||||
XCTAssertEqual(person.name.value, "John")
|
||||
XCTAssertEqual(person.displayName.value, "Mr. John") // Custom getter
|
||||
|
||||
let personSnapshot1 = person.asSnapshot(in: transaction)!
|
||||
XCTAssertEqual(person.name.value, personSnapshot1.name)
|
||||
XCTAssertEqual(person.title.value, personSnapshot1.title)
|
||||
XCTAssertEqual(person.displayName.value, personSnapshot1.displayName)
|
||||
|
||||
person.title .= "Sir"
|
||||
XCTAssertEqual(person.displayName.value, "Sir John")
|
||||
|
||||
XCTAssertEqual(personSnapshot1.name, "John")
|
||||
XCTAssertEqual(personSnapshot1.title, "Mr.")
|
||||
XCTAssertEqual(personSnapshot1.displayName, "Mr. John")
|
||||
|
||||
let personSnapshot2 = person.asSnapshot(in: transaction)!
|
||||
XCTAssertEqual(person.name.value, personSnapshot2.name)
|
||||
XCTAssertEqual(person.title.value, personSnapshot2.title)
|
||||
XCTAssertEqual(person.displayName.value, personSnapshot2.displayName)
|
||||
|
||||
var personSnapshot3 = personSnapshot2
|
||||
personSnapshot3.name = "James"
|
||||
XCTAssertEqual(personSnapshot1.name, "John")
|
||||
XCTAssertEqual(personSnapshot1.displayName, "Mr. John")
|
||||
XCTAssertEqual(personSnapshot2.name, "John")
|
||||
XCTAssertEqual(personSnapshot2.displayName, "Sir John")
|
||||
XCTAssertEqual(personSnapshot3.name, "James")
|
||||
XCTAssertEqual(personSnapshot3.displayName, "Sir John")
|
||||
|
||||
|
||||
person.pets.value.insert(dog)
|
||||
XCTAssertEqual(person.pets.count, 1)
|
||||
XCTAssertEqual(person.pets.value.first, dog)
|
||||
@@ -337,7 +424,7 @@ class DynamicModelTests: BaseTestDataTestCase {
|
||||
SQLiteStore(
|
||||
fileURL: SQLiteStore.defaultRootDirectory
|
||||
.appendingPathComponent(UUID().uuidString)
|
||||
.appendingPathComponent("\(type(of: self))_\((configuration ?? "-null-")).sqlite"),
|
||||
.appendingPathComponent("\(Self.self)_\((configuration ?? "-null-")).sqlite"),
|
||||
configuration: configuration,
|
||||
localStorageOptions: .recreateStoreOnModelMismatch
|
||||
)
|
||||
|
||||
@@ -88,7 +88,7 @@ final class ErrorTests: XCTestCase {
|
||||
let schemaHistory = SchemaHistory(
|
||||
XcodeDataModelSchema.from(
|
||||
modelName: "Model",
|
||||
bundle: Bundle(for: type(of: self))
|
||||
bundle: Bundle(for: Self.self)
|
||||
)
|
||||
)
|
||||
let version = "1.0.0"
|
||||
|
||||
@@ -74,7 +74,7 @@ final class FromTests: BaseTestCase {
|
||||
|
||||
let from = From<TestEntity1>()
|
||||
|
||||
let request = CoreStoreFetchRequest<NSFetchRequestResult>()
|
||||
let request = Internals.CoreStoreFetchRequest<NSFetchRequestResult>()
|
||||
try from.applyToFetchRequest(request, context: dataStack.mainContext)
|
||||
XCTAssertNotNil(request.entity)
|
||||
XCTAssertNotNil(request.safeAffectedStores())
|
||||
@@ -88,7 +88,7 @@ final class FromTests: BaseTestCase {
|
||||
|
||||
let from = From<TestEntity1>("Config1")
|
||||
|
||||
let request = CoreStoreFetchRequest<NSFetchRequestResult>()
|
||||
let request = Internals.CoreStoreFetchRequest<NSFetchRequestResult>()
|
||||
self.expectError(code: .persistentStoreNotFound) {
|
||||
|
||||
try from.applyToFetchRequest(request, context: dataStack.mainContext)
|
||||
@@ -113,7 +113,7 @@ final class FromTests: BaseTestCase {
|
||||
|
||||
let from = From<TestEntity1>()
|
||||
|
||||
let request = CoreStoreFetchRequest<NSFetchRequestResult>()
|
||||
let request = Internals.CoreStoreFetchRequest<NSFetchRequestResult>()
|
||||
let storesFound: Void? = try? from.applyToFetchRequest(request, context: dataStack.mainContext)
|
||||
XCTAssertNotNil(storesFound)
|
||||
XCTAssertNotNil(request.entity)
|
||||
@@ -128,7 +128,7 @@ final class FromTests: BaseTestCase {
|
||||
|
||||
let from = From<TestEntity1>("Config1")
|
||||
|
||||
let request = CoreStoreFetchRequest<NSFetchRequestResult>()
|
||||
let request = Internals.CoreStoreFetchRequest<NSFetchRequestResult>()
|
||||
let storesFound: Void? = try? from.applyToFetchRequest(request, context: dataStack.mainContext)
|
||||
XCTAssertNotNil(storesFound)
|
||||
XCTAssertNotNil(request.entity)
|
||||
@@ -143,7 +143,7 @@ final class FromTests: BaseTestCase {
|
||||
|
||||
let from = From<TestEntity1>("Config2")
|
||||
|
||||
let request = CoreStoreFetchRequest<NSFetchRequestResult>()
|
||||
let request = Internals.CoreStoreFetchRequest<NSFetchRequestResult>()
|
||||
self.expectError(code: .persistentStoreNotFound) {
|
||||
|
||||
try from.applyToFetchRequest(request, context: dataStack.mainContext)
|
||||
@@ -160,7 +160,7 @@ final class FromTests: BaseTestCase {
|
||||
|
||||
let from = From<TestEntity2>()
|
||||
|
||||
let request = CoreStoreFetchRequest<NSFetchRequestResult>()
|
||||
let request = Internals.CoreStoreFetchRequest<NSFetchRequestResult>()
|
||||
self.expectError(code: .persistentStoreNotFound) {
|
||||
|
||||
try from.applyToFetchRequest(request, context: dataStack.mainContext)
|
||||
@@ -177,7 +177,7 @@ final class FromTests: BaseTestCase {
|
||||
|
||||
let from = From<TestEntity2>("Config1")
|
||||
|
||||
let request = CoreStoreFetchRequest<NSFetchRequestResult>()
|
||||
let request = Internals.CoreStoreFetchRequest<NSFetchRequestResult>()
|
||||
self.expectError(code: .persistentStoreNotFound) {
|
||||
|
||||
try from.applyToFetchRequest(request, context: dataStack.mainContext)
|
||||
@@ -194,7 +194,7 @@ final class FromTests: BaseTestCase {
|
||||
|
||||
let from = From<TestEntity2>("Config2")
|
||||
|
||||
let request = CoreStoreFetchRequest<NSFetchRequestResult>()
|
||||
let request = Internals.CoreStoreFetchRequest<NSFetchRequestResult>()
|
||||
self.expectError(code: .persistentStoreNotFound) {
|
||||
|
||||
try from.applyToFetchRequest(request, context: dataStack.mainContext)
|
||||
@@ -219,7 +219,7 @@ final class FromTests: BaseTestCase {
|
||||
|
||||
let from = From<TestEntity1>()
|
||||
|
||||
let request = CoreStoreFetchRequest<NSFetchRequestResult>()
|
||||
let request = Internals.CoreStoreFetchRequest<NSFetchRequestResult>()
|
||||
let storesFound: Void? = try? from.applyToFetchRequest(request, context: dataStack.mainContext)
|
||||
XCTAssertNotNil(storesFound)
|
||||
XCTAssertNotNil(request.entity)
|
||||
@@ -234,7 +234,7 @@ final class FromTests: BaseTestCase {
|
||||
|
||||
let from = From<TestEntity1>("Config1")
|
||||
|
||||
let request = CoreStoreFetchRequest<NSFetchRequestResult>()
|
||||
let request = Internals.CoreStoreFetchRequest<NSFetchRequestResult>()
|
||||
let storesFound: Void? = try? from.applyToFetchRequest(request, context: dataStack.mainContext)
|
||||
XCTAssertNotNil(storesFound)
|
||||
XCTAssertNotNil(request.entity)
|
||||
@@ -249,7 +249,7 @@ final class FromTests: BaseTestCase {
|
||||
|
||||
let from = From<TestEntity1>("Config2")
|
||||
|
||||
let request = CoreStoreFetchRequest<NSFetchRequestResult>()
|
||||
let request = Internals.CoreStoreFetchRequest<NSFetchRequestResult>()
|
||||
self.expectError(code: .persistentStoreNotFound) {
|
||||
|
||||
try from.applyToFetchRequest(request, context: dataStack.mainContext)
|
||||
@@ -266,7 +266,7 @@ final class FromTests: BaseTestCase {
|
||||
|
||||
let from = From<TestEntity2>()
|
||||
|
||||
let request = CoreStoreFetchRequest<NSFetchRequestResult>()
|
||||
let request = Internals.CoreStoreFetchRequest<NSFetchRequestResult>()
|
||||
let storesFound: Void? = try? from.applyToFetchRequest(request, context: dataStack.mainContext)
|
||||
XCTAssertNotNil(storesFound)
|
||||
XCTAssertNotNil(request.entity)
|
||||
@@ -281,7 +281,7 @@ final class FromTests: BaseTestCase {
|
||||
|
||||
let from = From<TestEntity2>("Config1")
|
||||
|
||||
let request = CoreStoreFetchRequest<NSFetchRequestResult>()
|
||||
let request = Internals.CoreStoreFetchRequest<NSFetchRequestResult>()
|
||||
self.expectError(code: .persistentStoreNotFound) {
|
||||
|
||||
try from.applyToFetchRequest(request, context: dataStack.mainContext)
|
||||
@@ -298,7 +298,7 @@ final class FromTests: BaseTestCase {
|
||||
|
||||
let from = From<TestEntity2>("Config2")
|
||||
|
||||
let request = CoreStoreFetchRequest<NSFetchRequestResult>()
|
||||
let request = Internals.CoreStoreFetchRequest<NSFetchRequestResult>()
|
||||
self.expectError(code: .persistentStoreNotFound) {
|
||||
|
||||
try from.applyToFetchRequest(request, context: dataStack.mainContext)
|
||||
@@ -323,7 +323,7 @@ final class FromTests: BaseTestCase {
|
||||
|
||||
let from = From<TestEntity1>()
|
||||
|
||||
let request = CoreStoreFetchRequest<NSFetchRequestResult>()
|
||||
let request = Internals.CoreStoreFetchRequest<NSFetchRequestResult>()
|
||||
let storesFound: Void? = try? from.applyToFetchRequest(request, context: dataStack.mainContext)
|
||||
XCTAssertNotNil(storesFound)
|
||||
XCTAssertNotNil(request.entity)
|
||||
@@ -338,7 +338,7 @@ final class FromTests: BaseTestCase {
|
||||
|
||||
let from = From<TestEntity1>("Config1")
|
||||
|
||||
let request = CoreStoreFetchRequest<NSFetchRequestResult>()
|
||||
let request = Internals.CoreStoreFetchRequest<NSFetchRequestResult>()
|
||||
let storesFound: Void? = try? from.applyToFetchRequest(request, context: dataStack.mainContext)
|
||||
XCTAssertNotNil(storesFound)
|
||||
XCTAssertNotNil(request.entity)
|
||||
@@ -353,7 +353,7 @@ final class FromTests: BaseTestCase {
|
||||
|
||||
let from = From<TestEntity1>("Config2")
|
||||
|
||||
let request = CoreStoreFetchRequest<NSFetchRequestResult>()
|
||||
let request = Internals.CoreStoreFetchRequest<NSFetchRequestResult>()
|
||||
self.expectError(code: .persistentStoreNotFound) {
|
||||
|
||||
try from.applyToFetchRequest(request, context: dataStack.mainContext)
|
||||
@@ -370,7 +370,7 @@ final class FromTests: BaseTestCase {
|
||||
|
||||
let from = From<TestEntity2>()
|
||||
|
||||
let request = CoreStoreFetchRequest<NSFetchRequestResult>()
|
||||
let request = Internals.CoreStoreFetchRequest<NSFetchRequestResult>()
|
||||
let storesFound: Void? = try? from.applyToFetchRequest(request, context: dataStack.mainContext)
|
||||
XCTAssertNotNil(storesFound)
|
||||
XCTAssertNotNil(request.entity)
|
||||
@@ -385,7 +385,7 @@ final class FromTests: BaseTestCase {
|
||||
|
||||
let from = From<TestEntity2>("Config1")
|
||||
|
||||
let request = CoreStoreFetchRequest<NSFetchRequestResult>()
|
||||
let request = Internals.CoreStoreFetchRequest<NSFetchRequestResult>()
|
||||
self.expectError(code: .persistentStoreNotFound) {
|
||||
|
||||
try from.applyToFetchRequest(request, context: dataStack.mainContext)
|
||||
@@ -402,7 +402,7 @@ final class FromTests: BaseTestCase {
|
||||
|
||||
let from = From<TestEntity2>("Config2")
|
||||
|
||||
let request = CoreStoreFetchRequest<NSFetchRequestResult>()
|
||||
let request = Internals.CoreStoreFetchRequest<NSFetchRequestResult>()
|
||||
let storesFound: Void? = try? from.applyToFetchRequest(request, context: dataStack.mainContext)
|
||||
XCTAssertNotNil(storesFound)
|
||||
XCTAssertNotNil(request.entity)
|
||||
|
||||
@@ -68,7 +68,7 @@ final class GroupByTests: BaseTestCase {
|
||||
|
||||
let groupBy = GroupBy<NSManagedObject>(#keyPath(TestEntity1.testString))
|
||||
|
||||
let request = CoreStoreFetchRequest<NSFetchRequestResult>()
|
||||
let request = Internals.CoreStoreFetchRequest<NSFetchRequestResult>()
|
||||
try From<TestEntity1>().applyToFetchRequest(request, context: dataStack.mainContext)
|
||||
groupBy.applyToFetchRequest(request)
|
||||
|
||||
|
||||
683
CoreStoreTests/ListPublisherTests.swift
Normal file
683
CoreStoreTests/ListPublisherTests.swift
Normal file
@@ -0,0 +1,683 @@
|
||||
//
|
||||
// ListPublisherTests.swift
|
||||
// CoreStore iOS
|
||||
//
|
||||
// Copyright © 2018 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.
|
||||
//
|
||||
|
||||
#if canImport(UIKit) || canImport(AppKit)
|
||||
|
||||
import XCTest
|
||||
|
||||
@testable
|
||||
import CoreStore
|
||||
|
||||
|
||||
// MARK: - ListPublisherTests
|
||||
|
||||
@available(iOS 13.0, tvOS 13.0, watchOS 6.0, macOS 10.15, *)
|
||||
class ListPublisherTests: BaseTestDataTestCase {
|
||||
|
||||
@objc
|
||||
dynamic func test_ThatListPublishers_CanReceiveInsertNotifications() {
|
||||
|
||||
self.prepareStack { (stack) in
|
||||
|
||||
// let observer = TestListObserver()
|
||||
let listPublisher = stack.listPublisher(
|
||||
From<TestEntity1>(),
|
||||
SectionBy(#keyPath(TestEntity1.testBoolean)),
|
||||
OrderBy<TestEntity1>(.ascending(#keyPath(TestEntity1.testBoolean)), .ascending(#keyPath(TestEntity1.testEntityID)))
|
||||
)
|
||||
// monitor.addObserver(observer)
|
||||
//
|
||||
// XCTAssertFalse(monitor.hasSections())
|
||||
// XCTAssertFalse(monitor.hasObjects())
|
||||
// XCTAssertTrue(monitor.objectsInAllSections().isEmpty)
|
||||
//
|
||||
// var events = 0
|
||||
//
|
||||
// let willChangeExpectation = self.expectation(
|
||||
// forNotification: NSNotification.Name(rawValue: "listMonitorWillChange:"),
|
||||
// object: observer,
|
||||
// handler: { (note) -> Bool in
|
||||
//
|
||||
// XCTAssertEqual(events, 0)
|
||||
// XCTAssertEqual((note.userInfo as NSDictionary?) ?? [:], NSDictionary())
|
||||
// defer {
|
||||
//
|
||||
// events += 1
|
||||
// }
|
||||
// return events == 0
|
||||
// }
|
||||
// )
|
||||
// let didInsertSectionExpectation = self.expectation(
|
||||
// forNotification: NSNotification.Name(rawValue: "listMonitor:didInsertSection:toSectionIndex:"),
|
||||
// object: observer,
|
||||
// handler: { (note) -> Bool in
|
||||
//
|
||||
// XCTAssertEqual(events, 1)
|
||||
// XCTAssertEqual(
|
||||
// ((note.userInfo as NSDictionary?) ?? [:]),
|
||||
// [
|
||||
// "sectionInfo": monitor.sectionInfo(at: 0),
|
||||
// "sectionIndex": 0
|
||||
// ] as NSDictionary
|
||||
// )
|
||||
// defer {
|
||||
//
|
||||
// events += 1
|
||||
// }
|
||||
// return events == 1
|
||||
// }
|
||||
// )
|
||||
// let didInsertObjectExpectation = self.expectation(
|
||||
// forNotification: NSNotification.Name(rawValue: "listMonitor:didInsertObject:toIndexPath:"),
|
||||
// object: observer,
|
||||
// handler: { (note) -> Bool in
|
||||
//
|
||||
// XCTAssertEqual(events, 2)
|
||||
//
|
||||
// let userInfo = note.userInfo
|
||||
// XCTAssertNotNil(userInfo)
|
||||
// XCTAssertEqual(
|
||||
// Set(userInfo?.keys.map({ $0 as! String }) ?? []),
|
||||
// ["indexPath", "object"]
|
||||
// )
|
||||
//
|
||||
// let indexPath = userInfo?["indexPath"] as? NSIndexPath
|
||||
// XCTAssertEqual(indexPath?.index(atPosition: 0), 0)
|
||||
// XCTAssertEqual(indexPath?.index(atPosition: 1), 0)
|
||||
//
|
||||
// let object = userInfo?["object"] as? TestEntity1
|
||||
// XCTAssertEqual(object?.testBoolean, NSNumber(value: true))
|
||||
// XCTAssertEqual(object?.testNumber, NSNumber(value: 1))
|
||||
// XCTAssertEqual(object?.testDecimal, NSDecimalNumber(string: "1"))
|
||||
// XCTAssertEqual(object?.testString, "nil:TestEntity1:1")
|
||||
// XCTAssertEqual(object?.testData, ("nil:TestEntity1:1" as NSString).data(using: String.Encoding.utf8.rawValue)!)
|
||||
// XCTAssertEqual(object?.testDate, self.dateFormatter.date(from: "2000-01-01T00:00:00Z")!)
|
||||
// defer {
|
||||
//
|
||||
// events += 1
|
||||
// }
|
||||
// return events == 2
|
||||
// }
|
||||
// )
|
||||
// let didChangeExpectation = self.expectation(
|
||||
// forNotification: NSNotification.Name(rawValue: "listMonitorDidChange:"),
|
||||
// object: observer,
|
||||
// handler: { (note) -> Bool in
|
||||
//
|
||||
// XCTAssertEqual((note.userInfo as NSDictionary?) ?? [:], NSDictionary())
|
||||
// defer {
|
||||
//
|
||||
// events += 1
|
||||
// }
|
||||
// return events == 3
|
||||
// }
|
||||
// )
|
||||
let saveExpectation = self.expectation(description: "save")
|
||||
stack.perform(
|
||||
asynchronous: { (transaction) -> Bool in
|
||||
|
||||
let object = transaction.create(Into<TestEntity1>())
|
||||
object.testBoolean = NSNumber(value: true)
|
||||
object.testNumber = NSNumber(value: 1)
|
||||
object.testDecimal = NSDecimalNumber(string: "1")
|
||||
object.testString = "nil:TestEntity1:1"
|
||||
object.testData = ("nil:TestEntity1:1" as NSString).data(using: String.Encoding.utf8.rawValue)!
|
||||
object.testDate = self.dateFormatter.date(from: "2000-01-01T00:00:00Z")!
|
||||
|
||||
return transaction.hasChanges
|
||||
},
|
||||
success: { (hasChanges) in
|
||||
|
||||
XCTAssertTrue(hasChanges)
|
||||
saveExpectation.fulfill()
|
||||
},
|
||||
failure: { _ in
|
||||
|
||||
XCTFail()
|
||||
}
|
||||
)
|
||||
self.waitAndCheckExpectations()
|
||||
|
||||
withExtendedLifetime(listPublisher, {})
|
||||
}
|
||||
}
|
||||
|
||||
// @objc
|
||||
// dynamic func test_ThatListObservers_CanReceiveUpdateNotifications() {
|
||||
//
|
||||
// self.prepareStack { (stack) in
|
||||
//
|
||||
// self.prepareTestDataForStack(stack)
|
||||
//
|
||||
// let observer = TestListObserver()
|
||||
// let monitor = stack.monitorSectionedList(
|
||||
// From<TestEntity1>(),
|
||||
// SectionBy(#keyPath(TestEntity1.testBoolean)),
|
||||
// OrderBy<TestEntity1>(.ascending(#keyPath(TestEntity1.testBoolean)), .ascending(#keyPath(TestEntity1.testEntityID)))
|
||||
// )
|
||||
// monitor.addObserver(observer)
|
||||
//
|
||||
// XCTAssertTrue(monitor.hasSections())
|
||||
// XCTAssertEqual(monitor.numberOfSections(), 2)
|
||||
// XCTAssertTrue(monitor.hasObjects())
|
||||
// XCTAssertTrue(monitor.hasObjects(in: 0))
|
||||
// XCTAssertEqual(monitor.numberOfObjects(in: 0), 2)
|
||||
// XCTAssertEqual(monitor.numberOfObjects(in: 1), 3)
|
||||
//
|
||||
// var events = 0
|
||||
//
|
||||
// let willChangeExpectation = self.expectation(
|
||||
// forNotification: NSNotification.Name(rawValue: "listMonitorWillChange:"),
|
||||
// object: observer,
|
||||
// handler: { (note) -> Bool in
|
||||
//
|
||||
// XCTAssertEqual(events, 0)
|
||||
// XCTAssertEqual((note.userInfo as NSDictionary?) ?? [:], NSDictionary())
|
||||
// defer {
|
||||
//
|
||||
// events += 1
|
||||
// }
|
||||
// return events == 0
|
||||
// }
|
||||
// )
|
||||
//
|
||||
// let didUpdateObjectExpectation = self.expectation(
|
||||
// forNotification: NSNotification.Name(rawValue: "listMonitor:didUpdateObject:atIndexPath:"),
|
||||
// object: observer,
|
||||
// handler: { (note) -> Bool in
|
||||
//
|
||||
// XCTAssert(events == 1 || events == 2)
|
||||
//
|
||||
// let userInfo = note.userInfo
|
||||
// XCTAssertNotNil(userInfo)
|
||||
// XCTAssertEqual(
|
||||
// Set(userInfo?.keys.map({ $0 as! String }) ?? []),
|
||||
// ["indexPath", "object"]
|
||||
// )
|
||||
//
|
||||
// let indexPath = userInfo?["indexPath"] as? NSIndexPath
|
||||
// let object = userInfo?["object"] as? TestEntity1
|
||||
//
|
||||
// switch object?.testEntityID {
|
||||
//
|
||||
// case NSNumber(value: 101)?:
|
||||
// XCTAssertEqual(indexPath?.index(atPosition: 0), 1)
|
||||
// XCTAssertEqual(indexPath?.index(atPosition: 1), 0)
|
||||
//
|
||||
// XCTAssertEqual(object?.testBoolean, NSNumber(value: true))
|
||||
// XCTAssertEqual(object?.testNumber, NSNumber(value: 11))
|
||||
// XCTAssertEqual(object?.testDecimal, NSDecimalNumber(string: "11"))
|
||||
// XCTAssertEqual(object?.testString, "nil:TestEntity1:11")
|
||||
// XCTAssertEqual(object?.testData, ("nil:TestEntity1:11" as NSString).data(using: String.Encoding.utf8.rawValue)!)
|
||||
// XCTAssertEqual(object?.testDate, self.dateFormatter.date(from: "2000-01-11T00:00:00Z")!)
|
||||
//
|
||||
// case NSNumber(value: 102)?:
|
||||
// XCTAssertEqual(indexPath?.index(atPosition: 0), 0)
|
||||
// XCTAssertEqual(indexPath?.index(atPosition: 1), 0)
|
||||
//
|
||||
// XCTAssertEqual(object?.testBoolean, NSNumber(value: false))
|
||||
// XCTAssertEqual(object?.testNumber, NSNumber(value: 22))
|
||||
// XCTAssertEqual(object?.testDecimal, NSDecimalNumber(string: "22"))
|
||||
// XCTAssertEqual(object?.testString, "nil:TestEntity1:22")
|
||||
// XCTAssertEqual(object?.testData, ("nil:TestEntity1:22" as NSString).data(using: String.Encoding.utf8.rawValue)!)
|
||||
// XCTAssertEqual(object?.testDate, self.dateFormatter.date(from: "2000-01-22T00:00:00Z")!)
|
||||
//
|
||||
// default:
|
||||
// XCTFail()
|
||||
// }
|
||||
// defer {
|
||||
//
|
||||
// events += 1
|
||||
// }
|
||||
// return events == 1 || events == 2
|
||||
// }
|
||||
// )
|
||||
// let didChangeExpectation = self.expectation(
|
||||
// forNotification: NSNotification.Name(rawValue: "listMonitorDidChange:"),
|
||||
// object: observer,
|
||||
// handler: { (note) -> Bool in
|
||||
//
|
||||
// XCTAssertEqual(events, 3)
|
||||
// XCTAssertEqual((note.userInfo as NSDictionary?) ?? [:], NSDictionary())
|
||||
// defer {
|
||||
//
|
||||
// events += 1
|
||||
// }
|
||||
// return events == 3
|
||||
// }
|
||||
// )
|
||||
// let saveExpectation = self.expectation(description: "save")
|
||||
// stack.perform(
|
||||
// asynchronous: { (transaction) -> Bool in
|
||||
//
|
||||
// if let object = try transaction.fetchOne(
|
||||
// From<TestEntity1>(),
|
||||
// Where<TestEntity1>(#keyPath(TestEntity1.testEntityID), isEqualTo: 101)) {
|
||||
//
|
||||
// object.testNumber = NSNumber(value: 11)
|
||||
// object.testDecimal = NSDecimalNumber(string: "11")
|
||||
// object.testString = "nil:TestEntity1:11"
|
||||
// object.testData = ("nil:TestEntity1:11" as NSString).data(using: String.Encoding.utf8.rawValue)!
|
||||
// object.testDate = self.dateFormatter.date(from: "2000-01-11T00:00:00Z")!
|
||||
// }
|
||||
// else {
|
||||
//
|
||||
// XCTFail()
|
||||
// }
|
||||
// if let object = try transaction.fetchOne(
|
||||
// From<TestEntity1>(),
|
||||
// Where<TestEntity1>(#keyPath(TestEntity1.testEntityID), isEqualTo: 102)) {
|
||||
//
|
||||
// object.testNumber = NSNumber(value: 22)
|
||||
// object.testDecimal = NSDecimalNumber(string: "22")
|
||||
// object.testString = "nil:TestEntity1:22"
|
||||
// object.testData = ("nil:TestEntity1:22" as NSString).data(using: String.Encoding.utf8.rawValue)!
|
||||
// object.testDate = self.dateFormatter.date(from: "2000-01-22T00:00:00Z")!
|
||||
// }
|
||||
// else {
|
||||
//
|
||||
// XCTFail()
|
||||
// }
|
||||
// return transaction.hasChanges
|
||||
// },
|
||||
// success: { (hasChanges) in
|
||||
//
|
||||
// XCTAssertTrue(hasChanges)
|
||||
// saveExpectation.fulfill()
|
||||
// },
|
||||
// failure: { _ in
|
||||
//
|
||||
// XCTFail()
|
||||
// }
|
||||
// )
|
||||
// self.waitAndCheckExpectations()
|
||||
// }
|
||||
// }
|
||||
//
|
||||
// @objc
|
||||
// dynamic func test_ThatListObservers_CanReceiveMoveNotifications() {
|
||||
//
|
||||
// self.prepareStack { (stack) in
|
||||
//
|
||||
// self.prepareTestDataForStack(stack)
|
||||
//
|
||||
// let observer = TestListObserver()
|
||||
// let monitor = stack.monitorSectionedList(
|
||||
// From<TestEntity1>(),
|
||||
// SectionBy(#keyPath(TestEntity1.testBoolean)),
|
||||
// OrderBy<TestEntity1>(.ascending(#keyPath(TestEntity1.testBoolean)), .ascending(#keyPath(TestEntity1.testEntityID)))
|
||||
// )
|
||||
// monitor.addObserver(observer)
|
||||
//
|
||||
// var events = 0
|
||||
//
|
||||
// let willChangeExpectation = self.expectation(
|
||||
// forNotification: NSNotification.Name(rawValue: "listMonitorWillChange:"),
|
||||
// object: observer,
|
||||
// handler: { (note) -> Bool in
|
||||
//
|
||||
// XCTAssertEqual(events, 0)
|
||||
// XCTAssertEqual((note.userInfo as NSDictionary?) ?? [:], NSDictionary())
|
||||
// defer {
|
||||
//
|
||||
// events += 1
|
||||
// }
|
||||
// return events == 0
|
||||
// }
|
||||
// )
|
||||
// let didMoveObjectExpectation = self.expectation(
|
||||
// forNotification: NSNotification.Name(rawValue: "listMonitor:didMoveObject:fromIndexPath:toIndexPath:"),
|
||||
// object: observer,
|
||||
// handler: { (note) -> Bool in
|
||||
//
|
||||
// XCTAssertEqual(events, 1)
|
||||
//
|
||||
// let userInfo = note.userInfo
|
||||
// XCTAssertNotNil(userInfo)
|
||||
// XCTAssertEqual(
|
||||
// Set(userInfo?.keys.map({ $0 as! String }) ?? []),
|
||||
// ["fromIndexPath", "toIndexPath", "object"]
|
||||
// )
|
||||
//
|
||||
// let fromIndexPath = userInfo?["fromIndexPath"] as? NSIndexPath
|
||||
// XCTAssertEqual(fromIndexPath?.index(atPosition: 0), 0)
|
||||
// XCTAssertEqual(fromIndexPath?.index(atPosition: 1), 0)
|
||||
//
|
||||
// let toIndexPath = userInfo?["toIndexPath"] as? NSIndexPath
|
||||
// XCTAssertEqual(toIndexPath?.index(atPosition: 0), 1)
|
||||
// XCTAssertEqual(toIndexPath?.index(atPosition: 1), 1)
|
||||
//
|
||||
// let object = userInfo?["object"] as? TestEntity1
|
||||
// XCTAssertEqual(object?.testEntityID, NSNumber(value: 102))
|
||||
// XCTAssertEqual(object?.testBoolean, NSNumber(value: true))
|
||||
//
|
||||
// defer {
|
||||
//
|
||||
// events += 1
|
||||
// }
|
||||
// return events == 1
|
||||
// }
|
||||
// )
|
||||
// let didChangeExpectation = self.expectation(
|
||||
// forNotification: NSNotification.Name(rawValue: "listMonitorDidChange:"),
|
||||
// object: observer,
|
||||
// handler: { (note) -> Bool in
|
||||
//
|
||||
// XCTAssertEqual(events, 2)
|
||||
// XCTAssertEqual((note.userInfo as NSDictionary?) ?? [:], NSDictionary())
|
||||
// defer {
|
||||
//
|
||||
// events += 1
|
||||
// }
|
||||
// return events == 2
|
||||
// }
|
||||
// )
|
||||
// let saveExpectation = self.expectation(description: "save")
|
||||
// stack.perform(
|
||||
// asynchronous: { (transaction) -> Bool in
|
||||
//
|
||||
// if let object = try transaction.fetchOne(
|
||||
// From<TestEntity1>(),
|
||||
// Where<TestEntity1>(#keyPath(TestEntity1.testEntityID), isEqualTo: 102)) {
|
||||
//
|
||||
// object.testBoolean = NSNumber(value: true)
|
||||
// }
|
||||
// else {
|
||||
//
|
||||
// XCTFail()
|
||||
// }
|
||||
// return transaction.hasChanges
|
||||
// },
|
||||
// success: { (hasChanges) in
|
||||
//
|
||||
// XCTAssertTrue(hasChanges)
|
||||
// saveExpectation.fulfill()
|
||||
// },
|
||||
// failure: { _ in
|
||||
//
|
||||
// XCTFail()
|
||||
// }
|
||||
// )
|
||||
// self.waitAndCheckExpectations()
|
||||
// }
|
||||
// }
|
||||
//
|
||||
// @objc
|
||||
// dynamic func test_ThatListObservers_CanReceiveDeleteNotifications() {
|
||||
//
|
||||
// self.prepareStack { (stack) in
|
||||
//
|
||||
// self.prepareTestDataForStack(stack)
|
||||
//
|
||||
// let observer = TestListObserver()
|
||||
// let monitor = stack.monitorSectionedList(
|
||||
// From<TestEntity1>(),
|
||||
// SectionBy(#keyPath(TestEntity1.testBoolean)),
|
||||
// OrderBy<TestEntity1>(.ascending(#keyPath(TestEntity1.testBoolean)), .ascending(#keyPath(TestEntity1.testEntityID)))
|
||||
// )
|
||||
// monitor.addObserver(observer)
|
||||
//
|
||||
// var events = 0
|
||||
//
|
||||
// let willChangeExpectation = self.expectation(
|
||||
// forNotification: NSNotification.Name(rawValue: "listMonitorWillChange:"),
|
||||
// object: observer,
|
||||
// handler: { (note) -> Bool in
|
||||
//
|
||||
// XCTAssertEqual(events, 0)
|
||||
// XCTAssertEqual((note.userInfo as NSDictionary?) ?? [:], NSDictionary())
|
||||
// defer {
|
||||
//
|
||||
// events += 1
|
||||
// }
|
||||
// return events == 0
|
||||
// }
|
||||
// )
|
||||
// let didUpdateObjectExpectation = self.expectation(
|
||||
// forNotification: NSNotification.Name(rawValue: "listMonitor:didDeleteObject:fromIndexPath:"),
|
||||
// object: observer,
|
||||
// handler: { (note) -> Bool in
|
||||
//
|
||||
// XCTAssert(events == 1 || events == 2)
|
||||
//
|
||||
// let userInfo = note.userInfo
|
||||
// XCTAssertNotNil(userInfo)
|
||||
// XCTAssertEqual(
|
||||
// Set(userInfo?.keys.map({ $0 as! String }) ?? []),
|
||||
// ["indexPath", "object"]
|
||||
// )
|
||||
//
|
||||
// let indexPath = userInfo?["indexPath"] as? NSIndexPath
|
||||
//
|
||||
// XCTAssertEqual(indexPath?.section, 0)
|
||||
// XCTAssert(indexPath?.index(atPosition: 1) == 0 || indexPath?.index(atPosition: 1) == 1)
|
||||
//
|
||||
// let object = userInfo?["object"] as? TestEntity1
|
||||
// XCTAssertEqual(object?.isDeleted, true)
|
||||
//
|
||||
// defer {
|
||||
//
|
||||
// events += 1
|
||||
// }
|
||||
// return events == 1 || events == 2
|
||||
// }
|
||||
// )
|
||||
// let didDeleteSectionExpectation = self.expectation(
|
||||
// forNotification: NSNotification.Name(rawValue: "listMonitor:didDeleteSection:fromSectionIndex:"),
|
||||
// object: observer,
|
||||
// handler: { (note) -> Bool in
|
||||
//
|
||||
// XCTAssertEqual(events, 3)
|
||||
//
|
||||
// let userInfo = note.userInfo
|
||||
// XCTAssertNotNil(userInfo)
|
||||
// XCTAssertEqual(
|
||||
// Set(userInfo?.keys.map({ $0 as! String }) ?? []),
|
||||
// ["sectionInfo", "sectionIndex"]
|
||||
// )
|
||||
//
|
||||
// let sectionInfo = userInfo?["sectionInfo"] as? NSFetchedResultsSectionInfo
|
||||
// XCTAssertNotNil(sectionInfo)
|
||||
// XCTAssertEqual(sectionInfo?.name, "0")
|
||||
//
|
||||
// let sectionIndex = userInfo?["sectionIndex"]
|
||||
// XCTAssertEqual(sectionIndex as? NSNumber, NSNumber(value: 0))
|
||||
//
|
||||
// defer {
|
||||
//
|
||||
// events += 1
|
||||
// }
|
||||
// return events == 3
|
||||
// }
|
||||
// )
|
||||
// let didChangeExpectation = self.expectation(
|
||||
// forNotification: NSNotification.Name(rawValue: "listMonitorDidChange:"),
|
||||
// object: observer,
|
||||
// handler: { (note) -> Bool in
|
||||
//
|
||||
// XCTAssertEqual(events, 4)
|
||||
// XCTAssertEqual((note.userInfo as NSDictionary?) ?? [:], NSDictionary())
|
||||
// defer {
|
||||
//
|
||||
// events += 1
|
||||
// }
|
||||
// return events == 4
|
||||
// }
|
||||
// )
|
||||
// let saveExpectation = self.expectation(description: "save")
|
||||
// stack.perform(
|
||||
// asynchronous: { (transaction) -> Bool in
|
||||
//
|
||||
// let count = try transaction.deleteAll(
|
||||
// From<TestEntity1>(),
|
||||
// Where<TestEntity1>(#keyPath(TestEntity1.testBoolean), isEqualTo: false)
|
||||
// )
|
||||
// XCTAssertEqual(count, 2)
|
||||
// return transaction.hasChanges
|
||||
// },
|
||||
// success: { (hasChanges) in
|
||||
//
|
||||
// XCTAssertTrue(hasChanges)
|
||||
// saveExpectation.fulfill()
|
||||
// },
|
||||
// failure: { _ in
|
||||
//
|
||||
// XCTFail()
|
||||
// }
|
||||
// )
|
||||
// self.waitAndCheckExpectations()
|
||||
// }
|
||||
// }
|
||||
//}
|
||||
//
|
||||
//
|
||||
//// MARK: TestListObserver
|
||||
//
|
||||
//@available(macOS 10.12, *)
|
||||
//class TestListObserver: ListSectionObserver {
|
||||
//
|
||||
// // MARK: ListObserver
|
||||
//
|
||||
// typealias ListEntityType = TestEntity1
|
||||
//
|
||||
// func listMonitorWillChange(_ monitor: ListMonitor<TestEntity1>) {
|
||||
//
|
||||
// NotificationCenter.default.post(
|
||||
// name: Notification.Name(rawValue: "listMonitorWillChange:"),
|
||||
// object: self,
|
||||
// userInfo: [:]
|
||||
// )
|
||||
// }
|
||||
//
|
||||
// func listMonitorDidChange(_ monitor: ListMonitor<TestEntity1>) {
|
||||
//
|
||||
// NotificationCenter.default.post(
|
||||
// name: Notification.Name(rawValue: "listMonitorDidChange:"),
|
||||
// object: self,
|
||||
// userInfo: [:]
|
||||
// )
|
||||
// }
|
||||
//
|
||||
// func listMonitorWillRefetch(_ monitor: ListMonitor<TestEntity1>) {
|
||||
//
|
||||
// NotificationCenter.default.post(
|
||||
// name: Notification.Name(rawValue: "listMonitorWillRefetch:"),
|
||||
// object: self,
|
||||
// userInfo: [:]
|
||||
// )
|
||||
// }
|
||||
//
|
||||
// func listMonitorDidRefetch(_ monitor: ListMonitor<TestEntity1>) {
|
||||
//
|
||||
// NotificationCenter.default.post(
|
||||
// name: Notification.Name(rawValue: "listMonitorDidRefetch:"),
|
||||
// object: self,
|
||||
// userInfo: [:]
|
||||
// )
|
||||
// }
|
||||
//
|
||||
//
|
||||
// // MARK: ListObjectObserver
|
||||
//
|
||||
// func listMonitor(_ monitor: ListMonitor<TestEntity1>, didInsertObject object: TestEntity1, toIndexPath indexPath: IndexPath) {
|
||||
//
|
||||
// NotificationCenter.default.post(
|
||||
// name: Notification.Name(rawValue: "listMonitor:didInsertObject:toIndexPath:"),
|
||||
// object: self,
|
||||
// userInfo: [
|
||||
// "object": object,
|
||||
// "indexPath": indexPath
|
||||
// ]
|
||||
// )
|
||||
// }
|
||||
//
|
||||
// func listMonitor(_ monitor: ListMonitor<TestEntity1>, didDeleteObject object: TestEntity1, fromIndexPath indexPath: IndexPath) {
|
||||
//
|
||||
// NotificationCenter.default.post(
|
||||
// name: Notification.Name(rawValue: "listMonitor:didDeleteObject:fromIndexPath:"),
|
||||
// object: self,
|
||||
// userInfo: [
|
||||
// "object": object,
|
||||
// "indexPath": indexPath
|
||||
// ]
|
||||
// )
|
||||
// }
|
||||
//
|
||||
// func listMonitor(_ monitor: ListMonitor<TestEntity1>, didUpdateObject object: TestEntity1, atIndexPath indexPath: IndexPath) {
|
||||
//
|
||||
// NotificationCenter.default.post(
|
||||
// name: Notification.Name(rawValue: "listMonitor:didUpdateObject:atIndexPath:"),
|
||||
// object: self,
|
||||
// userInfo: [
|
||||
// "object": object,
|
||||
// "indexPath": indexPath
|
||||
// ]
|
||||
// )
|
||||
// }
|
||||
//
|
||||
//
|
||||
// func listMonitor(_ monitor: ListMonitor<TestEntity1>, didMoveObject object: TestEntity1, fromIndexPath: IndexPath, toIndexPath: IndexPath) {
|
||||
//
|
||||
// NotificationCenter.default.post(
|
||||
// name: Notification.Name(rawValue: "listMonitor:didMoveObject:fromIndexPath:toIndexPath:"),
|
||||
// object: self,
|
||||
// userInfo: [
|
||||
// "object": object,
|
||||
// "fromIndexPath": fromIndexPath,
|
||||
// "toIndexPath": toIndexPath
|
||||
// ]
|
||||
// )
|
||||
// }
|
||||
//
|
||||
//
|
||||
// // MARK: ListSectionObserver
|
||||
//
|
||||
// func listMonitor(_ monitor: ListMonitor<TestEntity1>, didInsertSection sectionInfo: NSFetchedResultsSectionInfo, toSectionIndex sectionIndex: Int) {
|
||||
//
|
||||
// NotificationCenter.default.post(
|
||||
// name: Notification.Name(rawValue: "listMonitor:didInsertSection:toSectionIndex:"),
|
||||
// object: self,
|
||||
// userInfo: [
|
||||
// "sectionInfo": sectionInfo,
|
||||
// "sectionIndex": sectionIndex
|
||||
// ]
|
||||
// )
|
||||
// }
|
||||
//
|
||||
// func listMonitor(_ monitor: ListMonitor<TestEntity1>, didDeleteSection sectionInfo: NSFetchedResultsSectionInfo, fromSectionIndex sectionIndex: Int) {
|
||||
//
|
||||
// NotificationCenter.default.post(
|
||||
// name: Notification.Name(rawValue: "listMonitor:didDeleteSection:fromSectionIndex:"),
|
||||
// object: self,
|
||||
// userInfo: [
|
||||
// "sectionInfo": sectionInfo,
|
||||
// "sectionIndex": sectionIndex
|
||||
// ]
|
||||
// )
|
||||
// }
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
@@ -179,7 +179,7 @@ final class OrderByTests: XCTestCase {
|
||||
dynamic func test_ThatOrderByClauses_ApplyToFetchRequestsCorrectly() {
|
||||
|
||||
let orderBy = OrderBy<NSManagedObject>(.ascending("key"))
|
||||
let request = CoreStoreFetchRequest<NSFetchRequestResult>()
|
||||
let request = Internals.CoreStoreFetchRequest<NSFetchRequestResult>()
|
||||
orderBy.applyToFetchRequest(request)
|
||||
XCTAssertNotNil(request.sortDescriptors)
|
||||
XCTAssertEqual(request.sortDescriptors ?? [], orderBy.sortDescriptors)
|
||||
|
||||
@@ -39,7 +39,7 @@ class SetupTests: BaseTestDataTestCase {
|
||||
let schemaHistory = SchemaHistory(
|
||||
XcodeDataModelSchema.from(
|
||||
modelName: "Model",
|
||||
bundle: Bundle(for: type(of: self))
|
||||
bundle: Bundle(for: Self.self)
|
||||
)
|
||||
)
|
||||
let stack = DataStack(schemaHistory: schemaHistory)
|
||||
@@ -56,9 +56,6 @@ class SetupTests: BaseTestDataTestCase {
|
||||
XCTAssertTrue(stack.schemaHistory.migrationChain.isEmpty)
|
||||
XCTAssertTrue(stack.schemaHistory.migrationChain.rootVersions.isEmpty)
|
||||
XCTAssertTrue(stack.schemaHistory.migrationChain.leafVersions.isEmpty)
|
||||
|
||||
CoreStore.defaultStack = stack
|
||||
XCTAssertEqual(CoreStore.defaultStack, stack)
|
||||
}
|
||||
do {
|
||||
|
||||
@@ -68,15 +65,12 @@ class SetupTests: BaseTestDataTestCase {
|
||||
|
||||
DataStack(
|
||||
xcodeModelName: "Model",
|
||||
bundle: Bundle(for: type(of: self)),
|
||||
bundle: Bundle(for: Self.self),
|
||||
migrationChain: migrationChain
|
||||
)
|
||||
}
|
||||
XCTAssertEqual(stack.modelVersion, "Model")
|
||||
XCTAssertEqual(stack.schemaHistory.migrationChain, migrationChain)
|
||||
|
||||
CoreStore.defaultStack = stack
|
||||
XCTAssertEqual(CoreStore.defaultStack, stack)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -85,7 +79,7 @@ class SetupTests: BaseTestDataTestCase {
|
||||
|
||||
let stack = DataStack(
|
||||
xcodeModelName: "Model",
|
||||
bundle: Bundle(for: type(of: self))
|
||||
bundle: Bundle(for: Self.self)
|
||||
)
|
||||
do {
|
||||
|
||||
@@ -140,7 +134,7 @@ class SetupTests: BaseTestDataTestCase {
|
||||
|
||||
let stack = DataStack(
|
||||
xcodeModelName: "Model",
|
||||
bundle: Bundle(for: type(of: self))
|
||||
bundle: Bundle(for: Self.self)
|
||||
)
|
||||
do {
|
||||
|
||||
@@ -208,7 +202,7 @@ class SetupTests: BaseTestDataTestCase {
|
||||
|
||||
let stack = DataStack(
|
||||
xcodeModelName: "Model",
|
||||
bundle: Bundle(for: type(of: self))
|
||||
bundle: Bundle(for: Self.self)
|
||||
)
|
||||
try! stack.addStorageAndWait(sqliteStore)
|
||||
self.prepareTestDataForStack(stack)
|
||||
@@ -227,7 +221,7 @@ class SetupTests: BaseTestDataTestCase {
|
||||
let metadata = try createStore()
|
||||
let stack = DataStack(
|
||||
xcodeModelName: "Model",
|
||||
bundle: Bundle(for: type(of: self))
|
||||
bundle: Bundle(for: Self.self)
|
||||
)
|
||||
try sqliteStore.cs_eraseStorageAndWait(
|
||||
metadata: metadata,
|
||||
@@ -260,7 +254,7 @@ class SetupTests: BaseTestDataTestCase {
|
||||
|
||||
let stack = DataStack(
|
||||
xcodeModelName: "Model",
|
||||
bundle: Bundle(for: type(of: self))
|
||||
bundle: Bundle(for: Self.self)
|
||||
)
|
||||
do {
|
||||
|
||||
@@ -328,7 +322,7 @@ class SetupTests: BaseTestDataTestCase {
|
||||
|
||||
let stack = DataStack(
|
||||
xcodeModelName: "Model",
|
||||
bundle: Bundle(for: type(of: self))
|
||||
bundle: Bundle(for: Self.self)
|
||||
)
|
||||
try! stack.addStorageAndWait(
|
||||
SQLiteStore.legacy(
|
||||
@@ -354,7 +348,7 @@ class SetupTests: BaseTestDataTestCase {
|
||||
let metadata = try createStore()
|
||||
let stack = DataStack(
|
||||
xcodeModelName: "Model",
|
||||
bundle: Bundle(for: type(of: self))
|
||||
bundle: Bundle(for: Self.self)
|
||||
)
|
||||
try sqliteStore.cs_eraseStorageAndWait(
|
||||
metadata: metadata,
|
||||
|
||||
@@ -112,7 +112,7 @@ final class StorageInterfaceTests: XCTestCase {
|
||||
.appendingPathExtension("db")
|
||||
let mappingProvider = XcodeSchemaMappingProvider(
|
||||
from: "V1", to: "V2",
|
||||
mappingModelBundle: Bundle(for: type(of: self))
|
||||
mappingModelBundle: Bundle(for: Self.self)
|
||||
)
|
||||
|
||||
let store = SQLiteStore(
|
||||
@@ -150,7 +150,7 @@ final class StorageInterfaceTests: XCTestCase {
|
||||
let fileName = UUID().uuidString + ".db"
|
||||
let mappingProvider = XcodeSchemaMappingProvider(
|
||||
from: "V1", to: "V2",
|
||||
mappingModelBundle: Bundle(for: type(of: self))
|
||||
mappingModelBundle: Bundle(for: Self.self)
|
||||
)
|
||||
let store = SQLiteStore(
|
||||
fileName: fileName,
|
||||
@@ -236,7 +236,7 @@ final class StorageInterfaceTests: XCTestCase {
|
||||
let fileName = UUID().uuidString + ".db"
|
||||
let mappingProvider = XcodeSchemaMappingProvider(
|
||||
from: "V1", to: "V2",
|
||||
mappingModelBundle: Bundle(for: type(of: self))
|
||||
mappingModelBundle: Bundle(for: Self.self)
|
||||
)
|
||||
let store = SQLiteStore.legacy(
|
||||
fileName: fileName,
|
||||
|
||||
@@ -43,7 +43,7 @@ final class TweakTests: XCTestCase {
|
||||
$0.fetchLimit = 200
|
||||
$0.predicate = predicate
|
||||
}
|
||||
let request = CoreStoreFetchRequest<NSFetchRequestResult>()
|
||||
let request = Internals.CoreStoreFetchRequest<NSFetchRequestResult>()
|
||||
tweak.applyToFetchRequest(request)
|
||||
XCTAssertEqual(request.fetchOffset, 100)
|
||||
XCTAssertEqual(request.fetchLimit, 200)
|
||||
|
||||
55
CoreStoreTests/VersionLockTests.swift
Normal file
55
CoreStoreTests/VersionLockTests.swift
Normal file
@@ -0,0 +1,55 @@
|
||||
//
|
||||
// VersionLockTests.swift
|
||||
// CoreStore
|
||||
//
|
||||
// Copyright © 2018 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: - VersionLockTests
|
||||
|
||||
final class VersionLockTests: XCTestCase {
|
||||
|
||||
@objc
|
||||
dynamic func test_ThatVersionLocksProduceCorrectHashes() {
|
||||
|
||||
let versionLock: VersionLock = [
|
||||
"Animal": [0x1b59d511019695cf, 0xdeb97e86c5eff179, 0x1cfd80745646cb3, 0x4ff99416175b5b9a],
|
||||
"Dog": [0xe3f0afeb109b283a, 0x29998d292938eb61, 0x6aab788333cfc2a3, 0x492ff1d295910ea7],
|
||||
"Person": [0x2831cf046084d96d, 0xbe19b13ace54641, 0x635a082728b0f6f0, 0x3d4ef2dd4b74a87c]
|
||||
]
|
||||
XCTAssertEqual(
|
||||
versionLock.description,
|
||||
"""
|
||||
[
|
||||
"Animal": [0x1b59d511019695cf, 0xdeb97e86c5eff179, 0x1cfd80745646cb3, 0x4ff99416175b5b9a],
|
||||
"Dog": [0xe3f0afeb109b283a, 0x29998d292938eb61, 0x6aab788333cfc2a3, 0x492ff1d295910ea7],
|
||||
"Person": [0x2831cf046084d96d, 0xbe19b13ace54641, 0x635a082728b0f6f0, 0x3d4ef2dd4b74a87c]
|
||||
]
|
||||
"""
|
||||
)
|
||||
}
|
||||
}
|
||||
@@ -31,12 +31,12 @@ import CoreStore
|
||||
|
||||
// MARK: - XCTAssertAllEqual
|
||||
|
||||
private func XCTAssertAllEqual<D>(_ whereClauses: Where<D>...) {
|
||||
private func XCTAssertAllEqual<O>(_ whereClauses: Where<O>...) {
|
||||
|
||||
XCTAssertAllEqual(whereClauses)
|
||||
}
|
||||
|
||||
private func XCTAssertAllEqual<D>(_ whereClauses: [Where<D>]) {
|
||||
private func XCTAssertAllEqual<O>(_ whereClauses: [Where<O>]) {
|
||||
|
||||
for i in whereClauses.indices {
|
||||
|
||||
@@ -47,6 +47,17 @@ private func XCTAssertAllEqual<D>(_ whereClauses: [Where<D>]) {
|
||||
}
|
||||
}
|
||||
|
||||
private func XCTAssertAllEqual<D: Equatable>(_ items: D...) {
|
||||
|
||||
for i in items.indices {
|
||||
|
||||
for j in items.indices where j != i {
|
||||
|
||||
XCTAssertEqual(items[i], items[j])
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
//MARK: - WhereTests
|
||||
|
||||
@@ -55,8 +66,8 @@ final class WhereTests: XCTestCase {
|
||||
@objc
|
||||
dynamic func test_ThatDynamicModelKeyPaths_CanBeCreated() {
|
||||
|
||||
XCTAssertEqual(String(keyPath: \TestEntity1.testEntityID), "testEntityID")
|
||||
XCTAssertEqual(String(keyPath: \Animal.color), "color")
|
||||
XCTAssertAllEqual(String(keyPath: \TestEntity1.testEntityID), "testEntityID")
|
||||
XCTAssertAllEqual(String(keyPath: \Animal.color), "color")
|
||||
}
|
||||
|
||||
@objc
|
||||
@@ -66,17 +77,24 @@ final class WhereTests: XCTestCase {
|
||||
|
||||
do {
|
||||
|
||||
XCTAssertEqual(
|
||||
// let keyPathBuilder = TestEntity1.keyPathBuilder()
|
||||
|
||||
// let kp = \TestEntity1.testToOne
|
||||
// print(keyPathBuilder.testString)
|
||||
// print(keyPathBuilder.testToOne)
|
||||
// print(keyPathBuilder.testToOne.testEntityID)
|
||||
XCTAssertAllEqual(
|
||||
#keyPath(TestEntity1.testToOne.testEntityID),
|
||||
(\TestEntity1.testToOne ~ \.testEntityID).description,
|
||||
String(keyPath: \TestEntity1.testToOne ~ \.testEntityID)
|
||||
// keyPathBuilder.testToOne.testEntityID.keyPathString
|
||||
)
|
||||
XCTAssertEqual(
|
||||
XCTAssertAllEqual(
|
||||
#keyPath(TestEntity1.testToOne.testToOne.testToManyUnordered),
|
||||
(\TestEntity1.testToOne ~ \.testToOne ~ \.testToManyUnordered).description,
|
||||
String(keyPath: \TestEntity1.testToOne ~ \.testToOne ~ \.testToManyUnordered)
|
||||
)
|
||||
XCTAssertEqual(
|
||||
XCTAssertAllEqual(
|
||||
#keyPath(TestEntity2.testToOne.testToOne.testToManyOrdered),
|
||||
(\TestEntity2.testToOne ~ \.testToOne ~ \.testToManyOrdered).description,
|
||||
String(keyPath: \TestEntity2.testToOne ~ \.testToOne ~ \.testToManyOrdered)
|
||||
@@ -84,17 +102,17 @@ final class WhereTests: XCTestCase {
|
||||
}
|
||||
do {
|
||||
|
||||
XCTAssertEqual(
|
||||
XCTAssertAllEqual(
|
||||
"master.pets",
|
||||
(\Animal.master ~ \.pets).description,
|
||||
String(keyPath: \Animal.master ~ \.pets)
|
||||
)
|
||||
XCTAssertEqual(
|
||||
XCTAssertAllEqual(
|
||||
"master.pets.species",
|
||||
(\Animal.master ~ \.pets ~ \.species).description,
|
||||
String(keyPath: \Animal.master ~ \.pets ~ \.species)
|
||||
)
|
||||
XCTAssertEqual(
|
||||
XCTAssertAllEqual(
|
||||
"master.pets.master",
|
||||
(\Animal.master ~ \.pets ~ \.master).description,
|
||||
String(keyPath: \Animal.master ~ \.pets ~ \.master)
|
||||
@@ -105,12 +123,12 @@ final class WhereTests: XCTestCase {
|
||||
|
||||
do {
|
||||
|
||||
XCTAssertEqual(
|
||||
XCTAssertAllEqual(
|
||||
#keyPath(TestEntity1.testToOne.testToManyUnordered) + ".@count",
|
||||
(\TestEntity1.testToOne ~ \.testToManyUnordered).count().description,
|
||||
String(keyPath: (\TestEntity1.testToOne ~ \.testToManyUnordered).count())
|
||||
)
|
||||
XCTAssertEqual(
|
||||
XCTAssertAllEqual(
|
||||
#keyPath(TestEntity2.testToOne.testToOne.testToManyOrdered) + ".@count",
|
||||
(\TestEntity2.testToOne ~ \.testToOne ~ \.testToManyOrdered).count().description,
|
||||
String(keyPath: (\TestEntity2.testToOne ~ \.testToOne ~ \.testToManyOrdered).count())
|
||||
@@ -118,7 +136,7 @@ final class WhereTests: XCTestCase {
|
||||
}
|
||||
do {
|
||||
|
||||
XCTAssertEqual(
|
||||
XCTAssertAllEqual(
|
||||
"master.pets.@count",
|
||||
(\Animal.master ~ \.pets).count().description,
|
||||
String(keyPath: (\Animal.master ~ \.pets).count())
|
||||
@@ -129,12 +147,12 @@ final class WhereTests: XCTestCase {
|
||||
|
||||
do {
|
||||
|
||||
XCTAssertEqual(
|
||||
XCTAssertAllEqual(
|
||||
"ANY " + #keyPath(TestEntity1.testToOne.testToManyUnordered),
|
||||
(\TestEntity1.testToOne ~ \.testToManyUnordered).any().description,
|
||||
String(keyPath: (\TestEntity1.testToOne ~ \.testToManyUnordered).any())
|
||||
)
|
||||
XCTAssertEqual(
|
||||
XCTAssertAllEqual(
|
||||
"ANY " + #keyPath(TestEntity2.testToOne.testToOne.testToManyOrdered),
|
||||
(\TestEntity2.testToOne ~ \.testToOne ~ \.testToManyOrdered).any().description,
|
||||
String(keyPath: (\TestEntity2.testToOne ~ \.testToOne ~ \.testToManyOrdered).any())
|
||||
@@ -142,12 +160,12 @@ final class WhereTests: XCTestCase {
|
||||
}
|
||||
do {
|
||||
|
||||
XCTAssertEqual(
|
||||
XCTAssertAllEqual(
|
||||
"ANY master.pets",
|
||||
(\Animal.master ~ \.pets).any().description,
|
||||
String(keyPath: (\Animal.master ~ \.pets).any())
|
||||
)
|
||||
XCTAssertEqual(
|
||||
XCTAssertAllEqual(
|
||||
"ANY master.pets.species",
|
||||
(\Animal.master ~ \.pets ~ \.species).any().description,
|
||||
String(keyPath: (\Animal.master ~ \.pets ~ \.species).any())
|
||||
@@ -158,12 +176,12 @@ final class WhereTests: XCTestCase {
|
||||
|
||||
do {
|
||||
|
||||
XCTAssertEqual(
|
||||
XCTAssertAllEqual(
|
||||
"ALL " + #keyPath(TestEntity1.testToOne.testToManyUnordered),
|
||||
(\TestEntity1.testToOne ~ \.testToManyUnordered).all().description,
|
||||
String(keyPath: (\TestEntity1.testToOne ~ \.testToManyUnordered).all())
|
||||
)
|
||||
XCTAssertEqual(
|
||||
XCTAssertAllEqual(
|
||||
"ALL " + #keyPath(TestEntity2.testToOne.testToOne.testToManyOrdered),
|
||||
(\TestEntity2.testToOne ~ \.testToOne ~ \.testToManyOrdered).all().description,
|
||||
String(keyPath: (\TestEntity2.testToOne ~ \.testToOne ~ \.testToManyOrdered).all())
|
||||
@@ -171,12 +189,12 @@ final class WhereTests: XCTestCase {
|
||||
}
|
||||
do {
|
||||
|
||||
XCTAssertEqual(
|
||||
XCTAssertAllEqual(
|
||||
"ALL master.pets",
|
||||
(\Animal.master ~ \.pets).all().description,
|
||||
String(keyPath: (\Animal.master ~ \.pets).all())
|
||||
)
|
||||
XCTAssertEqual(
|
||||
XCTAssertAllEqual(
|
||||
"ALL master.pets.species",
|
||||
(\Animal.master ~ \.pets ~ \.species).all().description,
|
||||
String(keyPath: (\Animal.master ~ \.pets ~ \.species).all())
|
||||
@@ -187,12 +205,12 @@ final class WhereTests: XCTestCase {
|
||||
|
||||
do {
|
||||
|
||||
XCTAssertEqual(
|
||||
XCTAssertAllEqual(
|
||||
"NONE " + #keyPath(TestEntity1.testToOne.testToManyUnordered),
|
||||
(\TestEntity1.testToOne ~ \.testToManyUnordered).none().description,
|
||||
String(keyPath: (\TestEntity1.testToOne ~ \.testToManyUnordered).none())
|
||||
)
|
||||
XCTAssertEqual(
|
||||
XCTAssertAllEqual(
|
||||
"NONE " + #keyPath(TestEntity2.testToOne.testToOne.testToManyOrdered),
|
||||
(\TestEntity2.testToOne ~ \.testToOne ~ \.testToManyOrdered).none().description,
|
||||
String(keyPath: (\TestEntity2.testToOne ~ \.testToOne ~ \.testToManyOrdered).none())
|
||||
@@ -200,12 +218,12 @@ final class WhereTests: XCTestCase {
|
||||
}
|
||||
do {
|
||||
|
||||
XCTAssertEqual(
|
||||
XCTAssertAllEqual(
|
||||
"NONE master.pets",
|
||||
(\Animal.master ~ \.pets).none().description,
|
||||
String(keyPath: (\Animal.master ~ \.pets).none())
|
||||
)
|
||||
XCTAssertEqual(
|
||||
XCTAssertAllEqual(
|
||||
"NONE master.pets.species",
|
||||
(\Animal.master ~ \.pets ~ \.species).none().description,
|
||||
String(keyPath: (\Animal.master ~ \.pets ~ \.species).none())
|
||||
@@ -224,15 +242,15 @@ final class WhereTests: XCTestCase {
|
||||
|
||||
let whereClause: Where<TestEntity1> = (\.testToOne ~ \.testString) == dummy
|
||||
let predicate = NSPredicate(format: "\(#keyPath(TestEntity1.testToOne.testString)) == %@", dummy)
|
||||
XCTAssertEqual(whereClause, Where<TestEntity1>(predicate))
|
||||
XCTAssertEqual(whereClause.predicate, predicate)
|
||||
XCTAssertAllEqual(whereClause, Where<TestEntity1>(predicate))
|
||||
XCTAssertAllEqual(whereClause.predicate, predicate)
|
||||
}
|
||||
do {
|
||||
|
||||
let whereClause: Where<Animal> = (\.master ~ \.name) == dummy
|
||||
let predicate = NSPredicate(format: "master.name == %@", dummy)
|
||||
XCTAssertEqual(whereClause, Where<Animal>(predicate))
|
||||
XCTAssertEqual(whereClause.predicate, predicate)
|
||||
XCTAssertAllEqual(whereClause, Where<Animal>(predicate))
|
||||
XCTAssertAllEqual(whereClause.predicate, predicate)
|
||||
}
|
||||
}
|
||||
do {
|
||||
@@ -242,15 +260,15 @@ final class WhereTests: XCTestCase {
|
||||
|
||||
let whereClause: Where<TestEntity1> = (\.testToOne ~ \.testToOne ~ \.testString) == dummy
|
||||
let predicate = NSPredicate(format: "\(#keyPath(TestEntity1.testToOne.testToOne.testString)) == %@", dummy)
|
||||
XCTAssertEqual(whereClause, Where<TestEntity1>(predicate))
|
||||
XCTAssertEqual(whereClause.predicate, predicate)
|
||||
XCTAssertAllEqual(whereClause, Where<TestEntity1>(predicate))
|
||||
XCTAssertAllEqual(whereClause.predicate, predicate)
|
||||
}
|
||||
do {
|
||||
|
||||
let whereClause: Where<Animal> = (\.master ~ \.spouse ~ \.name) == dummy
|
||||
let predicate = NSPredicate(format: "master.spouse.name == %@", dummy)
|
||||
XCTAssertEqual(whereClause, Where<Animal>(predicate))
|
||||
XCTAssertEqual(whereClause.predicate, predicate)
|
||||
XCTAssertAllEqual(whereClause, Where<Animal>(predicate))
|
||||
XCTAssertAllEqual(whereClause.predicate, predicate)
|
||||
}
|
||||
}
|
||||
do {
|
||||
@@ -260,15 +278,15 @@ final class WhereTests: XCTestCase {
|
||||
|
||||
let whereClause: Where<TestEntity1> = (\.testToOne ~ \.testToManyUnordered).count() == count
|
||||
let predicate = NSPredicate(format: "\(#keyPath(TestEntity1.testToOne.testToManyUnordered)).@count == %d", count)
|
||||
XCTAssertEqual(whereClause, Where<TestEntity1>(predicate))
|
||||
XCTAssertEqual(whereClause.predicate, predicate)
|
||||
XCTAssertAllEqual(whereClause, Where<TestEntity1>(predicate))
|
||||
XCTAssertAllEqual(whereClause.predicate, predicate)
|
||||
}
|
||||
do {
|
||||
|
||||
let whereClause: Where<Animal> = (\.master ~ \.pets).count() == count
|
||||
let predicate = NSPredicate(format: "master.pets.@count == %d", count)
|
||||
XCTAssertEqual(whereClause, Where<Animal>(predicate))
|
||||
XCTAssertEqual(whereClause.predicate, predicate)
|
||||
XCTAssertAllEqual(whereClause, Where<Animal>(predicate))
|
||||
XCTAssertAllEqual(whereClause.predicate, predicate)
|
||||
}
|
||||
}
|
||||
do {
|
||||
@@ -278,15 +296,15 @@ final class WhereTests: XCTestCase {
|
||||
|
||||
let whereClause: Where<TestEntity1> = (\.testToOne ~ \.testToManyUnordered ~ \TestEntity1.testString).any() == dummy
|
||||
let predicate = NSPredicate(format: "ANY \(#keyPath(TestEntity1.testToOne.testToManyUnordered)).\(#keyPath(TestEntity1.testString)) == %@", dummy)
|
||||
XCTAssertEqual(whereClause, Where<TestEntity1>(predicate))
|
||||
XCTAssertEqual(whereClause.predicate, predicate)
|
||||
XCTAssertAllEqual(whereClause, Where<TestEntity1>(predicate))
|
||||
XCTAssertAllEqual(whereClause.predicate, predicate)
|
||||
}
|
||||
do {
|
||||
|
||||
let whereClause: Where<Animal> = (\.master ~ \.pets ~ \.species).any() == dummy
|
||||
let predicate = NSPredicate(format: "ANY master.pets.species == %@", dummy)
|
||||
XCTAssertEqual(whereClause, Where<Animal>(predicate))
|
||||
XCTAssertEqual(whereClause.predicate, predicate)
|
||||
XCTAssertAllEqual(whereClause, Where<Animal>(predicate))
|
||||
XCTAssertAllEqual(whereClause.predicate, predicate)
|
||||
}
|
||||
}
|
||||
do {
|
||||
@@ -296,15 +314,15 @@ final class WhereTests: XCTestCase {
|
||||
|
||||
let whereClause: Where<TestEntity1> = (\.testToOne ~ \.testToManyUnordered ~ \TestEntity1.testString).all() == dummy
|
||||
let predicate = NSPredicate(format: "ALL \(#keyPath(TestEntity1.testToOne.testToManyUnordered)).\(#keyPath(TestEntity1.testString)) == %@", dummy)
|
||||
XCTAssertEqual(whereClause, Where<TestEntity1>(predicate))
|
||||
XCTAssertEqual(whereClause.predicate, predicate)
|
||||
XCTAssertAllEqual(whereClause, Where<TestEntity1>(predicate))
|
||||
XCTAssertAllEqual(whereClause.predicate, predicate)
|
||||
}
|
||||
do {
|
||||
|
||||
let whereClause: Where<Animal> = (\.master ~ \.pets ~ \.species).all() == dummy
|
||||
let predicate = NSPredicate(format: "ALL master.pets.species == %@", dummy)
|
||||
XCTAssertEqual(whereClause, Where<Animal>(predicate))
|
||||
XCTAssertEqual(whereClause.predicate, predicate)
|
||||
XCTAssertAllEqual(whereClause, Where<Animal>(predicate))
|
||||
XCTAssertAllEqual(whereClause.predicate, predicate)
|
||||
}
|
||||
}
|
||||
do {
|
||||
@@ -314,15 +332,15 @@ final class WhereTests: XCTestCase {
|
||||
|
||||
let whereClause: Where<TestEntity1> = (\.testToOne ~ \.testToManyUnordered ~ \TestEntity1.testString).none() == dummy
|
||||
let predicate = NSPredicate(format: "NONE \(#keyPath(TestEntity1.testToOne.testToManyUnordered)).\(#keyPath(TestEntity1.testString)) == %@", dummy)
|
||||
XCTAssertEqual(whereClause, Where<TestEntity1>(predicate))
|
||||
XCTAssertEqual(whereClause.predicate, predicate)
|
||||
XCTAssertAllEqual(whereClause, Where<TestEntity1>(predicate))
|
||||
XCTAssertAllEqual(whereClause.predicate, predicate)
|
||||
}
|
||||
do {
|
||||
|
||||
let whereClause: Where<Animal> = (\.master ~ \.pets ~ \.species).none() == dummy
|
||||
let predicate = NSPredicate(format: "NONE master.pets.species == %@", dummy)
|
||||
XCTAssertEqual(whereClause, Where<Animal>(predicate))
|
||||
XCTAssertEqual(whereClause.predicate, predicate)
|
||||
XCTAssertAllEqual(whereClause, Where<Animal>(predicate))
|
||||
XCTAssertAllEqual(whereClause.predicate, predicate)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -333,51 +351,51 @@ final class WhereTests: XCTestCase {
|
||||
do {
|
||||
|
||||
let whereClause = Where<NSManagedObject>()
|
||||
XCTAssertEqual(whereClause, Where<NSManagedObject>(true))
|
||||
XCTAssertAllEqual(whereClause, Where<NSManagedObject>(true))
|
||||
XCTAssertNotEqual(whereClause, Where<NSManagedObject>(false))
|
||||
XCTAssertEqual(whereClause.predicate, NSPredicate(value: true))
|
||||
XCTAssertAllEqual(whereClause.predicate, NSPredicate(value: true))
|
||||
}
|
||||
do {
|
||||
|
||||
let whereClause = Where<NSManagedObject>(true)
|
||||
XCTAssertEqual(whereClause, Where<NSManagedObject>())
|
||||
XCTAssertAllEqual(whereClause, Where<NSManagedObject>())
|
||||
XCTAssertNotEqual(whereClause, Where<NSManagedObject>(false))
|
||||
XCTAssertEqual(whereClause.predicate, NSPredicate(value: true))
|
||||
XCTAssertAllEqual(whereClause.predicate, NSPredicate(value: true))
|
||||
}
|
||||
do {
|
||||
|
||||
let predicate = NSPredicate(format: "%K == %@", "key", "value")
|
||||
let whereClause = Where<NSManagedObject>(predicate)
|
||||
XCTAssertEqual(whereClause, Where<NSManagedObject>(predicate))
|
||||
XCTAssertEqual(whereClause.predicate, predicate)
|
||||
XCTAssertAllEqual(whereClause, Where<NSManagedObject>(predicate))
|
||||
XCTAssertAllEqual(whereClause.predicate, predicate)
|
||||
}
|
||||
do {
|
||||
|
||||
let whereClause = Where<NSManagedObject>("%K == %@", "key", "value")
|
||||
let predicate = NSPredicate(format: "%K == %@", "key", "value")
|
||||
XCTAssertEqual(whereClause, Where<NSManagedObject>(predicate))
|
||||
XCTAssertEqual(whereClause.predicate, predicate)
|
||||
XCTAssertAllEqual(whereClause, Where<NSManagedObject>(predicate))
|
||||
XCTAssertAllEqual(whereClause.predicate, predicate)
|
||||
}
|
||||
do {
|
||||
|
||||
let whereClause = Where<NSManagedObject>("%K == %@", argumentArray: ["key", "value"])
|
||||
let predicate = NSPredicate(format: "%K == %@", "key", "value")
|
||||
XCTAssertEqual(whereClause, Where<NSManagedObject>(predicate))
|
||||
XCTAssertEqual(whereClause.predicate, predicate)
|
||||
XCTAssertAllEqual(whereClause, Where<NSManagedObject>(predicate))
|
||||
XCTAssertAllEqual(whereClause.predicate, predicate)
|
||||
}
|
||||
do {
|
||||
|
||||
let whereClause = Where<NSManagedObject>("key", isEqualTo: "value")
|
||||
let predicate = NSPredicate(format: "%K == %@", "key", "value")
|
||||
XCTAssertEqual(whereClause, Where<NSManagedObject>(predicate))
|
||||
XCTAssertEqual(whereClause.predicate, predicate)
|
||||
XCTAssertAllEqual(whereClause, Where<NSManagedObject>(predicate))
|
||||
XCTAssertAllEqual(whereClause.predicate, predicate)
|
||||
}
|
||||
do {
|
||||
|
||||
let whereClause = Where<NSManagedObject>("key", isMemberOf: ["value1", "value2", "value3"])
|
||||
let predicate = NSPredicate(format: "%K IN %@", "key", ["value1", "value2", "value3"])
|
||||
XCTAssertEqual(whereClause, Where<NSManagedObject>(predicate))
|
||||
XCTAssertEqual(whereClause.predicate, predicate)
|
||||
XCTAssertAllEqual(whereClause, Where<NSManagedObject>(predicate))
|
||||
XCTAssertAllEqual(whereClause.predicate, predicate)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -512,8 +530,8 @@ final class WhereTests: XCTestCase {
|
||||
type: .not,
|
||||
subpredicates: [whereClause1.predicate]
|
||||
)
|
||||
XCTAssertEqual(notWhere.predicate, notPredicate)
|
||||
XCTAssertEqual(notWhere, !whereClause1)
|
||||
XCTAssertAllEqual(notWhere.predicate, notPredicate)
|
||||
XCTAssertAllEqual(notWhere, !whereClause1)
|
||||
}
|
||||
do {
|
||||
|
||||
@@ -528,8 +546,8 @@ final class WhereTests: XCTestCase {
|
||||
whereClause3.predicate
|
||||
]
|
||||
)
|
||||
XCTAssertEqual(andWhere.predicate, andPredicate)
|
||||
XCTAssertEqual(andWhere, whereClause1 && whereClause2 && whereClause3)
|
||||
XCTAssertAllEqual(andWhere.predicate, andPredicate)
|
||||
XCTAssertAllEqual(andWhere, whereClause1 && whereClause2 && whereClause3)
|
||||
}
|
||||
do {
|
||||
|
||||
@@ -543,8 +561,8 @@ final class WhereTests: XCTestCase {
|
||||
let unwrappedFinalSomeWhere = andWhere && someWhere!
|
||||
|
||||
|
||||
XCTAssertEqual(andWhere.predicate, finalNoneWhere.predicate)
|
||||
XCTAssertEqual(finalSomeWhere.predicate, unwrappedFinalSomeWhere.predicate)
|
||||
XCTAssertAllEqual(andWhere.predicate, finalNoneWhere.predicate)
|
||||
XCTAssertAllEqual(finalSomeWhere.predicate, unwrappedFinalSomeWhere.predicate)
|
||||
}
|
||||
do {
|
||||
|
||||
@@ -559,8 +577,8 @@ final class WhereTests: XCTestCase {
|
||||
whereClause3.predicate
|
||||
]
|
||||
)
|
||||
XCTAssertEqual(orWhere.predicate, orPredicate)
|
||||
XCTAssertEqual(orWhere, whereClause1 || whereClause2 || whereClause3)
|
||||
XCTAssertAllEqual(orWhere.predicate, orPredicate)
|
||||
XCTAssertAllEqual(orWhere, whereClause1 || whereClause2 || whereClause3)
|
||||
}
|
||||
do {
|
||||
|
||||
@@ -573,8 +591,8 @@ final class WhereTests: XCTestCase {
|
||||
let finalSomeWhere = orWhere &&? someWhere
|
||||
let unwrappedFinalSomeWhere = orWhere && someWhere!
|
||||
|
||||
XCTAssertEqual(orWhere.predicate, finalNoneWhere.predicate)
|
||||
XCTAssertEqual(finalSomeWhere.predicate, unwrappedFinalSomeWhere.predicate)
|
||||
XCTAssertAllEqual(orWhere.predicate, finalNoneWhere.predicate)
|
||||
XCTAssertAllEqual(finalSomeWhere.predicate, unwrappedFinalSomeWhere.predicate)
|
||||
}
|
||||
|
||||
}
|
||||
@@ -583,9 +601,9 @@ final class WhereTests: XCTestCase {
|
||||
dynamic func test_ThatWhereClauses_ApplyToFetchRequestsCorrectly() {
|
||||
|
||||
let whereClause = Where<NSManagedObject>("key", isEqualTo: "value")
|
||||
let request = CoreStoreFetchRequest<NSFetchRequestResult>()
|
||||
let request = Internals.CoreStoreFetchRequest<NSFetchRequestResult>()
|
||||
whereClause.applyToFetchRequest(request)
|
||||
XCTAssertNotNil(request.predicate)
|
||||
XCTAssertEqual(request.predicate, whereClause.predicate)
|
||||
XCTAssertAllEqual(request.predicate, whereClause.predicate)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
// swift-tools-version:4.2
|
||||
// swift-tools-version:5.0
|
||||
//
|
||||
// Package.swift
|
||||
// CoreStore
|
||||
@@ -28,6 +28,9 @@ import PackageDescription
|
||||
|
||||
let package = Package(
|
||||
name: "CoreStore",
|
||||
platforms: [
|
||||
.macOS(.v10_12), .iOS(.v10), .tvOS(.v10), .watchOS(.v3)
|
||||
],
|
||||
products: [
|
||||
.library(name: "CoreStore", type: .static, targets: ["CoreStore"])
|
||||
],
|
||||
@@ -38,6 +41,12 @@ let package = Package(
|
||||
dependencies: [],
|
||||
path: "Sources",
|
||||
exclude: ["CoreStoreBridge.h", "CoreStoreBridge.m"]
|
||||
),
|
||||
.testTarget(
|
||||
name: "CoreStoreTests",
|
||||
dependencies: ["CoreStore"],
|
||||
path: "CoreStoreTests"
|
||||
)
|
||||
]
|
||||
],
|
||||
swiftLanguageVersions: [.v5_1]
|
||||
)
|
||||
|
||||
@@ -0,0 +1,8 @@
|
||||
<?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>IDEDidComputeMac32BitWarning</key>
|
||||
<true/>
|
||||
</dict>
|
||||
</plist>
|
||||
373
README.md
373
README.md
@@ -5,7 +5,7 @@
|
||||
Unleashing the real power of Core Data with the elegance and safety of Swift
|
||||
<br />
|
||||
<br />
|
||||
<a href="https://travis-ci.org/JohnEstropia/CoreStore"><img alt="Build Status" src="https://img.shields.io/travis/JohnEstropia/CoreStore/master.svg?style=flat" /></a>
|
||||
<a href="https://app.bitrise.io/app/e736852157296019#/builds"><img alt="Build Status" src="https://img.shields.io/bitrise/e736852157296019/master.svg?label=build&token=vhgAmaiF3tWZoQyFLkKM7g&logo=bitrise" /></a>
|
||||
<a href="https://github.com/JohnEstropia/CoreStore/commits"><img alt="Last Commit" src="https://img.shields.io/github/last-commit/johnestropia/corestore.svg?style=flat" /></a>
|
||||
<a href="http://cocoadocs.org/docsets/CoreStore"><img alt="Platform" src="https://img.shields.io/cocoapods/p/CoreStore.svg?style=flat" /></a>
|
||||
<a href="https://raw.githubusercontent.com/JohnEstropia/CoreStore/master/LICENSE"><img alt="License" src="https://img.shields.io/cocoapods/l/CoreStore.svg?style=flat" /></a>
|
||||
@@ -14,15 +14,15 @@ Unleashing the real power of Core Data with the elegance and safety of Swift
|
||||
<a href="https://github.com/Carthage/Carthage"><img alt="Carthage compatible" src="https://img.shields.io/badge/Carthage-compatible-16a085.svg?style=flat" /></a>
|
||||
<a href="https://swift.org/source-compatibility/#current-list-of-projects"><img alt="Swift Package Manager compatible" src="https://img.shields.io/badge/Swift_Package_Manager-compatible-orange.svg?style=flat" /></a>
|
||||
<br /><br />Contact<br />
|
||||
<a href="http://swift-corestore-slack.herokuapp.com/"><img alt="Join us on Slack!" src="http://swift-corestore-slack.herokuapp.com/badge.svg" /></a>
|
||||
<a href="https://twitter.com/JohnEstropia"><img alt="Reach me on Twitter!" src="https://img.shields.io/badge/twitter-%40JohnEstropia-3498db.svg" /></a>
|
||||
<a href="http://swift-corestore-slack.herokuapp.com/"><img alt="Join us on Slack!" src="http://swift-corestore-slack.herokuapp.com/badge.svg?logo=slack" /></a>
|
||||
<a href="https://twitter.com/JohnEstropia"><img alt="Reach me on Twitter!" src="https://img.shields.io/badge/twitter-%40JohnEstropia-3498db.svg?logo=twitter" /></a>
|
||||
<br />
|
||||
</p>
|
||||
|
||||
* **Swift 5.0:** iOS 10+ / macOS 10.12+ / watchOS 3.0+ / tvOS 10.0+
|
||||
* Previously supported Swift versions: [Swift 3.2](https://github.com/JohnEstropia/CoreStore/tree/4.2.3), [Swift 4.2](https://github.com/JohnEstropia/CoreStore/tree/6.2.1)
|
||||
* **Swift 5.1:** iOS 10+ / macOS 10.12+ / watchOS 3.0+ / tvOS 10.0+
|
||||
* Previously supported Swift versions: [Swift 3.2](https://github.com/JohnEstropia/CoreStore/tree/4.2.3), [Swift 4.2](https://github.com/JohnEstropia/CoreStore/tree/6.2.1), [Swift 5.0](https://github.com/JohnEstropia/CoreStore/tree/6.3.2)
|
||||
|
||||
Upgrading from CoreStore 5.x (min iOS 9) to 6.x (min iOS 10)? Check out the [new features](#features) and make sure to read the [Change logs](https://github.com/JohnEstropia/CoreStore/releases).
|
||||
Upgrading from CoreStore 6.x (swift 5.0) to 7.x (Swift 5.1)? Check out the [🆕 features](#features) and make sure to read the [Change logs](https://github.com/JohnEstropia/CoreStore/releases).
|
||||
|
||||
CoreStore is now part of the [Swift Source Compatibility projects](https://swift.org/source-compatibility/#current-list-of-projects).
|
||||
|
||||
@@ -33,17 +33,18 @@ CoreStore was (and is) heavily shaped by real-world needs of developing data-dep
|
||||
|
||||
### Features
|
||||
|
||||
- 🆕**Backwards-portable DiffableDataSources implementation!** `UITableViews` and `UICollectionViews` now have a new ally: `ListPublisher`s provide diffable snapshots that make reloading animations very easy and very safe. Say goodbye to `UITableViews` and `UICollectionViews` reload errors!
|
||||
- **💎Tight design around Swift’s code elegance and type safety.** CoreStore fully utilizes Swift's community-driven language features.
|
||||
- **🚦Safer concurrency architecture.** CoreStore makes it hard to fall into common concurrency mistakes. The main `NSManagedObjectContext` is strictly read-only, while all updates are done through serial *transactions*. *(See [Saving and processing transactions](#saving-and-processing-transactions))*
|
||||
- **🔍Clean fetching and querying API.** Fetching objects is easy, but querying for raw aggregates (`min`, `max`, etc.) and raw property values is now just as convenient. *(See [Fetching and querying](#fetching-and-querying))*
|
||||
- **🔭Type-safe, easy to configure observers.** You don't have to deal with the burden of setting up `NSFetchedResultsController`s and KVO. As an added bonus, `ListMonitor`s and `ObjectMonitor`s can have multiple observers. This means you can have multiple view controllers efficiently share a single resource! *(See [Observing changes and notifications](#observing-changes-and-notifications))*
|
||||
- **🔭Type-safe, easy to configure observers.** You don't have to deal with the burden of setting up `NSFetchedResultsController`s and KVO. As an added bonus, list and object observable types all support multiple observers. This means you can have multiple view controllers efficiently share a single resource! *(See [Observing changes and notifications](#observing-changes-and-notifications))*
|
||||
- **📥Efficient importing utilities.** Map your entities once with their corresponding import source (JSON for example), and importing from *transactions* becomes elegant. Uniquing is also done with an efficient find-and-replace algorithm. *(See [Importing data](#importing-data))*
|
||||
- **🗑Say goodbye to *.xcdatamodeld* files!** The new `CoreStoreObject` is *the* replacement to `NSManagedObject`. `CoreStoreObject` subclasses can declare type-safe properties all in Swift code, no need to maintain separate resource files for the models. As bonus, these special properties support custom types, and can be used to create type-safe keypaths and queries. *(See [Type-safe `CoreStoreObject`s](#type-safe-corestoreobjects))*
|
||||
- **🗑Say goodbye to *.xcdatamodeld* files!** While CoreStore supports `NSManagedObject`s, it offers `CoreStoreObject` whose subclasses can declare type-safe properties all in Swift code without the need to maintain separate resource files for the models. As bonus, these special properties support custom types, and can be used to create type-safe keypaths and queries. *(See [Type-safe `CoreStoreObject`s](#type-safe-corestoreobjects))*
|
||||
- **🔗Progressive migrations.** No need to think how to migrate from all previous model versions to your latest model. Just tell the `DataStack` the sequence of version strings (`MigrationChain`s) and CoreStore will automatically use progressive migrations when needed. *(See [Migrations](#migrations))*
|
||||
- **Easier custom migrations.** Say goodbye to *.xcmappingmodel* files; CoreStore can now infer entity mappings when possible, while still allowing an easy way to write custom mappings. *(See [Migrations](#migrations))*
|
||||
- **📝Plug-in your own logging framework.** Although a default logger is built-in, all logging, asserting, and error reporting can be funneled to `CoreStoreLogger` protocol implementations. *(See [Logging and error reporting](#logging-and-error-reporting))*
|
||||
- **⛓Heavy support for multiple persistent stores per data stack.** CoreStore lets you manage separate stores in a single `DataStack`, just the way *.xcdatamodeld* configurations are designed to. CoreStore will also manage one stack by default, but you can create and manage as many as you need. *(See [Setting up](#setting-up))*
|
||||
- **🎯Free to name entities and their class names independently.** CoreStore gets around a restriction with other Core Data wrappers where the entity name should be the same as the `NSManagedObject` subclass name. CoreStore loads entity-to-class mappings from the managed object model file, so you can assign different names for the entities and their class names.
|
||||
- **🎯Free to name entities and their class names independently.** CoreStore gets around a restriction with other Core Data wrappers where the entity name should be the same as the `NSManagedObject` subclass name. CoreStore loads entity-to-class mappings from the managed object model file, so you can assign independent names for the entities and their class names.
|
||||
- **📙Full Documentation.** No magic here; all public classes, functions, properties, etc. have detailed *Apple Docs*. This *README* also introduces a lot of concepts and explains a lot of CoreStore's behavior.
|
||||
- **ℹ️Informative (and pretty) logs.** All CoreStore and Core Data-related types now have very informative and pretty print outputs! *(See [Logging and error reporting](#logging-and-error-reporting))*
|
||||
- **🎗Objective-C support!** Is your project transitioning from Objective-C to Swift but still can't quite fully convert some huge classes to Swift yet? CoreStore adjusts to the ever-increasing Swift adoption. While still written in pure Swift, all CoreStore types have their corresponding Objective-C-visible "bridging classes". *(See [Objective-C support](#objective-c-support))*
|
||||
@@ -87,8 +88,10 @@ CoreStore was (and is) heavily shaped by real-world needs of developing data-dep
|
||||
- [Logging and error reporting](#logging-and-error-reporting)
|
||||
- [Observing changes and notifications](#observing-changes-and-notifications)
|
||||
- [Observe a single property](#observe-a-single-property)
|
||||
- [Observe a single object](#observe-a-single-object)
|
||||
- [Observe a list of objects](#observe-a-list-of-objects)
|
||||
- 🆕[Observe a single object's updates](#observe-a-single-objects-updates)
|
||||
- [Observe a single object's per-property updates](#observe-a-single-objects-per-property-updates)
|
||||
- 🆕[Observe a diffable list](#observe-a-diffable-list)
|
||||
- [Observe detailed list changes](#observe-detailed-list-changes)
|
||||
- [Objective-C support](#objective-c-support)
|
||||
- [Type-safe `CoreStoreObject`s](#type-safe-corestoreobjects)
|
||||
- [`VersionLock`s](#versionlocks)
|
||||
@@ -105,7 +108,7 @@ CoreStore was (and is) heavily shaped by real-world needs of developing data-dep
|
||||
|
||||
Setting-up with progressive migration support:
|
||||
```swift
|
||||
CoreStore.defaultStack = DataStack(
|
||||
dataStack = DataStack(
|
||||
xcodeModelName: "MyStore",
|
||||
migrationChain: ["MyStore", "MyStoreV2", "MyStoreV3"]
|
||||
)
|
||||
@@ -113,7 +116,7 @@ CoreStore.defaultStack = DataStack(
|
||||
|
||||
Adding a store:
|
||||
```swift
|
||||
CoreStore.addStorage(
|
||||
dataStack.addStorage(
|
||||
SQLiteStore(fileName: "MyStore.sqlite"),
|
||||
completion: { (result) -> Void in
|
||||
// ...
|
||||
@@ -123,7 +126,7 @@ CoreStore.addStorage(
|
||||
|
||||
Starting transactions:
|
||||
```swift
|
||||
CoreStore.perform(
|
||||
dataStack.perform(
|
||||
asynchronous: { (transaction) -> Void in
|
||||
let person = transaction.create(Into<MyPersonEntity>())
|
||||
person.name = "John Smith"
|
||||
@@ -140,12 +143,12 @@ CoreStore.perform(
|
||||
|
||||
Fetching objects (simple):
|
||||
```swift
|
||||
let people = try CoreStore.fetchAll(From<MyPersonEntity>())
|
||||
let people = try dataStack.fetchAll(From<MyPersonEntity>())
|
||||
```
|
||||
|
||||
Fetching objects (complex):
|
||||
```swift
|
||||
let people = try CoreStore.fetchAll(
|
||||
let people = try dataStack.fetchAll(
|
||||
From<MyPersonEntity>()
|
||||
.where(\.age > 30),
|
||||
.orderBy(.ascending(\.name), .descending(.\age)),
|
||||
@@ -155,7 +158,7 @@ let people = try CoreStore.fetchAll(
|
||||
|
||||
Querying values:
|
||||
```swift
|
||||
let maxAge = try CoreStore.queryValue(
|
||||
let maxAge = try dataStack.queryValue(
|
||||
From<MyPersonEntity>()
|
||||
.select(Int.self, .maximum(\.age))
|
||||
)
|
||||
@@ -174,15 +177,15 @@ If you are already familiar with the inner workings of CoreData, here is a mappi
|
||||
|
||||
| *Core Data* | *CoreStore* |
|
||||
| --- | --- |
|
||||
| `NSManagedObjectModel` / `NSPersistentStoreCoordinator`<br />(.xcdatamodeld file) | `DataStack` |
|
||||
| `NSPersistentStore`<br />("Configuration"s in the .xcdatamodeld file) | `StorageInterface` implementations<br />(`InMemoryStore`, `SQLiteStore`, `ICloudStore`) |
|
||||
| `NSPersistentContainer`<br />(.xcdatamodeld file) | `DataStack` |
|
||||
| `NSPersistentStoreDescription`<br />("Configuration"s in the .xcdatamodeld file) | `StorageInterface` implementations<br />(`InMemoryStore`, `SQLiteStore`) |
|
||||
| `NSManagedObjectContext` | `BaseDataTransaction` subclasses<br />(`SynchronousDataTransaction`, `AsynchronousDataTransaction`, `UnsafeDataTransaction`) |
|
||||
|
||||
A lot of Core Data wrapper libraries set up their `NSManagedObjectContext`s this way:
|
||||
|
||||
<img src="https://cloud.githubusercontent.com/assets/3029684/16707160/984ef25c-4600-11e6-869f-8db7d2c63668.png" alt="nested contexts" height=380 />
|
||||
|
||||
Nesting saves from child context to the root context ensures maximum data integrity between contexts without blocking the main queue. But <a href="http://floriankugler.com/2013/04/29/concurrent-core-data-stack-performance-shootout/">in reality</a>, merging contexts is still by far faster than saving contexts. CoreStore's `DataStack` takes the best of both worlds by treating the main `NSManagedObjectContext` as a read-only context, and only allows changes to be made within *transactions* on the child context:
|
||||
Nesting saves from child context to the root context ensures maximum data integrity between contexts without blocking the main queue. But <a href="http://floriankugler.com/2013/04/29/concurrent-core-data-stack-performance-shootout/">in reality</a>, merging contexts is still by far faster than saving contexts. CoreStore's `DataStack` takes the best of both worlds by treating the main `NSManagedObjectContext` as a read-only context (or "viewContext"), and only allows changes to be made within *transactions* on the child context:
|
||||
|
||||
<img src="https://cloud.githubusercontent.com/assets/3029684/16707161/9adeb962-4600-11e6-8bc8-4ec85764dba4.png" alt="nested contexts and merge hybrid" height=292 />
|
||||
|
||||
@@ -193,10 +196,10 @@ This allows for a butter-smooth main thread, while still taking advantage of saf
|
||||
## Setting up
|
||||
The simplest way to initialize CoreStore is to add a default store to the default stack:
|
||||
```swift
|
||||
try CoreStore.addStorageAndWait()
|
||||
try CoreStoreDefaults.dataStack.addStorageAndWait()
|
||||
```
|
||||
This one-liner does the following:
|
||||
- Triggers the lazy-initialization of `CoreStore.defaultStack` with a default `DataStack`
|
||||
- Triggers the lazy-initialization of `CoreStoreDefaults.dataStack` with a default `DataStack`
|
||||
- Sets up the stack's `NSPersistentStoreCoordinator`, the root saving `NSManagedObjectContext`, and the read-only main `NSManagedObjectContext`
|
||||
- Adds an `SQLiteStore` in the *"Application Support/<bundle id>"* directory (or the *"Caches/<bundle id>"* directory on tvOS) with the file name *"[App bundle name].sqlite"*
|
||||
- Creates and returns the `NSPersistentStore` instance on success, or an `NSError` on failure
|
||||
@@ -223,13 +226,13 @@ let migrationProgress = dataStack.addStorage(
|
||||
}
|
||||
)
|
||||
|
||||
CoreStore.defaultStack = dataStack // pass the dataStack to CoreStore for easier access later on
|
||||
CoreStoreDefaults.dataStack = dataStack // pass the dataStack to CoreStore for easier access later on
|
||||
```
|
||||
|
||||
> 💡If you have never heard of "Configurations", you'll find them in your *.xcdatamodeld* file
|
||||
> <img src="https://cloud.githubusercontent.com/assets/3029684/8333192/e52cfaac-1acc-11e5-9902-08724f9f1324.png" alt="xcode configurations screenshot" height=212 />
|
||||
|
||||
In our sample code above, note that you don't need to do the `CoreStore.defaultStack = dataStack` line. You can just as well hold a reference to the `DataStack` like below and call all its instance methods directly:
|
||||
In our sample code above, note that you don't need to do the `CoreStoreDefaults.dataStack = dataStack` line. You can just as well hold a reference to the `DataStack` like below and call all its instance methods directly:
|
||||
```swift
|
||||
class MyViewController: UIViewController {
|
||||
let dataStack = DataStack(xcodeModelName: "MyModel") // keep reference to the stack
|
||||
@@ -242,25 +245,7 @@ class MyViewController: UIViewController {
|
||||
}
|
||||
}
|
||||
func methodToBeCalledLaterOn() {
|
||||
let objects = self.dataStack.fetchAll(From(MyEntity))
|
||||
print(objects)
|
||||
}
|
||||
}
|
||||
```
|
||||
The difference is when you set the stack as the `CoreStore.defaultStack`, you can call the stack's methods directly from `CoreStore` itself:
|
||||
```swift
|
||||
class MyViewController: UIViewController {
|
||||
// elsewhere: CoreStore.defaultStack = DataStack(modelName: "MyModel")
|
||||
override func viewDidLoad() {
|
||||
super.viewDidLoad()
|
||||
do {
|
||||
try CoreStore.addStorageAndWait(SQLiteStore.self)
|
||||
}
|
||||
catch { // ...
|
||||
}
|
||||
}
|
||||
func methodToBeCalledLaterOn() {
|
||||
let objects = CoreStore.fetchAll(From<MyEntity>())
|
||||
let objects = self.dataStack.fetchAll(From<MyEntity>())
|
||||
print(objects)
|
||||
}
|
||||
}
|
||||
@@ -268,12 +253,12 @@ class MyViewController: UIViewController {
|
||||
|
||||
> 💡By default, CoreStore will initialize `NSManagedObject`s from *.xcdatamodeld* files, but you can create models completely from source code using `CoreStoreObject`s and `CoreStoreSchema`. To use this feature, refer to [Type-safe `CoreStoreObject`s](#type-safe-corestoreobjects).
|
||||
|
||||
Notice that in our previous examples, `addStorageAndWait(_:)` and `addStorage(_:completion:)` both accept either `InMemoryStore`, `SQLiteStore`, or `ICloudStore`. These implement the `StorageInterface` protocol.
|
||||
Notice that in our previous examples, `addStorageAndWait(_:)` and `addStorage(_:completion:)` both accept either `InMemoryStore`, or `SQLiteStore`. These implement the `StorageInterface` protocol.
|
||||
|
||||
### In-memory store
|
||||
The most basic `StorageInterface` concrete type is the `InMemoryStore`, which just stores objects in memory. Since `InMemoryStore`s always start with a fresh empty data, they do not need any migration information.
|
||||
```swift
|
||||
try CoreStore.addStorageAndWait(
|
||||
try dataStack.addStorageAndWait(
|
||||
InMemoryStore(
|
||||
configuration: "Config2" // optional. Use entities from the "Config2" configuration in the .xcdatamodeld file
|
||||
)
|
||||
@@ -283,7 +268,7 @@ try CoreStore.addStorageAndWait(
|
||||
### Local Store
|
||||
The most common `StorageInterface` you will probably use is the `SQLiteStore`, which saves data in a local SQLite file.
|
||||
```swift
|
||||
let migrationProgress = CoreStore.addStorage(
|
||||
let migrationProgress = dataStack.addStorage(
|
||||
SQLiteStore(
|
||||
fileName: "MyStore.sqlite",
|
||||
configuration: "Config2", // optional. Use entities from the "Config2" configuration in the .xcdatamodeld file
|
||||
@@ -297,7 +282,7 @@ Refer to the *SQLiteStore.swift* source documentation for detailed explanations
|
||||
|
||||
CoreStore can decide the default values for these properties, so `SQLiteStore`s can be initialized with no arguments:
|
||||
```swift
|
||||
try CoreStore.addStorageAndWait(SQLiteStore())
|
||||
try dataStack.addStorageAndWait(SQLiteStore())
|
||||
```
|
||||
|
||||
The file-related properties above are actually requirements of another protocol that `SQLiteStore` implements, the `LocalStorage` protocol:
|
||||
@@ -316,16 +301,7 @@ If you have custom `NSIncrementalStore` or `NSAtomicStore` subclasses, you can i
|
||||
## Migrations
|
||||
|
||||
### Declaring model versions
|
||||
Until CoreStore 4.0, model versions were always assumed to be declared in *.xcdatamodeld* files. The `DataStack` loads these for us by accepting the *.xcdatamodeld* file name and the `Bundle` where the files can be found:
|
||||
```swift
|
||||
CoreStore.defaultStack = DataStack(
|
||||
xcodeModelName: "MyModel",
|
||||
bundle: Bundle.main,
|
||||
migrationChain: ["MyAppModel", "MyAppModelV2", "MyAppModelV3", "MyAppModelV4"]
|
||||
)
|
||||
```
|
||||
|
||||
Starting CoreStore 4.0, model versions are now expressed as a first-class protocol, `DynamicSchema`. CoreStore currently supports the following schema classes:
|
||||
Model versions are now expressed as a first-class protocol, `DynamicSchema`. CoreStore currently supports the following schema classes:
|
||||
- **`XcodeDataModelSchema`**: a model version with entities loaded from a *.xcdatamodeld* file.
|
||||
- **`CoreStoreSchema`**: a model version created with `CoreStoreObject` entities. *(See [Type-safe `CoreStoreObject`s](#type-safe-corestore-objects))*
|
||||
- **`UnsafeDataModelSchema`**: a model version created with an existing `NSManagedObjectModel` instance.
|
||||
@@ -334,7 +310,7 @@ All the `DynamicSchema` for all model versions are then collected within a singl
|
||||
|
||||
**Multiple model versions grouped in a *.xcdatamodeld* file (Core Data standard method)**
|
||||
```swift
|
||||
CoreStore.defaultStack = DataStack(
|
||||
CoreStoreDefaults.dataStack = DataStack(
|
||||
xcodeModelName: "MyModel",
|
||||
bundle: Bundle.main,
|
||||
migrationChain: ["MyAppModel", "MyAppModelV2", "MyAppModelV3", "MyAppModelV4"]
|
||||
@@ -354,7 +330,7 @@ class Person: CoreStoreObject {
|
||||
// ...
|
||||
}
|
||||
|
||||
CoreStore.defaultStack = DataStack(
|
||||
CoreStoreDefaults.dataStack = DataStack(
|
||||
CoreStoreSchema(
|
||||
modelVersion: "V1",
|
||||
entities: [
|
||||
@@ -391,7 +367,7 @@ let newSchema = CoreStoreSchema(
|
||||
Entity<Person>("Person")
|
||||
]
|
||||
)
|
||||
CoreStore.defaultStack = DataStack(
|
||||
CoreStoreDefaults.dataStack = DataStack(
|
||||
schemaHistory: SchemaHistory(
|
||||
legacySchema + [newSchema],
|
||||
migrationChain: ["MyAppModel", "MyAppModelV2", "MyAppModelV3", "MyAppModelV4", "V1"]
|
||||
@@ -427,7 +403,7 @@ enum V1 {
|
||||
}
|
||||
}
|
||||
|
||||
CoreStore.defaultStack = DataStack(
|
||||
CoreStoreDefaults.dataStack = DataStack(
|
||||
CoreStoreSchema(
|
||||
modelVersion: "V1",
|
||||
entities: [
|
||||
@@ -450,7 +426,7 @@ CoreStore.defaultStack = DataStack(
|
||||
|
||||
|
||||
### Starting migrations
|
||||
We have seen `addStorageAndWait(...)` used to initialize our persistent store. As the method name's *~AndWait* suffix suggests though, this method blocks so it should not do long tasks such as store migrations. In fact CoreStore will only attempt a synchronous **lightweight** migration if you explicitly provide the `.allowSynchronousLightweightMigration` option:
|
||||
We have seen `addStorageAndWait(...)` used to initialize our persistent store. As the method name's *~AndWait* suffix suggests though, this method blocks so it should not do long tasks such as data migrations. In fact CoreStore will only attempt a synchronous **lightweight** migration if you explicitly provide the `.allowSynchronousLightweightMigration` option:
|
||||
```swift
|
||||
try dataStack.addStorageAndWait(
|
||||
SQLiteStore(
|
||||
@@ -533,7 +509,7 @@ Sometimes migrations are huge and you may want prior information so your app cou
|
||||
```swift
|
||||
do {
|
||||
let storage = SQLiteStorage(fileName: "MyStore.sqlite")
|
||||
let migrationTypes: [MigrationType] = try CoreStore.requiredMigrationsForStorage(storage)
|
||||
let migrationTypes: [MigrationType] = try dataStack.requiredMigrationsForStorage(storage)
|
||||
if migrationTypes.count > 1
|
||||
|| (migrationTypes.filter { $0.isHeavyweightMigration }.count) > 0 {
|
||||
// ... will migrate more than once. Show special waiting screen
|
||||
@@ -544,7 +520,7 @@ do {
|
||||
else {
|
||||
// ... Do nothing
|
||||
}
|
||||
CoreStore.addStorage(storage, completion: { /* ... */ })
|
||||
dataStack.addStorage(storage, completion: { /* ... */ })
|
||||
}
|
||||
catch {
|
||||
// ... either inspection of the store failed, or if no mapping model was found/inferred
|
||||
@@ -560,11 +536,11 @@ Each `MigrationType` indicates the migration type for each step in the `Migratio
|
||||
|
||||
### Custom migrations
|
||||
|
||||
Before CoreStore 4.0, the only way to implement custom migrations is to use Core Data's standard method: declaring entity mappings through *.xcmappingmodel* files. Starting CoreStore 4.0, new ways to declare migration mappings have been added:
|
||||
CoreStore offers several ways to declare migration mappings:
|
||||
|
||||
- `InferredSchemaMappingProvider`: The default mapping provider which tries to infer model migration between two `DynamicSchema` versions either by searching all *.xcmappingmodel* files from `Bundle.allBundles`, or by relying on lightweight migration if possible.
|
||||
- `XcodeSchemaMappingProvider`: A mapping provider which loads entity mappings from *.xcmappingmodel* files in a specified `Bundle`.
|
||||
- `CustomSchemaMappingProvider`: A mapping provider that infers mapping initially, but also accepts custom mappings for specified entities. This was added to support custom migrations with `CoreStoreObject`s as well, but may also be used with `NSManagedObject`s.
|
||||
- `XcodeSchemaMappingProvider`: A mapping provider which loads entity mappings from *.xcmappingmodel* files in a specified `Bundle`.
|
||||
- `InferredSchemaMappingProvider`: The default mapping provider which tries to infer model migration between two `DynamicSchema` versions either by searching all *.xcmappingmodel* files from `Bundle.allBundles`, or by relying on lightweight migration if possible.
|
||||
|
||||
These mapping providers conform to `SchemaMappingProvider` and can be passed to `SQLiteStore`'s initializer:
|
||||
```swift
|
||||
@@ -631,18 +607,7 @@ dataStack.perform(
|
||||
}
|
||||
)
|
||||
```
|
||||
or for the default stack, directly from `CoreStore`:
|
||||
```swift
|
||||
CoreStore.perform(
|
||||
asynchronous: { (transaction) -> Void in
|
||||
// make changes
|
||||
},
|
||||
completion: { (result) -> Void in
|
||||
// ...
|
||||
}
|
||||
)
|
||||
```
|
||||
Transaction blocks automatically save changes once the block completes. To cancel and rollback a transaction, throw a `CoreStoreError.userCancelled` from inside the closure by calling `try transaction.cancel()`:
|
||||
Transaction closures automatically save changes once the closures completes. To cancel and rollback a transaction, throw a `CoreStoreError.userCancelled` from inside the closure by calling `try transaction.cancel()`:
|
||||
```swift
|
||||
dataStack.perform(
|
||||
asynchronous: { (transaction) -> Void in
|
||||
@@ -668,7 +633,7 @@ The examples above use `perform(asynchronous:...)`, but there are actually 3 typ
|
||||
#### Asynchronous transactions
|
||||
are spawned from `perform(asynchronous:...)`. This method returns immediately and executes its closure from a background serial queue. The return value for the closure is declared as a generic type, so any value returned from the closure can be passed to the completion result:
|
||||
```swift
|
||||
CoreStore.perform(
|
||||
dataStack.perform(
|
||||
asynchronous: { (transaction) -> Bool in
|
||||
// make changes
|
||||
return transaction.hasChanges
|
||||
@@ -683,7 +648,7 @@ CoreStore.perform(
|
||||
```
|
||||
The success and failure can also be declared as separate handlers:
|
||||
```swift
|
||||
CoreStore.perform(
|
||||
dataStack.perform(
|
||||
asynchronous: { (transaction) -> Int in
|
||||
// make changes
|
||||
return transaction.delete(objects)
|
||||
@@ -704,7 +669,7 @@ Transactions created from `perform(asynchronous:...)` are instances of `Asynchro
|
||||
#### Synchronous transactions
|
||||
are created from `perform(synchronous:...)`. While the syntax is similar to its asynchronous counterpart, `perform(synchronous:...)` waits for its transaction block to complete before returning:
|
||||
```swift
|
||||
let hasChanges = CoreStore.perform(
|
||||
let hasChanges = dataStack.perform(
|
||||
synchronous: { (transaction) -> Bool in
|
||||
// make changes
|
||||
return transaction.hasChanges
|
||||
@@ -717,14 +682,14 @@ Since `perform(synchronous:...)` technically blocks two queues (the caller's que
|
||||
|
||||
By default, `perform(synchronous:...)` will wait for observers such as `ListMonitor`s to be notified before the method returns. This may cause deadlocks, especially if you are calling this from the main thread. To reduce this risk, you may try to set the `waitForAllObservers:` parameter to `false`. Doing so tells the `SynchronousDataTransaction` to block only until it completes saving. It will not wait for other context's to receive those changes. This reduces deadlock risk but may have surprising side-effects:
|
||||
```swift
|
||||
CoreStore.perform(
|
||||
dataStack.perform(
|
||||
synchronous: { (transaction) in
|
||||
let person = transaction.create(Into<Person>())
|
||||
person.name = "John"
|
||||
},
|
||||
waitForAllObservers: false
|
||||
)
|
||||
let newPerson = CoreStore.fetchOne(From<Person>.where(\.name == "John"))
|
||||
let newPerson = dataStack.fetchOne(From<Person>.where(\.name == "John"))
|
||||
// newPerson may be nil!
|
||||
// The DataStack may have not yet received the update notification.
|
||||
```
|
||||
@@ -733,7 +698,7 @@ Due to this complicated nature of synchronous transactions, if your app has very
|
||||
#### Unsafe transactions
|
||||
are special in that they do not enclose updates within a closure:
|
||||
```swift
|
||||
let transaction = CoreStore.beginUnsafe()
|
||||
let transaction = dataStack.beginUnsafe()
|
||||
// make changes
|
||||
downloadJSONWithCompletion({ (json) -> Void in
|
||||
|
||||
@@ -766,20 +731,20 @@ While the syntax is straightforward, CoreStore does not just naively insert a ne
|
||||
- If the entity belongs to multiple stores, an assertion failure will be raised. **This is also a programmer error and should never occur in production code.** Normally, with Core Data you can insert an object in this state but saving the `NSManagedObjectContext` will always fail. CoreStore checks this for you at creation time when it makes sense (not during save).
|
||||
|
||||
If the entity exists in multiple configurations, you need to provide the configuration name for the destination persistent store:
|
||||
|
||||
let person = transaction.create(Into<MyPersonEntity>("Config1"))
|
||||
|
||||
```swift
|
||||
let person = transaction.create(Into<MyPersonEntity>("Config1"))
|
||||
```
|
||||
or if the persistent store is the auto-generated "Default" configuration, specify `nil`:
|
||||
|
||||
let person = transaction.create(Into<MyPersonEntity>(nil))
|
||||
|
||||
```swift
|
||||
let person = transaction.create(Into<MyPersonEntity>(nil))
|
||||
```
|
||||
Note that if you do explicitly specify the configuration name, CoreStore will only try to insert the created object to that particular store and will fail if that store is not found; it will not fall back to any other configuration that the entity belongs to.
|
||||
|
||||
### Updating objects
|
||||
|
||||
After creating an object from the transaction, you can simply update its properties as normal:
|
||||
```swift
|
||||
CoreStore.perform(
|
||||
dataStack.perform(
|
||||
asynchronous: { (transaction) -> Void in
|
||||
let person = transaction.create(Into<MyPersonEntity>())
|
||||
person.name = "John Smith"
|
||||
@@ -790,7 +755,7 @@ CoreStore.perform(
|
||||
```
|
||||
To update an existing object, fetch the object's instance from the transaction:
|
||||
```swift
|
||||
CoreStore.perform(
|
||||
dataStack.perform(
|
||||
asynchronous: { (transaction) -> Void in
|
||||
let person = try transaction.fetchOne(
|
||||
From<MyPersonEntity>()
|
||||
@@ -807,7 +772,7 @@ CoreStore.perform(
|
||||
```swift
|
||||
let jane: MyPersonEntity = // ...
|
||||
|
||||
CoreStore.perform(
|
||||
dataStack.perform(
|
||||
asynchronous: { (transaction) -> Void in
|
||||
// WRONG: jane.age = jane.age + 1
|
||||
// RIGHT:
|
||||
@@ -822,7 +787,7 @@ This is also true when updating an object's relationships. Make sure that the ob
|
||||
let jane: MyPersonEntity = // ...
|
||||
let john: MyPersonEntity = // ...
|
||||
|
||||
CoreStore.perform(
|
||||
dataStack.perform(
|
||||
asynchronous: { (transaction) -> Void in
|
||||
// WRONG: jane.friends = [john]
|
||||
// RIGHT:
|
||||
@@ -840,7 +805,7 @@ Deleting an object is simpler because you can tell a transaction to delete an ob
|
||||
```swift
|
||||
let john: MyPersonEntity = // ...
|
||||
|
||||
CoreStore.perform(
|
||||
dataStack.perform(
|
||||
asynchronous: { (transaction) -> Void in
|
||||
transaction.delete(john)
|
||||
},
|
||||
@@ -852,7 +817,7 @@ or several objects at once:
|
||||
let john: MyPersonEntity = // ...
|
||||
let jane: MyPersonEntity = // ...
|
||||
|
||||
CoreStore.perform(
|
||||
dataStack.perform(
|
||||
asynchronous: { (transaction) -> Void in
|
||||
try transaction.delete(john, jane)
|
||||
// try transaction.delete([john, jane]) is also allowed
|
||||
@@ -862,7 +827,7 @@ CoreStore.perform(
|
||||
```
|
||||
If you do not have references yet to the objects to be deleted, transactions have a `deleteAll(...)` method you can pass a query to:
|
||||
```swift
|
||||
CoreStore.perform(
|
||||
dataStack.perform(
|
||||
asynchronous: { (transaction) -> Void in
|
||||
try transaction.deleteAll(
|
||||
From<MyPersonEntity>()
|
||||
@@ -879,7 +844,7 @@ Always remember that the `DataStack` and individual transactions manage differen
|
||||
```swift
|
||||
let jane: MyPersonEntity = // ...
|
||||
|
||||
CoreStore.perform(
|
||||
dataStack.perform(
|
||||
asynchronous: { (transaction) -> Void in
|
||||
let jane = transaction.edit(jane)!
|
||||
jane.age = jane.age + 1
|
||||
@@ -891,14 +856,14 @@ But `CoreStore`, `DataStack` and `BaseDataTransaction` have a very flexible `fet
|
||||
```swift
|
||||
let jane: MyPersonEntity = // ...
|
||||
|
||||
CoreStore.perform(
|
||||
dataStack.perform(
|
||||
asynchronous: { (transaction) -> MyPersonEntity in
|
||||
let jane = transaction.fetchExisting(jane)! // instance for transaction
|
||||
jane.age = jane.age + 1
|
||||
return jane
|
||||
},
|
||||
success: { (transactionJane) in
|
||||
let jane = CoreStore.fetchExisting(transactionJane)! // instance for DataStack
|
||||
let jane = dataStack.fetchExisting(transactionJane)! // instance for DataStack
|
||||
print(jane.age)
|
||||
},
|
||||
failure: { (error) in
|
||||
@@ -910,7 +875,7 @@ CoreStore.perform(
|
||||
```swift
|
||||
var peopleIDs: [NSManagedObjectID] = // ...
|
||||
|
||||
CoreStore.perform(
|
||||
dataStack.perform(
|
||||
asynchronous: { (transaction) -> Void in
|
||||
let jane = try transaction.fetchOne(
|
||||
From<MyPersonEntity>()
|
||||
@@ -925,7 +890,7 @@ CoreStore.perform(
|
||||
|
||||
|
||||
## Importing data
|
||||
Some times, if not most of the time, the data that we save to Core Data comes from external sources such as web servers or external files. If you have for example a JSON dictionary, you may be extracting values as such:
|
||||
Some times, if not most of the time, the data that we save to Core Data comes from external sources such as web servers or external files. If you have a JSON dictionary for example, you may be extracting values as such:
|
||||
```swift
|
||||
let json: [String: Any] = // ...
|
||||
person.name = json["name"] as? NSString
|
||||
@@ -934,7 +899,7 @@ person.age = json["age"] as? NSNumber
|
||||
```
|
||||
If you have many attributes, you don't want to keep repeating this mapping everytime you want to import data. CoreStore lets you write the data mapping code just once, and all you have to do is call `importObject(...)` or `importUniqueObject(...)` through `BaseDataTransaction` subclasses:
|
||||
```swift
|
||||
CoreStore.perform(
|
||||
dataStack.perform(
|
||||
asynchronous: { (transaction) -> Void in
|
||||
let json: [String: Any] = // ...
|
||||
try! transaction.importObject(
|
||||
@@ -964,7 +929,7 @@ You can even use external types from popular 3rd-party JSON libraries, or just s
|
||||
#### `ImportableObject`
|
||||
`ImportableObject` is a very simple protocol:
|
||||
```swift
|
||||
public protocol ImportableObject: class {
|
||||
public protocol ImportableObject: AnyObject {
|
||||
typealias ImportSource
|
||||
static func shouldInsert(from source: ImportSource, in transaction: BaseDataTransaction) -> Bool
|
||||
func didInsert(from source: ImportSource, in transaction: BaseDataTransaction) throws
|
||||
@@ -976,7 +941,7 @@ typealias ImportSource = [String: Any]
|
||||
```
|
||||
This lets us call `importObject(_:source:)` with any `[String: Any]` type as the argument to `source`:
|
||||
```swift
|
||||
CoreStore.perform(
|
||||
dataStack.perform(
|
||||
asynchronous: { (transaction) -> Void in
|
||||
let json: [String: Any] = // ...
|
||||
try! transaction.importObject(
|
||||
@@ -998,7 +963,7 @@ func didInsert(from source: ImportSource, in transaction: BaseDataTransaction) t
|
||||
```
|
||||
Transactions also let you import multiple objects at once using the `importObjects(_:sourceArray:)` method:
|
||||
```swift
|
||||
CoreStore.perform(
|
||||
dataStack.perform(
|
||||
asynchronous: { (transaction) -> Void in
|
||||
let jsonArray: [[String: Any]] = // ...
|
||||
try! transaction.importObjects(
|
||||
@@ -1025,7 +990,7 @@ func didInsert(from source: ImportSource, in transaction: BaseDataTransaction) t
|
||||
```
|
||||
Doing so can let you abandon an invalid transaction immediately:
|
||||
```swift
|
||||
CoreStore.perform(
|
||||
dataStack.perform(
|
||||
asynchronous: { (transaction) -> Void in
|
||||
let jsonArray: [[String: Any]] = // ...
|
||||
|
||||
@@ -1080,7 +1045,7 @@ For `ImportableUniqueObject`, the extraction and assignment of values should be
|
||||
|
||||
You can then create/update an object by calling a transaction's `importUniqueObject(...)` method:
|
||||
```swift
|
||||
CoreStore.perform(
|
||||
dataStack.perform(
|
||||
asynchronous: { (transaction) -> Void in
|
||||
let json: [String: Any] = // ...
|
||||
try! transaction.importUniqueObject(
|
||||
@@ -1095,7 +1060,7 @@ CoreStore.perform(
|
||||
or multiple objects at once with the `importUniqueObjects(...)` method:
|
||||
|
||||
```swift
|
||||
CoreStore.perform(
|
||||
dataStack.perform(
|
||||
asynchronous: { (transaction) -> Void in
|
||||
let jsonArray: [[String: AnyObject]] = // ...
|
||||
try! transaction.importUniqueObjects(
|
||||
@@ -1107,7 +1072,7 @@ CoreStore.perform(
|
||||
completion: { _ in }
|
||||
)
|
||||
```
|
||||
As with `ImportableObject`, you can control wether to skip importing an object by implementing
|
||||
As with `ImportableObject`, you can control whether to skip importing an object by implementing
|
||||
`shouldInsert(from:in:)` and `shouldUpdate(from:in:)`, or to cancel all objects by `throw`ing an error from the `uniqueID(from:in:)`, `didInsert(from:in:)` or `update(from:in:)` methods.
|
||||
|
||||
|
||||
@@ -1125,17 +1090,17 @@ Before we dive in, be aware that CoreStore distinguishes between *fetching* and
|
||||
#### `From` clause
|
||||
The search conditions for fetches and queries are specified using *clauses*. All fetches and queries require a `From` clause that indicates the target entity type:
|
||||
```swift
|
||||
let people = try CoreStore.fetchAll(From<MyPersonEntity>())
|
||||
let people = try dataStack.fetchAll(From<MyPersonEntity>())
|
||||
```
|
||||
`people` in the example above will be of type `[MyPersonEntity]`. The `From<MyPersonEntity>()` clause indicates a fetch to all persistent stores that `MyPersonEntity` belong to.
|
||||
|
||||
If the entity exists in multiple configurations and you need to only search from a particular configuration, indicate in the `From` clause the configuration name for the destination persistent store:
|
||||
```swift
|
||||
let people = try CoreStore.fetchAll(From<MyPersonEntity>("Config1")) // ignore objects in persistent stores other than the "Config1" configuration
|
||||
let people = try dataStack.fetchAll(From<MyPersonEntity>("Config1")) // ignore objects in persistent stores other than the "Config1" configuration
|
||||
```
|
||||
or if the persistent store is the auto-generated "Default" configuration, specify `nil`:
|
||||
```swift
|
||||
let person = try CoreStore.fetchAll(From<MyPersonEntity>(nil))
|
||||
let person = try dataStack.fetchAll(From<MyPersonEntity>(nil))
|
||||
```
|
||||
Now we know how to use a `From` clause, let's move on to fetching and querying.
|
||||
|
||||
@@ -1155,11 +1120,11 @@ Each method's purpose is straightforward, but we need to understand how to set t
|
||||
|
||||
The `Where` clause is CoreStore's `NSPredicate` wrapper. It specifies the search filter to use when fetching (or querying). It implements all initializers that `NSPredicate` does (except for `-predicateWithBlock:`, which Core Data does not support):
|
||||
```swift
|
||||
var people = try CoreStore.fetchAll(
|
||||
var people = try dataStack.fetchAll(
|
||||
From<MyPersonEntity>(),
|
||||
Where<MyPersonEntity>("%K > %d", "age", 30) // string format initializer
|
||||
)
|
||||
people = try CoreStore.fetchAll(
|
||||
people = try dataStack.fetchAll(
|
||||
From<MyPersonEntity>(),
|
||||
Where<MyPersonEntity>(true) // boolean initializer
|
||||
)
|
||||
@@ -1167,21 +1132,21 @@ people = try CoreStore.fetchAll(
|
||||
If you do have an existing `NSPredicate` instance already, you can pass that to `Where` as well:
|
||||
```swift
|
||||
let predicate = NSPredicate(...)
|
||||
var people = CoreStore.fetchAll(
|
||||
var people = dataStack.fetchAll(
|
||||
From<MyPersonEntity>(),
|
||||
Where<MyPersonEntity>(predicate) // predicate initializer
|
||||
)
|
||||
```
|
||||
⭐️Starting CoreStore 5.0, `Where` clauses became more type-safe and are now generic types. To avoid verbose repetition of the generic object type, fetch methods now support **Fetch Chain builders**. We can also use Swift's Smart KeyPaths as the `Where` clause expression:
|
||||
`Where` clauses are generic types. To avoid verbose repetition of the generic object type, fetch methods support **Fetch Chain builders**. We can also use Swift's Smart KeyPaths as the `Where` clause expression:
|
||||
```swift
|
||||
var people = try CoreStore.fetchAll(
|
||||
var people = try dataStack.fetchAll(
|
||||
From<MyPersonEntity>()
|
||||
.where(\.age > 30) // Type-safe!
|
||||
)
|
||||
```
|
||||
`Where` clauses also implement the `&&`, `||`, and `!` logic operators, so you can provide logical conditions without writing too much `AND`, `OR`, and `NOT` strings:
|
||||
```swift
|
||||
var people = try CoreStore.fetchAll(
|
||||
var people = try dataStack.fetchAll(
|
||||
From<MyPersonEntity>()
|
||||
.where(\.age > 30 && \.gender == "M")
|
||||
)
|
||||
@@ -1192,15 +1157,15 @@ If you do not provide a `Where` clause, all objects that belong to the specified
|
||||
|
||||
The `OrderBy` clause is CoreStore's `NSSortDescriptor` wrapper. Use it to specify attribute keys in which to sort the fetch (or query) results with.
|
||||
```swift
|
||||
var mostValuablePeople = try CoreStore.fetchAll(
|
||||
var mostValuablePeople = try dataStack.fetchAll(
|
||||
From<MyPersonEntity>(),
|
||||
OrderBy<MyPersonEntity>(.descending("rating"), .ascending("surname"))
|
||||
)
|
||||
```
|
||||
As seen above, `OrderBy` accepts a list of `SortKey` enumeration values, which can be either `.ascending` or `.descending`.
|
||||
⭐️As with `Where` clauses, CoreStore 5.0 turned `OrderBy` clauses into generic types. To avoid verbose repetition of the generic object type, fetch methods now support **Fetch Chain builders**. We can also use Swift's Smart KeyPaths as the `OrderBy` clause expression:
|
||||
As with `Where` clauses, `OrderBy` clauses are also generic types. To avoid verbose repetition of the generic object type, fetch methods support **Fetch Chain builders**. We can also use Swift's Smart KeyPaths as the `OrderBy` clause expression:
|
||||
```swift
|
||||
var people = try CoreStore.fetchAll(
|
||||
var people = try dataStack.fetchAll(
|
||||
From<MyPersonEntity>()
|
||||
.orderBy(.descending(\.rating), .ascending(\.surname)) // Type-safe!
|
||||
)
|
||||
@@ -1212,7 +1177,7 @@ var orderBy = OrderBy<MyPersonEntity>(.descending(\.rating))
|
||||
if sortFromYoungest {
|
||||
orderBy += OrderBy(.ascending(\.age))
|
||||
}
|
||||
var mostValuablePeople = try CoreStore.fetchAll(
|
||||
var mostValuablePeople = try dataStack.fetchAll(
|
||||
From<MyPersonEntity>(),
|
||||
orderBy
|
||||
)
|
||||
@@ -1222,7 +1187,7 @@ var mostValuablePeople = try CoreStore.fetchAll(
|
||||
|
||||
The `Tweak` clause lets you, uh, *tweak* the fetch (or query). `Tweak` exposes the `NSFetchRequest` in a closure where you can make changes to its properties:
|
||||
```swift
|
||||
var people = try CoreStore.fetchAll(
|
||||
var people = try dataStack.fetchAll(
|
||||
From<MyPersonEntity>(),
|
||||
Where<MyPersonEntity>("age > %d", 30),
|
||||
OrderBy<MyPersonEntity>(.ascending("surname")),
|
||||
@@ -1235,7 +1200,7 @@ var people = try CoreStore.fetchAll(
|
||||
```
|
||||
`Tweak` also supports **Fetch Chain builders**:
|
||||
```swift
|
||||
var people = try CoreStore.fetchAll(
|
||||
var people = try dataStack.fetchAll(
|
||||
From<MyPersonEntity>(),
|
||||
.where(\.age > 30)
|
||||
.orderBy(.ascending(\.surname))
|
||||
@@ -1266,24 +1231,24 @@ Setting up the `From`, `Where`, `OrderBy`, and `Tweak` clauses is similar to how
|
||||
|
||||
The `Select<T>` clause specifies the target attribute/aggregate key, as well as the expected return type:
|
||||
```swift
|
||||
let johnsAge = try CoreStore.queryValue(
|
||||
let johnsAge = try dataStack.queryValue(
|
||||
From<MyPersonEntity>(),
|
||||
Select<Int>("age"),
|
||||
Where("name == %@", "John Smith")
|
||||
Where<MyPersonEntity>("name == %@", "John Smith")
|
||||
)
|
||||
```
|
||||
The example above queries the "age" property for the first object that matches the `Where` condition. `johnsAge` will be bound to type `Int?`, as indicated by the `Select<Int>` generic type. For `queryValue(...)`, types that conform to `QueryableAttributeType` are allowed as the return type (and therefore as the generic type for `Select<T>`).
|
||||
|
||||
For `queryAttributes(...)`, only `NSDictionary` is valid for `Select`, thus you are allowed to omit the generic type:
|
||||
```swift
|
||||
let allAges = try CoreStore.queryAttributes(
|
||||
let allAges = try dataStack.queryAttributes(
|
||||
From<MyPersonEntity>(),
|
||||
Select("age")
|
||||
)
|
||||
```
|
||||
⭐️Starting CoreStore 5.0, query methods now support **Query Chain builders**. We can also use Swift's Smart KeyPaths to use in the expressions:
|
||||
query methods also support **Query Chain builders**. We can also use Swift's Smart KeyPaths to use in the expressions:
|
||||
```swift
|
||||
let johnsAge = try CoreStore.queryValue(
|
||||
let johnsAge = try dataStack.queryValue(
|
||||
From<MyPersonEntity>()
|
||||
.select(\.age) // binds the result to Int
|
||||
.where(\.name == "John Smith")
|
||||
@@ -1298,7 +1263,7 @@ If you only need a value for a particular attribute, you can just specify the ke
|
||||
- `.sum(...)`
|
||||
|
||||
```swift
|
||||
let oldestAge = try CoreStore.queryValue(
|
||||
let oldestAge = try dataStack.queryValue(
|
||||
From<MyPersonEntity>(),
|
||||
Select<Int>(.maximum("age"))
|
||||
)
|
||||
@@ -1306,7 +1271,7 @@ let oldestAge = try CoreStore.queryValue(
|
||||
|
||||
For `queryAttributes(...)` which returns an array of dictionaries, you can specify multiple attributes/aggregates to `Select`:
|
||||
```swift
|
||||
let personJSON = try CoreStore.queryAttributes(
|
||||
let personJSON = try dataStack.queryAttributes(
|
||||
From<MyPersonEntity>(),
|
||||
Select("name", "age")
|
||||
)
|
||||
@@ -1326,7 +1291,7 @@ let personJSON = try CoreStore.queryAttributes(
|
||||
```
|
||||
You can also include an aggregate as well:
|
||||
```swift
|
||||
let personJSON = try CoreStore.queryAttributes(
|
||||
let personJSON = try dataStack.queryAttributes(
|
||||
From<MyPersonEntity>(),
|
||||
Select("name", .count("friends"))
|
||||
)
|
||||
@@ -1346,7 +1311,7 @@ which returns:
|
||||
```
|
||||
The `"count(friends)"` key name was automatically used by CoreStore, but you can specify your own key alias if you need:
|
||||
```swift
|
||||
let personJSON = try CoreStore.queryAttributes(
|
||||
let personJSON = try dataStack.queryAttributes(
|
||||
From<MyPersonEntity>(),
|
||||
Select("name", .count("friends", as: "friendsCount"))
|
||||
)
|
||||
@@ -1369,15 +1334,15 @@ which now returns:
|
||||
|
||||
The `GroupBy` clause lets you group results by a specified attribute/aggregate. This is useful only for `queryAttributes(...)` since `queryValue(...)` just returns the first value.
|
||||
```swift
|
||||
let personJSON = try CoreStore.queryAttributes(
|
||||
let personJSON = try dataStack.queryAttributes(
|
||||
From<MyPersonEntity>(),
|
||||
Select("age", .count("age", as: "count")),
|
||||
GroupBy("age")
|
||||
)
|
||||
```
|
||||
⭐️Starting CoreStore 5.0, `GroupBy` clauses are now also generic types and now support **Query Chain builders**. We can also use Swift's Smart KeyPaths to use in the expressions:
|
||||
`GroupBy` clauses are also generic types and support **Query Chain builders**. We can also use Swift's Smart KeyPaths to use in the expressions:
|
||||
```swift
|
||||
let personJSON = try CoreStore.queryAttributes(
|
||||
let personJSON = try dataStack.queryAttributes(
|
||||
From<MyPersonEntity>()
|
||||
.select(.attribute(\.age), .count(\.age, as: "count"))
|
||||
.groupBy(\.age)
|
||||
@@ -1407,9 +1372,9 @@ public protocol CoreStoreLogger {
|
||||
func abort(message: String, fileName: StaticString, lineNumber: Int, functionName: StaticString)
|
||||
}
|
||||
```
|
||||
Implement this protocol with your custom class then pass the instance to `CoreStore.logger`:
|
||||
Implement this protocol with your custom class then pass the instance to `CoreStoreDefaults.logger`:
|
||||
```swift
|
||||
CoreStore.logger = MyLogger()
|
||||
CoreStoreDefaults.logger = MyLogger()
|
||||
```
|
||||
Doing so channels all logging calls to your logger.
|
||||
|
||||
@@ -1419,8 +1384,7 @@ Take special care when implementing `CoreStoreLogger`'s `assert(...)` and `abort
|
||||
- `assert(...)`: The behavior between `DEBUG` and release builds, or `-O` and `-Onone`, are all left to the implementers' responsibility. CoreStore calls `CoreStoreLogger.assert(...)` only for invalid but usually recoverable errors (for example, early validation failures that may cause an error thrown and handled somewhere else)
|
||||
- `abort(...)`: This method is *the* last-chance for your app to *synchronously* log a fatal error within CoreStore. The app will be terminated right after this function is called (CoreStore calls `fatalError()` internally)
|
||||
|
||||
Starting CoreStore 2.0, all CoreStore types now have very useful (and pretty formatted!) `print(...)` outputs.
|
||||
|
||||
All CoreStore types have very useful (and pretty formatted!) `print(...)` outputs.
|
||||
A couple of examples, `ListMonitor`:
|
||||
|
||||
<img width="369" alt="screen shot 2016-07-10 at 22 56 44" src="https://cloud.githubusercontent.com/assets/3029684/16713994/ae06e702-46f1-11e6-83a8-dee48b480bab.png" />
|
||||
@@ -1435,8 +1399,15 @@ These are all implemented with `CustomDebugStringConvertible.debugDescription`,
|
||||
|
||||
CoreStore provides type-safe wrappers for observing managed objects:
|
||||
|
||||
- `ObjectMonitor`: use to monitor changes to a single `NSManagedObject` or `CoreStoreObject` instance (instead of Key-Value Observing)
|
||||
- `ListMonitor`: use to monitor changes to a list of `NSManagedObject` or `CoreStoreObject` instances (instead of `NSFetchedResultsController`)
|
||||
| | 🆕[*ObjectPublisher*](#observe-a-single-objects-updates) | [*ObjectMonitor*](#observe-a-single-objects-per-property-updates) | 🆕[*ListPublisher*](#observe-a-diffable-list) | [*ListMonitor*](#observe-detailed-list-changes) |
|
||||
| --- | --- | --- | --- | --- |
|
||||
| *Number of objects* | 1 | 1 | N | N |
|
||||
| *Allows multiple observers* | ✅ | ✅ | ✅ | ✅ |
|
||||
| *Emits fine-grained changes* | ❌ | ✅ | ❌ | ✅ |
|
||||
| *Emits DiffableDataSource snapshots* | ✅ | ❌ | ✅ | ❌ |
|
||||
| *Delegate methods* | ❌ | ✅ | ❌ | ✅ |
|
||||
| *Closure callback* | ✅ | ❌ | ✅ | ❌ |
|
||||
| *SwiftUI support* | ✅ | ❌ | ✅ | ❌ |
|
||||
|
||||
### Observe a single property
|
||||
To get notifications for single property changes in an object, there are two methods depending on the object's base class.
|
||||
@@ -1457,10 +1428,35 @@ let observer = person.age.observe(options: [.new]) { (person, change)
|
||||
|
||||
For both methods, you will need to keep a reference to the returned `observer` for the duration of the observation.
|
||||
|
||||
### Observe a single object's updates
|
||||
|
||||
### Observe a single object
|
||||
Observers of an `ObjectPublisher` can receive notifications if any of the object's property changes. You can create an `ObjectPublisher` from the object directly:
|
||||
```swift
|
||||
let objectPublisher: ObjectPublisher<Person> = person.asPublisher(in: dataStack)
|
||||
```
|
||||
or by indexing a `ListPublisher`'s `ListSnapshot`:
|
||||
```swift
|
||||
let listPublisher: ListPublisher<Person> = // ...
|
||||
// ...
|
||||
let objectPublisher = listPublisher.snapshot[indexPath]
|
||||
```
|
||||
(See [`ListPublisher` examples](#observe-a-diffable-list) below)
|
||||
|
||||
To observe an object itself as a whole, implement the `ObjectObserver` protocol and specify the `EntityType`:
|
||||
To receive notifications, call the `ObjectPublisher`'s `addObserve(...)` method passing the owner of the callback closure:
|
||||
```swift
|
||||
objectPublisher.addObserver(self) { [weak self] (objectPublisher) in
|
||||
let snapshot: ObjectSnapshot<Person> = objectPublisher.snapshot
|
||||
// handle changes
|
||||
}
|
||||
```
|
||||
Note that the owner instance will not be retained. You may call `ObjectPublisher.removeObserver(...)` explicitly to stop receiving notifications, but the `ObjectPublisher` also discontinues sending events to deallocated observers.
|
||||
|
||||
The `ObjectSnapshot` returned from the `ObjectPublisher.snapshot` property returns a full-copy `struct` of all properties of the object. This is ideal for managing states as they are thread-safe and are not affected by further changes to the actual object. `ObjectPublisher` automatically updates its `snapshot` value to the latest state of the object.
|
||||
|
||||
|
||||
### Observe a single object's per-property updates
|
||||
|
||||
If you need to track specifically which properties change in an object, implement the `ObjectObserver` protocol and specify the `EntityType`:
|
||||
```swift
|
||||
class MyViewController: UIViewController, ObjectObserver {
|
||||
func objectMonitor(monitor: ObjectMonitor<MyPersonEntity>, willUpdateObject object: MyPersonEntity) {
|
||||
@@ -1476,10 +1472,10 @@ class MyViewController: UIViewController, ObjectObserver {
|
||||
}
|
||||
}
|
||||
```
|
||||
We then need to keep a `ObjectMonitor` instance and register our `ObjectObserver` as an observer:
|
||||
We then need to keep an `ObjectMonitor` instance and register our `ObjectObserver` as an observer:
|
||||
```swift
|
||||
let person: MyPersonEntity = // ...
|
||||
self.monitor = CoreStore.monitorObject(person)
|
||||
self.monitor = dataStack.monitorObject(person)
|
||||
self.monitor.addObserver(self)
|
||||
```
|
||||
The controller will then notify our observer whenever the object's attributes change. You can add multiple `ObjectObserver`s to a single `ObjectMonitor` without any problem. This means you can just share around the `ObjectMonitor` instance to different screens without problem.
|
||||
@@ -1488,8 +1484,51 @@ You can get `ObjectMonitor`'s object through its `object` property. If the objec
|
||||
|
||||
While `ObjectMonitor` exposes `removeObserver(...)` as well, it only stores `weak` references of the observers and will safely unregister deallocated observers.
|
||||
|
||||
### Observe a list of objects
|
||||
To observe a list of objects, implement one of the `ListObserver` protocols and specify the `EntityType`:
|
||||
### Observe a diffable list
|
||||
|
||||
Observers of a `ListPublisher` can receive notifications whenever its fetched result set changes. You can create a `ListPublisher` by fetching from the `DataStack`:
|
||||
```swift
|
||||
let listPublisher = dataStack.listPublisher(
|
||||
From<Person>()
|
||||
.sectionBy(\.age") { "Age \($0)" } // sections are optional
|
||||
.where(\.title == "Engineer")
|
||||
.orderBy(.ascending(\.lastName))
|
||||
)
|
||||
```
|
||||
To receive notifications, call the `ListPublisher`'s `addObserve(...)` method passing the owner of the callback closure:
|
||||
```swift
|
||||
listPublisher.addObserver(self) { [weak self] (listPublisher) in
|
||||
let snapshot: ListSnapshot<Person> = listPublisher.snapshot
|
||||
// handle changes
|
||||
}
|
||||
```
|
||||
Note that the owner instance will not be retained. You may call `ListPublisher.removeObserver(...)` explicitly to stop receiving notifications, but the `ListPublisher` also discontinues sending events to deallocated observers.
|
||||
|
||||
The `ListSnapshot` returned from the `ListPublisher.snapshot` property returns a full-copy `struct` of all sections and `NSManagedObject` items in the list. This is ideal for managing states as they are thread-safe and are not affected by further changes to the result set. `ListPublisher` automatically updates its `snapshot` value to the latest state of the fetch.
|
||||
|
||||
Unlike `ListMonitor`s (See [`ListMonitor` examples](#observe-detailed-list-changes) below), a `ListPublisher` does not track detailed inserts, deletes, and moves. In return, a `ListPublisher` is a lot more lightweight and are designed to work well with `DiffableDataSource.TableView`s and `DiffableDataSource.CollectionView`s:
|
||||
```swift
|
||||
self.dataSource = DiffableDataSource.CollectionView<Person>(
|
||||
collectionView: self.collectionView,
|
||||
dataStack: CoreStoreDefaults.dataStack,
|
||||
cellProvider: { (collectionView, indexPath, person) in
|
||||
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "PersonCell") as! PersonCell
|
||||
cell.setPerson(person)
|
||||
return cell
|
||||
}
|
||||
)
|
||||
|
||||
// ...
|
||||
|
||||
listPublisher.addObserver(self) { [weak self] (listPublisher) in
|
||||
self?.dataSource?.apply(
|
||||
listPublisher.snapshot, animatingDifferences: true
|
||||
)
|
||||
}
|
||||
```
|
||||
|
||||
### Observe detailed list changes
|
||||
If you need to track each object's inserts, deletes, moves, and updates, implement one of the `ListObserver` protocols and specify the `EntityType`:
|
||||
```swift
|
||||
class MyViewController: UIViewController, ListObserver {
|
||||
func listMonitorDidChange(monitor: ListMonitor<MyPersonEntity>) {
|
||||
@@ -1526,7 +1565,7 @@ Including `ListObserver`, there are 3 observer protocols you can implement depen
|
||||
|
||||
We then need to create a `ListMonitor` instance and register our `ListObserver` as an observer:
|
||||
```swift
|
||||
self.monitor = CoreStore.monitorList(
|
||||
self.monitor = dataStack.monitorList(
|
||||
From<MyPersonEntity>()
|
||||
.where(\.age > 30)
|
||||
.orderBy(.ascending(\.name))
|
||||
@@ -1545,7 +1584,7 @@ let firstPerson = self.monitor[0]
|
||||
|
||||
If the list needs to be grouped into sections, create the `ListMonitor` instance with the `monitorSectionedList(...)` method and a `SectionBy` clause:
|
||||
```swift
|
||||
self.monitor = CoreStore.monitorSectionedList(
|
||||
self.monitor = dataStack.monitorSectionedList(
|
||||
From<MyPersonEntity>()
|
||||
.sectionBy(\.age)
|
||||
.where(\.gender == "M")
|
||||
@@ -1557,7 +1596,7 @@ A list controller created this way will group the objects by the attribute key i
|
||||
|
||||
The `SectionBy` clause can also be passed a closure to transform the section name into a displayable string:
|
||||
```swift
|
||||
self.monitor = CoreStore.monitorSectionedList(
|
||||
self.monitor = dataStack.monitorSectionedList(
|
||||
From<MyPersonEntity>()
|
||||
.sectionBy(\.age) { (sectionName) -> String? in
|
||||
"\(sectionName) years old"
|
||||
@@ -1590,7 +1629,7 @@ All CoreStore types are still written in pure Swift, but most core types have Ob
|
||||
<tr><th>Swift</th><th>Objective-C</th></tr>
|
||||
<tr>
|
||||
<td><pre lang=swift>
|
||||
try CoreStore.addStorageAndWait(SQLiteStore.self)
|
||||
try dataStack.addStorageAndWait(SQLiteStore.self)
|
||||
</pre></td>
|
||||
<td><pre lang=objc>
|
||||
NSError *error
|
||||
@@ -1599,7 +1638,7 @@ NSError *error
|
||||
</tr>
|
||||
<tr>
|
||||
<td><pre lang=swift>
|
||||
CoreStore.perform(
|
||||
dataStack.perform(
|
||||
asynchronous: { (transaction) in
|
||||
// ...
|
||||
},
|
||||
@@ -1631,7 +1670,7 @@ All of these `CS`-prefixed bridging classes have very similar usage to the exist
|
||||
For example, you may have a new, modern Swift class that holds a `ListMonitor`:
|
||||
```swift
|
||||
class MyViewController: UIViewController {
|
||||
let monitor = CoreStore.monitorList(From<MyEntity>(), ...)
|
||||
let monitor = dataStack.monitorList(From<MyEntity>(), ...)
|
||||
// ...
|
||||
}
|
||||
```
|
||||
@@ -1645,7 +1684,7 @@ Now let's say you have a legacy Objective-C class that previously uses `NSFetche
|
||||
When you need to instantiate this class from Swift, you just call `bridgeToObjectiveC`:
|
||||
```swift
|
||||
class MyViewController: UIViewController {
|
||||
let monitor = CoreStore.monitorList(From<MyEntity>(), ...)
|
||||
let monitor = dataStack.monitorList(From<MyEntity>(), ...)
|
||||
func showOldController() {
|
||||
let controller = MYOldViewController(monitor: self.monitor.bridgeToObjectiveC)
|
||||
self.presentViewController(controller, animated: true, completion: nil)
|
||||
@@ -1719,7 +1758,7 @@ Also note how `Relationship`s are linked statically with the `inverse:` argument
|
||||
To tell the `DataStack` about these types, add all `CoreStoreObject`s' entities to a `CoreStoreSchema`:
|
||||
```swift
|
||||
|
||||
CoreStore.defaultStack = DataStack(
|
||||
CoreStoreDefaults.dataStack = DataStack(
|
||||
CoreStoreSchema(
|
||||
modelVersion: "V1",
|
||||
entities: [
|
||||
@@ -1729,13 +1768,13 @@ CoreStore.defaultStack = DataStack(
|
||||
]
|
||||
)
|
||||
)
|
||||
CoreStore.addStorage(/* ... */)
|
||||
CoreStoreDefaults.dataStack.addStorage(/* ... */)
|
||||
```
|
||||
And that's all CoreStore needs to build the model; **we don't need *.xcdatamodeld* files anymore.**
|
||||
|
||||
These special properties' values can be accessed or mutated using `.value`:
|
||||
```swift
|
||||
CoreStore.perform(
|
||||
dataStack.perform(
|
||||
asynchronous: { (transaction) in
|
||||
let dog: Dog = transaction.fetchOne(From<Dog>())!
|
||||
// ...
|
||||
@@ -1755,7 +1794,7 @@ let keyPath: String = Dog.keyPath { $0.nickname }
|
||||
```
|
||||
as well as `Where` and `OrderBy` clauses
|
||||
```swift
|
||||
let puppies = try CoreStore.fetchAll(
|
||||
let puppies = try dataStack.fetchAll(
|
||||
From<Dog>()
|
||||
.where(\.age < 1)
|
||||
.orderBy(.ascending(\.age))
|
||||
@@ -1790,7 +1829,7 @@ CoreStoreSchema(
|
||||
```
|
||||
You can also get this hash after the `DataStack` has been fully set up by printing to the console:
|
||||
```swift
|
||||
print(CoreStore.defaultStack.modelSchema.printCoreStoreSchema())
|
||||
print(CoreStoreDefaults.dataStack.modelSchema.printCoreStoreSchema())
|
||||
```
|
||||
|
||||
Once the version lock is set, any changes in the properties or to the model will trigger an assertion failure similar to this:
|
||||
@@ -1801,8 +1840,8 @@ Once the version lock is set, any changes in the properties or to the model will
|
||||
# Installation
|
||||
- Requires:
|
||||
- iOS 10 SDK and above
|
||||
- Swift 5.0 (Xcode 10+)
|
||||
- For previous Swift versions: [Swift 3.2](https://github.com/JohnEstropia/CoreStore/tree/4.2.3), [Swift 4.2](https://github.com/JohnEstropia/CoreStore/tree/6.2.1)
|
||||
- Swift 5.1 (Xcode 11+)
|
||||
- For previous Swift versions: [Swift 3.2](https://github.com/JohnEstropia/CoreStore/tree/4.2.3), [Swift 4.2](https://github.com/JohnEstropia/CoreStore/tree/6.2.1), [Swift 5.0](https://github.com/JohnEstropia/CoreStore/tree/6.3.2)
|
||||
- Dependencies:
|
||||
- *None*
|
||||
- Other notes:
|
||||
@@ -1811,7 +1850,7 @@ Once the version lock is set, any changes in the properties or to the model will
|
||||
### Install with CocoaPods
|
||||
In your `Podfile`, add
|
||||
```
|
||||
pod 'CoreStore', '~> 6.3'
|
||||
pod 'CoreStore', '~> 7.0'
|
||||
```
|
||||
and run
|
||||
```
|
||||
@@ -1822,7 +1861,7 @@ This installs CoreStore as a framework. Declare `import CoreStore` in your swift
|
||||
### Install with Carthage
|
||||
In your `Cartfile`, add
|
||||
```
|
||||
github "JohnEstropia/CoreStore" >= 6.3.0
|
||||
github "JohnEstropia/CoreStore" >= 7.0.0
|
||||
```
|
||||
and run
|
||||
```
|
||||
@@ -1833,7 +1872,7 @@ This installs CoreStore as a framework. Declare `import CoreStore` in your swift
|
||||
#### Install with Swift Package Manager:
|
||||
```swift
|
||||
dependencies: [
|
||||
.package(url: "https://github.com/JohnEstropia/CoreStore.git", from: "6.3.0"))
|
||||
.package(url: "https://github.com/JohnEstropia/CoreStore.git", from: "7.0.0"))
|
||||
]
|
||||
```
|
||||
Declare `import CoreStore` in your swift file to use the library.
|
||||
|
||||
@@ -30,7 +30,7 @@ import CoreData
|
||||
// MARK: - AsynchronousDataTransaction
|
||||
|
||||
/**
|
||||
The `AsynchronousDataTransaction` provides an interface for `DynamicObject` creates, updates, and deletes. A transaction object should typically be only used from within a transaction block initiated from `DataStack.perform(asynchronous:...)`, or from `CoreStore.perform(synchronous:...)`.
|
||||
The `AsynchronousDataTransaction` provides an interface for `DynamicObject` creates, updates, and deletes. A transaction object should typically be only used from within a transaction block initiated from `DataStack.perform(asynchronous:...)`.
|
||||
*/
|
||||
public final class AsynchronousDataTransaction: BaseDataTransaction {
|
||||
|
||||
@@ -66,11 +66,11 @@ public final class AsynchronousDataTransaction: BaseDataTransaction {
|
||||
- parameter into: the `Into` clause indicating the destination `NSManagedObject` or `CoreStoreObject` entity type and the destination configuration
|
||||
- returns: a new `NSManagedObject` or `CoreStoreObject` instance of the specified entity type.
|
||||
*/
|
||||
public override func create<D>(_ into: Into<D>) -> D {
|
||||
public override func create<O>(_ into: Into<O>) -> O {
|
||||
|
||||
CoreStore.assert(
|
||||
Internals.assert(
|
||||
!self.isCommitted,
|
||||
"Attempted to create an entity of type \(cs_typeName(into.entityClass)) from an already committed \(cs_typeName(self))."
|
||||
"Attempted to create an entity of type \(Internals.typeName(into.entityClass)) from an already committed \(Internals.typeName(self))."
|
||||
)
|
||||
|
||||
return super.create(into)
|
||||
@@ -82,11 +82,11 @@ public final class AsynchronousDataTransaction: BaseDataTransaction {
|
||||
- parameter object: the `NSManagedObject` or `CoreStoreObject` to be edited
|
||||
- returns: an editable proxy for the specified `NSManagedObject` or `CoreStoreObject`.
|
||||
*/
|
||||
public override func edit<D: DynamicObject>(_ object: D?) -> D? {
|
||||
public override func edit<O: DynamicObject>(_ object: O?) -> O? {
|
||||
|
||||
CoreStore.assert(
|
||||
Internals.assert(
|
||||
!self.isCommitted,
|
||||
"Attempted to update an entity of type \(cs_typeName(object)) from an already committed \(cs_typeName(self))."
|
||||
"Attempted to update an entity of type \(Internals.typeName(object)) from an already committed \(Internals.typeName(self))."
|
||||
)
|
||||
|
||||
return super.edit(object)
|
||||
@@ -99,60 +99,59 @@ public final class AsynchronousDataTransaction: BaseDataTransaction {
|
||||
- parameter objectID: the `NSManagedObjectID` for the object to be edited
|
||||
- returns: an editable proxy for the specified `NSManagedObject` or `CoreStoreObject`.
|
||||
*/
|
||||
public override func edit<D>(_ into: Into<D>, _ objectID: NSManagedObjectID) -> D? {
|
||||
public override func edit<O>(_ into: Into<O>, _ objectID: NSManagedObjectID) -> O? {
|
||||
|
||||
CoreStore.assert(
|
||||
Internals.assert(
|
||||
!self.isCommitted,
|
||||
"Attempted to update an entity of type \(cs_typeName(into.entityClass)) from an already committed \(cs_typeName(self))."
|
||||
"Attempted to update an entity of type \(Internals.typeName(into.entityClass)) from an already committed \(Internals.typeName(self))."
|
||||
)
|
||||
|
||||
return super.edit(into, objectID)
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
Deletes a specified `NSManagedObject` or `CoreStoreObject`.
|
||||
|
||||
- parameter object: the `NSManagedObject` or `CoreStoreObject` to be deleted
|
||||
Deletes the objects with the specified `NSManagedObjectID`s.
|
||||
|
||||
- parameter objectIDs: the `NSManagedObjectID`s of the objects to delete
|
||||
*/
|
||||
public override func delete<D: DynamicObject>(_ object: D?) {
|
||||
|
||||
CoreStore.assert(
|
||||
public override func delete<S: Sequence>(objectIDs: S) where S.Iterator.Element: NSManagedObjectID {
|
||||
|
||||
Internals.assert(
|
||||
!self.isCommitted,
|
||||
"Attempted to delete an entity of type \(cs_typeName(object)) from an already committed \(cs_typeName(self))."
|
||||
"Attempted to delete an entities from an already committed \(Internals.typeName(self))."
|
||||
)
|
||||
|
||||
super.delete(object)
|
||||
|
||||
super.delete(objectIDs: objectIDs)
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
Deletes the specified `DynamicObject`s.
|
||||
|
||||
- parameter object1: the `DynamicObject` to be deleted
|
||||
- parameter object2: another `DynamicObject` to be deleted
|
||||
- parameter objects: other `DynamicObject`s to be deleted
|
||||
Deletes the specified `NSManagedObject`s or `CoreStoreObject`s represented by series of `ObjectRepresentation`s.
|
||||
|
||||
- parameter object: the `ObjectRepresentation` representing an `NSManagedObject` or `CoreStoreObject` to be deleted
|
||||
- parameter objects: other `ObjectRepresentation`s representing `NSManagedObject`s or `CoreStoreObject`s to be deleted
|
||||
*/
|
||||
public override func delete<D: DynamicObject>(_ object1: D?, _ object2: D?, _ objects: D?...) {
|
||||
|
||||
CoreStore.assert(
|
||||
public override func delete<O: ObjectRepresentation>(_ object: O?, _ objects: O?...) {
|
||||
|
||||
Internals.assert(
|
||||
!self.isCommitted,
|
||||
"Attempted to delete an entities from an already committed \(cs_typeName(self))."
|
||||
"Attempted to delete an entities from an already committed \(Internals.typeName(self))."
|
||||
)
|
||||
|
||||
super.delete(([object1, object2] + objects).compactMap { $0 })
|
||||
|
||||
super.delete(([object] + objects).compactMap { $0 })
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
Deletes the specified `DynamicObject`s.
|
||||
|
||||
- parameter objects: the `DynamicObject`s to be deleted
|
||||
Deletes the specified `NSManagedObject`s or `CoreStoreObject`s represented by an `ObjectRepresenation`.
|
||||
|
||||
- parameter objects: the `ObjectRepresenation`s representing `NSManagedObject`s or `CoreStoreObject`s to be deleted
|
||||
*/
|
||||
public override func delete<S: Sequence>(_ objects: S) where S.Iterator.Element: DynamicObject {
|
||||
|
||||
CoreStore.assert(
|
||||
public override func delete<S: Sequence>(_ objects: S) where S.Iterator.Element: ObjectRepresentation {
|
||||
|
||||
Internals.assert(
|
||||
!self.isCommitted,
|
||||
"Attempted to delete an entities from an already committed \(cs_typeName(self))."
|
||||
"Attempted to delete an entities from an already committed \(Internals.typeName(self))."
|
||||
)
|
||||
|
||||
|
||||
super.delete(objects)
|
||||
}
|
||||
|
||||
|
||||
@@ -29,11 +29,10 @@ import CoreData
|
||||
|
||||
// MARK: - AttributeProtocol
|
||||
|
||||
internal protocol AttributeProtocol: class {
|
||||
internal protocol AttributeProtocol: PropertyProtocol {
|
||||
|
||||
static var attributeType: NSAttributeType { get }
|
||||
|
||||
var keyPath: KeyPathString { get }
|
||||
var isOptional: Bool { get }
|
||||
var isTransient: Bool { get }
|
||||
var allowsExternalBinaryDataStorage: Bool { get }
|
||||
@@ -44,4 +43,5 @@ internal protocol AttributeProtocol: class {
|
||||
var rawObject: CoreStoreManagedObject? { get set }
|
||||
var getter: CoreStoreManagedObject.CustomGetter? { get }
|
||||
var setter: CoreStoreManagedObject.CustomSetter? { get }
|
||||
var valueForSnapshot: Any { get }
|
||||
}
|
||||
|
||||
@@ -39,13 +39,13 @@ extension BaseDataTransaction {
|
||||
- throws: an `Error` thrown from any of the `ImportableObject` methods
|
||||
- returns: the created `ImportableObject` instance, or `nil` if the import was ignored
|
||||
*/
|
||||
public func importObject<D: ImportableObject>(
|
||||
_ into: Into<D>,
|
||||
source: D.ImportSource) throws -> D? {
|
||||
public func importObject<O: ImportableObject>(
|
||||
_ into: Into<O>,
|
||||
source: O.ImportSource) throws -> O? {
|
||||
|
||||
CoreStore.assert(
|
||||
Internals.assert(
|
||||
self.isRunningInAllowedQueue(),
|
||||
"Attempted to import an object of type \(cs_typeName(into.entityClass)) outside the transaction's designated queue."
|
||||
"Attempted to import an object of type \(Internals.typeName(into.entityClass)) outside the transaction's designated queue."
|
||||
)
|
||||
|
||||
return try autoreleasepool {
|
||||
@@ -65,22 +65,22 @@ extension BaseDataTransaction {
|
||||
/**
|
||||
Updates an existing `ImportableObject` by importing values from the specified import source.
|
||||
|
||||
- parameter object: the `NSManagedObject` to update
|
||||
- parameter object: the `ImportableObject` to update
|
||||
- parameter source: the object to import values from
|
||||
- throws: an `Error` thrown from any of the `ImportableObject` methods
|
||||
*/
|
||||
public func importObject<D: ImportableObject>(
|
||||
_ object: D,
|
||||
source: D.ImportSource) throws {
|
||||
public func importObject<O: ImportableObject>(
|
||||
_ object: O,
|
||||
source: O.ImportSource) throws {
|
||||
|
||||
CoreStore.assert(
|
||||
Internals.assert(
|
||||
self.isRunningInAllowedQueue(),
|
||||
"Attempted to import an object of type \(cs_typeName(object)) outside the transaction's designated queue."
|
||||
"Attempted to import an object of type \(Internals.typeName(object)) outside the transaction's designated queue."
|
||||
)
|
||||
|
||||
try autoreleasepool {
|
||||
|
||||
let entityType = cs_dynamicType(of: object)
|
||||
let entityType = object.runtimeType()
|
||||
guard entityType.shouldInsert(from: source, in: self) else {
|
||||
|
||||
return
|
||||
@@ -97,18 +97,18 @@ extension BaseDataTransaction {
|
||||
- throws: an `Error` thrown from any of the `ImportableObject` methods
|
||||
- returns: the array of created `ImportableObject` instances
|
||||
*/
|
||||
public func importObjects<D: ImportableObject, S: Sequence>(
|
||||
_ into: Into<D>,
|
||||
sourceArray: S) throws -> [D] where S.Iterator.Element == D.ImportSource {
|
||||
public func importObjects<O: ImportableObject, S: Sequence>(
|
||||
_ into: Into<O>,
|
||||
sourceArray: S) throws -> [O] where S.Iterator.Element == O.ImportSource {
|
||||
|
||||
CoreStore.assert(
|
||||
Internals.assert(
|
||||
self.isRunningInAllowedQueue(),
|
||||
"Attempted to import an object of type \(cs_typeName(into.entityClass)) outside the transaction's designated queue."
|
||||
"Attempted to import an object of type \(Internals.typeName(into.entityClass)) outside the transaction's designated queue."
|
||||
)
|
||||
|
||||
return try autoreleasepool {
|
||||
|
||||
return try sourceArray.compactMap { (source) -> D? in
|
||||
return try sourceArray.compactMap { (source) -> O? in
|
||||
|
||||
let entityType = into.entityClass
|
||||
guard entityType.shouldInsert(from: source, in: self) else {
|
||||
@@ -133,13 +133,13 @@ extension BaseDataTransaction {
|
||||
- throws: an `Error` thrown from any of the `ImportableUniqueObject` methods
|
||||
- returns: the created/updated `ImportableUniqueObject` instance, or `nil` if the import was ignored
|
||||
*/
|
||||
public func importUniqueObject<D: ImportableUniqueObject>(
|
||||
_ into: Into<D>,
|
||||
source: D.ImportSource) throws -> D? {
|
||||
public func importUniqueObject<O: ImportableUniqueObject>(
|
||||
_ into: Into<O>,
|
||||
source: O.ImportSource) throws -> O? {
|
||||
|
||||
CoreStore.assert(
|
||||
Internals.assert(
|
||||
self.isRunningInAllowedQueue(),
|
||||
"Attempted to import an object of type \(cs_typeName(into.entityClass)) outside the transaction's designated queue."
|
||||
"Attempted to import an object of type \(Internals.typeName(into.entityClass)) outside the transaction's designated queue."
|
||||
)
|
||||
|
||||
return try autoreleasepool {
|
||||
@@ -151,7 +151,7 @@ extension BaseDataTransaction {
|
||||
return nil
|
||||
}
|
||||
|
||||
if let object = try self.fetchOne(From(entityType), Where<D>(uniqueIDKeyPath, isEqualTo: uniqueIDValue)) {
|
||||
if let object = try self.fetchOne(From(entityType), Where<O>(uniqueIDKeyPath, isEqualTo: uniqueIDValue)) {
|
||||
|
||||
guard entityType.shouldUpdate(from: source, in: self) else {
|
||||
|
||||
@@ -185,23 +185,23 @@ extension BaseDataTransaction {
|
||||
- throws: an `Error` thrown from any of the `ImportableUniqueObject` methods
|
||||
- returns: the array of created/updated `ImportableUniqueObject` instances
|
||||
*/
|
||||
public func importUniqueObjects<D: ImportableUniqueObject, S: Sequence>(
|
||||
_ into: Into<D>,
|
||||
public func importUniqueObjects<O: ImportableUniqueObject, S: Sequence>(
|
||||
_ into: Into<O>,
|
||||
sourceArray: S,
|
||||
preProcess: @escaping (_ mapping: [D.UniqueIDType: D.ImportSource]) throws -> [D.UniqueIDType: D.ImportSource] = { $0 }) throws -> [D] where S.Iterator.Element == D.ImportSource {
|
||||
preProcess: @escaping (_ mapping: [O.UniqueIDType: O.ImportSource]) throws -> [O.UniqueIDType: O.ImportSource] = { $0 }) throws -> [O] where S.Iterator.Element == O.ImportSource {
|
||||
|
||||
CoreStore.assert(
|
||||
Internals.assert(
|
||||
self.isRunningInAllowedQueue(),
|
||||
"Attempted to import an object of type \(cs_typeName(into.entityClass)) outside the transaction's designated queue."
|
||||
"Attempted to import an object of type \(Internals.typeName(into.entityClass)) outside the transaction's designated queue."
|
||||
)
|
||||
|
||||
return try autoreleasepool {
|
||||
|
||||
let entityType = into.entityClass
|
||||
var importSourceByID = Dictionary<D.UniqueIDType, D.ImportSource>()
|
||||
var importSourceByID = Dictionary<O.UniqueIDType, O.ImportSource>()
|
||||
let sortedIDs = try autoreleasepool {
|
||||
|
||||
return try sourceArray.compactMap { (source) -> D.UniqueIDType? in
|
||||
return try sourceArray.compactMap { (source) -> O.UniqueIDType? in
|
||||
|
||||
guard let uniqueIDValue = try entityType.uniqueID(from: source, in: self) else {
|
||||
|
||||
@@ -214,13 +214,13 @@ extension BaseDataTransaction {
|
||||
|
||||
importSourceByID = try autoreleasepool { try preProcess(importSourceByID) }
|
||||
|
||||
var existingObjectsByID = Dictionary<D.UniqueIDType, D>()
|
||||
var existingObjectsByID = Dictionary<O.UniqueIDType, O>()
|
||||
try self
|
||||
.fetchAll(From(entityType), Where<D>(entityType.uniqueIDKeyPath, isMemberOf: sortedIDs))
|
||||
.fetchAll(From(entityType), Where<O>(entityType.uniqueIDKeyPath, isMemberOf: sortedIDs))
|
||||
.forEach { existingObjectsByID[$0.uniqueIDValue] = $0 }
|
||||
|
||||
var processedObjectIDs = Set<D.UniqueIDType>()
|
||||
var result = [D]()
|
||||
var processedObjectIDs = Set<O.UniqueIDType>()
|
||||
var result = [O]()
|
||||
|
||||
for objectID in sortedIDs where !processedObjectIDs.contains(objectID) {
|
||||
|
||||
|
||||
@@ -39,11 +39,11 @@ extension BaseDataTransaction: FetchableSource, QueryableSource {
|
||||
- returns: the number of `DynamicObject`s deleted
|
||||
*/
|
||||
@discardableResult
|
||||
public func deleteAll<D>(_ from: From<D>, _ deleteClauses: DeleteClause...) throws -> Int {
|
||||
public func deleteAll<O>(_ from: From<O>, _ deleteClauses: DeleteClause...) throws -> Int {
|
||||
|
||||
CoreStore.assert(
|
||||
Internals.assert(
|
||||
self.isRunningInAllowedQueue(),
|
||||
"Attempted to delete from a \(cs_typeName(self)) outside its designated queue."
|
||||
"Attempted to delete from a \(Internals.typeName(self)) outside its designated queue."
|
||||
)
|
||||
return try self.context.deleteAll(from, deleteClauses)
|
||||
}
|
||||
@@ -56,11 +56,11 @@ extension BaseDataTransaction: FetchableSource, QueryableSource {
|
||||
- returns: the number of `DynamicObject`s deleted
|
||||
*/
|
||||
@discardableResult
|
||||
public func deleteAll<D>(_ from: From<D>, _ deleteClauses: [DeleteClause]) throws -> Int {
|
||||
public func deleteAll<O>(_ from: From<O>, _ deleteClauses: [DeleteClause]) throws -> Int {
|
||||
|
||||
CoreStore.assert(
|
||||
Internals.assert(
|
||||
self.isRunningInAllowedQueue(),
|
||||
"Attempted to delete from a \(cs_typeName(self)) outside its designated queue."
|
||||
"Attempted to delete from a \(Internals.typeName(self)) outside its designated queue."
|
||||
)
|
||||
return try self.context.deleteAll(from, deleteClauses)
|
||||
}
|
||||
@@ -76,9 +76,9 @@ extension BaseDataTransaction: FetchableSource, QueryableSource {
|
||||
@discardableResult
|
||||
public func deleteAll<B: FetchChainableBuilderType>(_ clauseChain: B) throws -> Int {
|
||||
|
||||
CoreStore.assert(
|
||||
Internals.assert(
|
||||
self.isRunningInAllowedQueue(),
|
||||
"Attempted to delete from a \(cs_typeName(self)) outside its designated queue."
|
||||
"Attempted to delete from a \(Internals.typeName(self)) outside its designated queue."
|
||||
)
|
||||
|
||||
return try self.context.deleteAll(clauseChain.from, clauseChain.fetchClauses)
|
||||
@@ -93,7 +93,7 @@ extension BaseDataTransaction: FetchableSource, QueryableSource {
|
||||
- parameter object: a reference to the object created/fetched outside the transaction
|
||||
- returns: the `DynamicObject` instance if the object exists in the transaction, or `nil` if not found.
|
||||
*/
|
||||
public func fetchExisting<D: DynamicObject>(_ object: D) -> D? {
|
||||
public func fetchExisting<O: DynamicObject>(_ object: O) -> O? {
|
||||
|
||||
return self.context.fetchExisting(object)
|
||||
}
|
||||
@@ -104,7 +104,7 @@ extension BaseDataTransaction: FetchableSource, QueryableSource {
|
||||
- parameter objectID: the `NSManagedObjectID` for the object
|
||||
- returns: the `DynamicObject` instance if the object exists in the transaction, or `nil` if not found.
|
||||
*/
|
||||
public func fetchExisting<D: DynamicObject>(_ objectID: NSManagedObjectID) -> D? {
|
||||
public func fetchExisting<O: DynamicObject>(_ objectID: NSManagedObjectID) -> O? {
|
||||
|
||||
return self.context.fetchExisting(objectID)
|
||||
}
|
||||
@@ -115,7 +115,7 @@ extension BaseDataTransaction: FetchableSource, QueryableSource {
|
||||
- parameter objects: an array of `DynamicObject`s created/fetched outside the transaction
|
||||
- returns: the `DynamicObject` array for objects that exists in the transaction
|
||||
*/
|
||||
public func fetchExisting<D: DynamicObject, S: Sequence>(_ objects: S) -> [D] where S.Iterator.Element == D {
|
||||
public func fetchExisting<O: DynamicObject, S: Sequence>(_ objects: S) -> [O] where S.Iterator.Element == O {
|
||||
|
||||
return self.context.fetchExisting(objects)
|
||||
}
|
||||
@@ -126,7 +126,7 @@ extension BaseDataTransaction: FetchableSource, QueryableSource {
|
||||
- parameter objectIDs: the `NSManagedObjectID` array for the objects
|
||||
- returns: the `DynamicObject` array for objects that exists in the transaction
|
||||
*/
|
||||
public func fetchExisting<D: DynamicObject, S: Sequence>(_ objectIDs: S) -> [D] where S.Iterator.Element == NSManagedObjectID {
|
||||
public func fetchExisting<O: DynamicObject, S: Sequence>(_ objectIDs: S) -> [O] where S.Iterator.Element == NSManagedObjectID {
|
||||
|
||||
return self.context.fetchExisting(objectIDs)
|
||||
}
|
||||
@@ -139,11 +139,11 @@ extension BaseDataTransaction: FetchableSource, QueryableSource {
|
||||
- returns: the first `DynamicObject` instance that satisfies the specified `FetchClause`s, or `nil` if no match was found
|
||||
- throws: `CoreStoreError.persistentStoreNotFound` if the specified entity could not be found in any store's schema.
|
||||
*/
|
||||
public func fetchOne<D>(_ from: From<D>, _ fetchClauses: FetchClause...) throws -> D? {
|
||||
public func fetchOne<O>(_ from: From<O>, _ fetchClauses: FetchClause...) throws -> O? {
|
||||
|
||||
CoreStore.assert(
|
||||
Internals.assert(
|
||||
self.isRunningInAllowedQueue(),
|
||||
"Attempted to fetch from a \(cs_typeName(self)) outside its designated queue."
|
||||
"Attempted to fetch from a \(Internals.typeName(self)) outside its designated queue."
|
||||
)
|
||||
return try self.context.fetchOne(from, fetchClauses)
|
||||
}
|
||||
@@ -156,11 +156,11 @@ extension BaseDataTransaction: FetchableSource, QueryableSource {
|
||||
- returns: the first `DynamicObject` instance that satisfies the specified `FetchClause`s, or `nil` if no match was found
|
||||
- throws: `CoreStoreError.persistentStoreNotFound` if the specified entity could not be found in any store's schema.
|
||||
*/
|
||||
public func fetchOne<D>(_ from: From<D>, _ fetchClauses: [FetchClause]) throws -> D? {
|
||||
public func fetchOne<O>(_ from: From<O>, _ fetchClauses: [FetchClause]) throws -> O? {
|
||||
|
||||
CoreStore.assert(
|
||||
Internals.assert(
|
||||
self.isRunningInAllowedQueue(),
|
||||
"Attempted to fetch from a \(cs_typeName(self)) outside its designated queue."
|
||||
"Attempted to fetch from a \(Internals.typeName(self)) outside its designated queue."
|
||||
)
|
||||
return try self.context.fetchOne(from, fetchClauses)
|
||||
}
|
||||
@@ -180,9 +180,9 @@ extension BaseDataTransaction: FetchableSource, QueryableSource {
|
||||
*/
|
||||
public func fetchOne<B: FetchChainableBuilderType>(_ clauseChain: B) throws -> B.ObjectType? {
|
||||
|
||||
CoreStore.assert(
|
||||
Internals.assert(
|
||||
self.isRunningInAllowedQueue(),
|
||||
"Attempted to fetch from a \(cs_typeName(self)) outside its designated queue."
|
||||
"Attempted to fetch from a \(Internals.typeName(self)) outside its designated queue."
|
||||
)
|
||||
return try self.context.fetchOne(clauseChain)
|
||||
}
|
||||
@@ -195,11 +195,11 @@ extension BaseDataTransaction: FetchableSource, QueryableSource {
|
||||
- returns: all `DynamicObject` instances that satisfy the specified `FetchClause`s, or an empty array if no match was found
|
||||
- throws: `CoreStoreError.persistentStoreNotFound` if the specified entity could not be found in any store's schema.
|
||||
*/
|
||||
public func fetchAll<D>(_ from: From<D>, _ fetchClauses: FetchClause...) throws -> [D] {
|
||||
public func fetchAll<O>(_ from: From<O>, _ fetchClauses: FetchClause...) throws -> [O] {
|
||||
|
||||
CoreStore.assert(
|
||||
Internals.assert(
|
||||
self.isRunningInAllowedQueue(),
|
||||
"Attempted to fetch from a \(cs_typeName(self)) outside its designated queue."
|
||||
"Attempted to fetch from a \(Internals.typeName(self)) outside its designated queue."
|
||||
)
|
||||
return try self.context.fetchAll(from, fetchClauses)
|
||||
}
|
||||
@@ -212,11 +212,11 @@ extension BaseDataTransaction: FetchableSource, QueryableSource {
|
||||
- returns: all `DynamicObject` instances that satisfy the specified `FetchClause`s, or an empty array if no match was found
|
||||
- throws: `CoreStoreError.persistentStoreNotFound` if the specified entity could not be found in any store's schema.
|
||||
*/
|
||||
public func fetchAll<D>(_ from: From<D>, _ fetchClauses: [FetchClause]) throws -> [D] {
|
||||
public func fetchAll<O>(_ from: From<O>, _ fetchClauses: [FetchClause]) throws -> [O] {
|
||||
|
||||
CoreStore.assert(
|
||||
Internals.assert(
|
||||
self.isRunningInAllowedQueue(),
|
||||
"Attempted to fetch from a \(cs_typeName(self)) outside its designated queue."
|
||||
"Attempted to fetch from a \(Internals.typeName(self)) outside its designated queue."
|
||||
)
|
||||
return try self.context.fetchAll(from, fetchClauses)
|
||||
}
|
||||
@@ -236,9 +236,9 @@ extension BaseDataTransaction: FetchableSource, QueryableSource {
|
||||
*/
|
||||
public func fetchAll<B: FetchChainableBuilderType>(_ clauseChain: B) throws -> [B.ObjectType] {
|
||||
|
||||
CoreStore.assert(
|
||||
Internals.assert(
|
||||
self.isRunningInAllowedQueue(),
|
||||
"Attempted to fetch from a \(cs_typeName(self)) outside its designated queue."
|
||||
"Attempted to fetch from a \(Internals.typeName(self)) outside its designated queue."
|
||||
)
|
||||
return try self.context.fetchAll(clauseChain)
|
||||
}
|
||||
@@ -251,11 +251,11 @@ extension BaseDataTransaction: FetchableSource, QueryableSource {
|
||||
- returns: the number of `DynamicObject`s that satisfy the specified `FetchClause`s
|
||||
- throws: `CoreStoreError.persistentStoreNotFound` if the specified entity could not be found in any store's schema.
|
||||
*/
|
||||
public func fetchCount<D>(_ from: From<D>, _ fetchClauses: FetchClause...) throws -> Int {
|
||||
public func fetchCount<O>(_ from: From<O>, _ fetchClauses: FetchClause...) throws -> Int {
|
||||
|
||||
CoreStore.assert(
|
||||
Internals.assert(
|
||||
self.isRunningInAllowedQueue(),
|
||||
"Attempted to fetch from a \(cs_typeName(self)) outside its designated queue."
|
||||
"Attempted to fetch from a \(Internals.typeName(self)) outside its designated queue."
|
||||
)
|
||||
return try self.context.fetchCount(from, fetchClauses)
|
||||
}
|
||||
@@ -268,11 +268,11 @@ extension BaseDataTransaction: FetchableSource, QueryableSource {
|
||||
- returns: the number of `DynamicObject`s that satisfy the specified `FetchClause`s
|
||||
- throws: `CoreStoreError.persistentStoreNotFound` if the specified entity could not be found in any store's schema.
|
||||
*/
|
||||
public func fetchCount<D>(_ from: From<D>, _ fetchClauses: [FetchClause]) throws -> Int {
|
||||
public func fetchCount<O>(_ from: From<O>, _ fetchClauses: [FetchClause]) throws -> Int {
|
||||
|
||||
CoreStore.assert(
|
||||
Internals.assert(
|
||||
self.isRunningInAllowedQueue(),
|
||||
"Attempted to fetch from a \(cs_typeName(self)) outside its designated queue."
|
||||
"Attempted to fetch from a \(Internals.typeName(self)) outside its designated queue."
|
||||
)
|
||||
return try self.context.fetchCount(from, fetchClauses)
|
||||
}
|
||||
@@ -292,9 +292,9 @@ extension BaseDataTransaction: FetchableSource, QueryableSource {
|
||||
*/
|
||||
public func fetchCount<B: FetchChainableBuilderType>(_ clauseChain: B) throws -> Int {
|
||||
|
||||
CoreStore.assert(
|
||||
Internals.assert(
|
||||
self.isRunningInAllowedQueue(),
|
||||
"Attempted to fetch from a \(cs_typeName(self)) outside its designated queue."
|
||||
"Attempted to fetch from a \(Internals.typeName(self)) outside its designated queue."
|
||||
)
|
||||
return try self.context.fetchCount(clauseChain)
|
||||
}
|
||||
@@ -307,11 +307,11 @@ extension BaseDataTransaction: FetchableSource, QueryableSource {
|
||||
- returns: the `NSManagedObjectID` for the first `DynamicObject` that satisfies the specified `FetchClause`s, or `nil` if no match was found
|
||||
- throws: `CoreStoreError.persistentStoreNotFound` if the specified entity could not be found in any store's schema.
|
||||
*/
|
||||
public func fetchObjectID<D>(_ from: From<D>, _ fetchClauses: FetchClause...) throws -> NSManagedObjectID? {
|
||||
public func fetchObjectID<O>(_ from: From<O>, _ fetchClauses: FetchClause...) throws -> NSManagedObjectID? {
|
||||
|
||||
CoreStore.assert(
|
||||
Internals.assert(
|
||||
self.isRunningInAllowedQueue(),
|
||||
"Attempted to fetch from a \(cs_typeName(self)) outside its designated queue."
|
||||
"Attempted to fetch from a \(Internals.typeName(self)) outside its designated queue."
|
||||
)
|
||||
return try self.context.fetchObjectID(from, fetchClauses)
|
||||
}
|
||||
@@ -324,11 +324,11 @@ extension BaseDataTransaction: FetchableSource, QueryableSource {
|
||||
- returns: the `NSManagedObjectID` for the first `DynamicObject` that satisfies the specified `FetchClause`s, or `nil` if no match was found
|
||||
- throws: `CoreStoreError.persistentStoreNotFound` if the specified entity could not be found in any store's schema.
|
||||
*/
|
||||
public func fetchObjectID<D>(_ from: From<D>, _ fetchClauses: [FetchClause]) throws -> NSManagedObjectID? {
|
||||
public func fetchObjectID<O>(_ from: From<O>, _ fetchClauses: [FetchClause]) throws -> NSManagedObjectID? {
|
||||
|
||||
CoreStore.assert(
|
||||
Internals.assert(
|
||||
self.isRunningInAllowedQueue(),
|
||||
"Attempted to fetch from a \(cs_typeName(self)) outside its designated queue."
|
||||
"Attempted to fetch from a \(Internals.typeName(self)) outside its designated queue."
|
||||
)
|
||||
return try self.context.fetchObjectID(from, fetchClauses)
|
||||
}
|
||||
@@ -348,9 +348,9 @@ extension BaseDataTransaction: FetchableSource, QueryableSource {
|
||||
*/
|
||||
public func fetchObjectID<B: FetchChainableBuilderType>(_ clauseChain: B) throws -> NSManagedObjectID? {
|
||||
|
||||
CoreStore.assert(
|
||||
Internals.assert(
|
||||
self.isRunningInAllowedQueue(),
|
||||
"Attempted to fetch from a \(cs_typeName(self)) outside its designated queue."
|
||||
"Attempted to fetch from a \(Internals.typeName(self)) outside its designated queue."
|
||||
)
|
||||
return try self.context.fetchObjectID(clauseChain)
|
||||
}
|
||||
@@ -363,11 +363,11 @@ extension BaseDataTransaction: FetchableSource, QueryableSource {
|
||||
- returns: the `NSManagedObjectID` for all `DynamicObject`s that satisfy the specified `FetchClause`s, or an empty array if no match was found
|
||||
- throws: `CoreStoreError.persistentStoreNotFound` if the specified entity could not be found in any store's schema.
|
||||
*/
|
||||
public func fetchObjectIDs<D>(_ from: From<D>, _ fetchClauses: FetchClause...) throws -> [NSManagedObjectID] {
|
||||
public func fetchObjectIDs<O>(_ from: From<O>, _ fetchClauses: FetchClause...) throws -> [NSManagedObjectID] {
|
||||
|
||||
CoreStore.assert(
|
||||
Internals.assert(
|
||||
self.isRunningInAllowedQueue(),
|
||||
"Attempted to fetch from a \(cs_typeName(self)) outside its designated queue."
|
||||
"Attempted to fetch from a \(Internals.typeName(self)) outside its designated queue."
|
||||
)
|
||||
return try self.context.fetchObjectIDs(from, fetchClauses)
|
||||
}
|
||||
@@ -380,11 +380,11 @@ extension BaseDataTransaction: FetchableSource, QueryableSource {
|
||||
- returns: the `NSManagedObjectID` for all `DynamicObject`s that satisfy the specified `FetchClause`s, or an empty array if no match was found
|
||||
- throws: `CoreStoreError.persistentStoreNotFound` if the specified entity could not be found in any store's schema.
|
||||
*/
|
||||
public func fetchObjectIDs<D>(_ from: From<D>, _ fetchClauses: [FetchClause]) throws -> [NSManagedObjectID] {
|
||||
public func fetchObjectIDs<O>(_ from: From<O>, _ fetchClauses: [FetchClause]) throws -> [NSManagedObjectID] {
|
||||
|
||||
CoreStore.assert(
|
||||
Internals.assert(
|
||||
self.isRunningInAllowedQueue(),
|
||||
"Attempted to fetch from a \(cs_typeName(self)) outside its designated queue."
|
||||
"Attempted to fetch from a \(Internals.typeName(self)) outside its designated queue."
|
||||
)
|
||||
return try self.context.fetchObjectIDs(from, fetchClauses)
|
||||
}
|
||||
@@ -404,9 +404,9 @@ extension BaseDataTransaction: FetchableSource, QueryableSource {
|
||||
*/
|
||||
public func fetchObjectIDs<B: FetchChainableBuilderType>(_ clauseChain: B) throws -> [NSManagedObjectID] {
|
||||
|
||||
CoreStore.assert(
|
||||
Internals.assert(
|
||||
self.isRunningInAllowedQueue(),
|
||||
"Attempted to fetch from a \(cs_typeName(self)) outside its designated queue."
|
||||
"Attempted to fetch from a \(Internals.typeName(self)) outside its designated queue."
|
||||
)
|
||||
return try self.context.fetchObjectIDs(clauseChain)
|
||||
}
|
||||
@@ -425,11 +425,11 @@ extension BaseDataTransaction: FetchableSource, QueryableSource {
|
||||
- returns: the result of the the query, or `nil` if no match was found. The type of the return value is specified by the generic type of the `Select<U>` parameter.
|
||||
- throws: `CoreStoreError.persistentStoreNotFound` if the specified entity could not be found in any store's schema.
|
||||
*/
|
||||
public func queryValue<D, U: QueryableAttributeType>(_ from: From<D>, _ selectClause: Select<D, U>, _ queryClauses: QueryClause...) throws -> U? {
|
||||
public func queryValue<O, U: QueryableAttributeType>(_ from: From<O>, _ selectClause: Select<O, U>, _ queryClauses: QueryClause...) throws -> U? {
|
||||
|
||||
CoreStore.assert(
|
||||
Internals.assert(
|
||||
self.isRunningInAllowedQueue(),
|
||||
"Attempted to query from a \(cs_typeName(self)) outside its designated queue."
|
||||
"Attempted to query from a \(Internals.typeName(self)) outside its designated queue."
|
||||
)
|
||||
return try self.context.queryValue(from, selectClause, queryClauses)
|
||||
}
|
||||
@@ -445,11 +445,11 @@ extension BaseDataTransaction: FetchableSource, QueryableSource {
|
||||
- returns: the result of the the query, or `nil` if no match was found. The type of the return value is specified by the generic type of the `Select<U>` parameter.
|
||||
- throws: `CoreStoreError.persistentStoreNotFound` if the specified entity could not be found in any store's schema.
|
||||
*/
|
||||
public func queryValue<D, U: QueryableAttributeType>(_ from: From<D>, _ selectClause: Select<D, U>, _ queryClauses: [QueryClause]) throws -> U? {
|
||||
public func queryValue<O, U: QueryableAttributeType>(_ from: From<O>, _ selectClause: Select<O, U>, _ queryClauses: [QueryClause]) throws -> U? {
|
||||
|
||||
CoreStore.assert(
|
||||
Internals.assert(
|
||||
self.isRunningInAllowedQueue(),
|
||||
"Attempted to query from a \(cs_typeName(self)) outside its designated queue."
|
||||
"Attempted to query from a \(Internals.typeName(self)) outside its designated queue."
|
||||
)
|
||||
return try self.context.queryValue(from, selectClause, queryClauses)
|
||||
}
|
||||
@@ -471,9 +471,9 @@ extension BaseDataTransaction: FetchableSource, QueryableSource {
|
||||
*/
|
||||
public func queryValue<B: QueryChainableBuilderType>(_ clauseChain: B) throws -> B.ResultType? where B.ResultType: QueryableAttributeType {
|
||||
|
||||
CoreStore.assert(
|
||||
Internals.assert(
|
||||
self.isRunningInAllowedQueue(),
|
||||
"Attempted to query from a \(cs_typeName(self)) outside its designated queue."
|
||||
"Attempted to query from a \(Internals.typeName(self)) outside its designated queue."
|
||||
)
|
||||
return try self.context.queryValue(clauseChain.from, clauseChain.select, clauseChain.queryClauses)
|
||||
}
|
||||
@@ -489,11 +489,11 @@ extension BaseDataTransaction: FetchableSource, QueryableSource {
|
||||
- returns: the result of the the query. The type of the return value is specified by the generic type of the `Select<U>` parameter.
|
||||
- throws: `CoreStoreError.persistentStoreNotFound` if the specified entity could not be found in any store's schema.
|
||||
*/
|
||||
public func queryAttributes<D>(_ from: From<D>, _ selectClause: Select<D, NSDictionary>, _ queryClauses: QueryClause...) throws -> [[String: Any]] {
|
||||
public func queryAttributes<O>(_ from: From<O>, _ selectClause: Select<O, NSDictionary>, _ queryClauses: QueryClause...) throws -> [[String: Any]] {
|
||||
|
||||
CoreStore.assert(
|
||||
Internals.assert(
|
||||
self.isRunningInAllowedQueue(),
|
||||
"Attempted to query from a \(cs_typeName(self)) outside its designated queue."
|
||||
"Attempted to query from a \(Internals.typeName(self)) outside its designated queue."
|
||||
)
|
||||
return try self.context.queryAttributes(from, selectClause, queryClauses)
|
||||
}
|
||||
@@ -509,11 +509,11 @@ extension BaseDataTransaction: FetchableSource, QueryableSource {
|
||||
- returns: the result of the the query. The type of the return value is specified by the generic type of the `Select<U>` parameter.
|
||||
- throws: `CoreStoreError.persistentStoreNotFound` if the specified entity could not be found in any store's schema.
|
||||
*/
|
||||
public func queryAttributes<D>(_ from: From<D>, _ selectClause: Select<D, NSDictionary>, _ queryClauses: [QueryClause]) throws -> [[String: Any]] {
|
||||
public func queryAttributes<O>(_ from: From<O>, _ selectClause: Select<O, NSDictionary>, _ queryClauses: [QueryClause]) throws -> [[String: Any]] {
|
||||
|
||||
CoreStore.assert(
|
||||
Internals.assert(
|
||||
self.isRunningInAllowedQueue(),
|
||||
"Attempted to query from a \(cs_typeName(self)) outside its designated queue."
|
||||
"Attempted to query from a \(Internals.typeName(self)) outside its designated queue."
|
||||
)
|
||||
return try self.context.queryAttributes(from, selectClause, queryClauses)
|
||||
}
|
||||
@@ -544,9 +544,9 @@ extension BaseDataTransaction: FetchableSource, QueryableSource {
|
||||
*/
|
||||
public func queryAttributes<B: QueryChainableBuilderType>(_ clauseChain: B) throws -> [[String: Any]] where B.ResultType == NSDictionary {
|
||||
|
||||
CoreStore.assert(
|
||||
Internals.assert(
|
||||
self.isRunningInAllowedQueue(),
|
||||
"Attempted to query from a \(cs_typeName(self)) outside its designated queue."
|
||||
"Attempted to query from a \(Internals.typeName(self)) outside its designated queue."
|
||||
)
|
||||
return try self.context.queryAttributes(clauseChain.from, clauseChain.select, clauseChain.queryClauses)
|
||||
}
|
||||
|
||||
@@ -50,17 +50,17 @@ public /*abstract*/ class BaseDataTransaction {
|
||||
- parameter into: the `Into` clause indicating the destination `NSManagedObject` or `CoreStoreObject` entity type and the destination configuration
|
||||
- returns: a new `NSManagedObject` or `CoreStoreObject` instance of the specified entity type.
|
||||
*/
|
||||
public func create<D>(_ into: Into<D>) -> D {
|
||||
public func create<O>(_ into: Into<O>) -> O {
|
||||
|
||||
let entityClass = into.entityClass
|
||||
CoreStore.assert(
|
||||
Internals.assert(
|
||||
self.isRunningInAllowedQueue(),
|
||||
"Attempted to create an entity of type \(cs_typeName(entityClass)) outside its designated queue."
|
||||
"Attempted to create an entity of type \(Internals.typeName(entityClass)) outside its designated queue."
|
||||
)
|
||||
|
||||
let context = self.context
|
||||
let dataStack = context.parentStack!
|
||||
let entityIdentifier = EntityIdentifier(entityClass)
|
||||
let entityIdentifier = Internals.EntityIdentifier(entityClass)
|
||||
if into.inferStoreIfPossible {
|
||||
|
||||
switch dataStack.persistentStore(
|
||||
@@ -77,10 +77,10 @@ public /*abstract*/ class BaseDataTransaction {
|
||||
)
|
||||
|
||||
case (nil, true):
|
||||
CoreStore.abort("Attempted to create an entity of type \(cs_typeName(entityClass)) with ambiguous destination persistent store, but the configuration name was not specified.")
|
||||
Internals.abort("Attempted to create an entity of type \(Internals.typeName(entityClass)) with ambiguous destination persistent store, but the configuration name was not specified.")
|
||||
|
||||
default:
|
||||
CoreStore.abort("Attempted to create an entity of type \(cs_typeName(entityClass)), but a destination persistent store containing the entity type could not be found.")
|
||||
Internals.abort("Attempted to create an entity of type \(Internals.typeName(entityClass)), but a destination persistent store containing the entity type could not be found.")
|
||||
}
|
||||
}
|
||||
else {
|
||||
@@ -100,16 +100,16 @@ public /*abstract*/ class BaseDataTransaction {
|
||||
)
|
||||
|
||||
case (nil, true):
|
||||
CoreStore.abort("Attempted to create an entity of type \(cs_typeName(entityClass)) with ambiguous destination persistent store, but the configuration name was not specified.")
|
||||
Internals.abort("Attempted to create an entity of type \(Internals.typeName(entityClass)) with ambiguous destination persistent store, but the configuration name was not specified.")
|
||||
|
||||
default:
|
||||
if let configuration = into.configuration {
|
||||
|
||||
CoreStore.abort("Attempted to create an entity of type \(cs_typeName(entityClass)) into the configuration \"\(configuration)\", which it doesn't belong to.")
|
||||
Internals.abort("Attempted to create an entity of type \(Internals.typeName(entityClass)) into the configuration \"\(configuration)\", which it doesn't belong to.")
|
||||
}
|
||||
else {
|
||||
|
||||
CoreStore.abort("Attempted to create an entity of type \(cs_typeName(entityClass)) into the default configuration, which it doesn't belong to.")
|
||||
Internals.abort("Attempted to create an entity of type \(Internals.typeName(entityClass)) into the default configuration, which it doesn't belong to.")
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -121,11 +121,11 @@ public /*abstract*/ class BaseDataTransaction {
|
||||
- parameter object: the `NSManagedObject` or `CoreStoreObject` type to be edited
|
||||
- returns: an editable proxy for the specified `NSManagedObject` or `CoreStoreObject`.
|
||||
*/
|
||||
public func edit<D: DynamicObject>(_ object: D?) -> D? {
|
||||
public func edit<O: DynamicObject>(_ object: O?) -> O? {
|
||||
|
||||
CoreStore.assert(
|
||||
Internals.assert(
|
||||
self.isRunningInAllowedQueue(),
|
||||
"Attempted to update an entity of type \(cs_typeName(object)) outside its designated queue."
|
||||
"Attempted to update an entity of type \(Internals.typeName(object)) outside its designated queue."
|
||||
)
|
||||
guard let object = object else {
|
||||
|
||||
@@ -141,62 +141,69 @@ public /*abstract*/ class BaseDataTransaction {
|
||||
- parameter objectID: the `NSManagedObjectID` for the object to be edited
|
||||
- returns: an editable proxy for the specified `NSManagedObject` or `CoreStoreObject`.
|
||||
*/
|
||||
public func edit<D>(_ into: Into<D>, _ objectID: NSManagedObjectID) -> D? {
|
||||
public func edit<O>(_ into: Into<O>, _ objectID: NSManagedObjectID) -> O? {
|
||||
|
||||
CoreStore.assert(
|
||||
Internals.assert(
|
||||
self.isRunningInAllowedQueue(),
|
||||
"Attempted to update an entity of type \(cs_typeName(into.entityClass)) outside its designated queue."
|
||||
"Attempted to update an entity of type \(Internals.typeName(into.entityClass)) outside its designated queue."
|
||||
)
|
||||
CoreStore.assert(
|
||||
Internals.assert(
|
||||
into.inferStoreIfPossible
|
||||
|| (into.configuration ?? DataStack.defaultConfigurationName) == objectID.persistentStore?.configurationName,
|
||||
"Attempted to update an entity of type \(cs_typeName(into.entityClass)) but the specified persistent store do not match the `NSManagedObjectID`."
|
||||
"Attempted to update an entity of type \(Internals.typeName(into.entityClass)) but the specified persistent store do not match the `NSManagedObjectID`."
|
||||
)
|
||||
return self.fetchExisting(objectID)
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
Deletes a specified `NSManagedObject` or `CoreStoreObject`.
|
||||
|
||||
- parameter object: the `NSManagedObject` or `CoreStoreObject` to be deleted
|
||||
Deletes the objects with the specified `NSManagedObjectID`s.
|
||||
|
||||
- parameter objectIDs: the `NSManagedObjectID`s of the objects to delete
|
||||
*/
|
||||
public func delete<D: DynamicObject>(_ object: D?) {
|
||||
|
||||
CoreStore.assert(
|
||||
public func delete<S: Sequence>(objectIDs: S) where S.Iterator.Element: NSManagedObjectID {
|
||||
|
||||
Internals.assert(
|
||||
self.isRunningInAllowedQueue(),
|
||||
"Attempted to delete an entity outside its designated queue."
|
||||
)
|
||||
let context = self.context
|
||||
object
|
||||
.flatMap(context.fetchExisting)
|
||||
.flatMap({ context.delete($0.cs_toRaw()) })
|
||||
objectIDs.forEach {
|
||||
|
||||
context.fetchExisting($0).map(context.delete(_:))
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
Deletes the specified `NSManagedObject`s or `CoreStoreObject`s.
|
||||
Deletes the specified `NSManagedObject`s or `CoreStoreObject`s represented by series of `ObjectRepresentation`s.
|
||||
|
||||
- parameter object1: the `NSManagedObject` or `CoreStoreObject` to be deleted
|
||||
- parameter object2: another `NSManagedObject` or `CoreStoreObject` to be deleted
|
||||
- parameter objects: other `NSManagedObject`s or `CoreStoreObject`s to be deleted
|
||||
- parameter object: the `ObjectRepresentation` representing an `NSManagedObject` or `CoreStoreObject` to be deleted
|
||||
- parameter objects: other `ObjectRepresentation`s representing `NSManagedObject`s or `CoreStoreObject`s to be deleted
|
||||
*/
|
||||
public func delete<D: DynamicObject>(_ object1: D?, _ object2: D?, _ objects: D?...) {
|
||||
public func delete<O: ObjectRepresentation>(_ object: O?, _ objects: O?...) {
|
||||
|
||||
self.delete(([object1, object2] + objects).compactMap { $0 })
|
||||
Internals.assert(
|
||||
self.isRunningInAllowedQueue(),
|
||||
"Attempted to delete an entity outside its designated queue."
|
||||
)
|
||||
self.delete(([object] + objects).compactMap { $0 })
|
||||
}
|
||||
|
||||
/**
|
||||
Deletes the specified `NSManagedObject`s or `CoreStoreObject`s.
|
||||
Deletes the specified `NSManagedObject`s or `CoreStoreObject`s represented by an `ObjectRepresenation`.
|
||||
|
||||
- parameter objects: the `NSManagedObject`s or `CoreStoreObject`s to be deleted
|
||||
- parameter objects: the `ObjectRepresenation`s representing `NSManagedObject`s or `CoreStoreObject`s to be deleted
|
||||
*/
|
||||
public func delete<S: Sequence>(_ objects: S) where S.Iterator.Element: DynamicObject {
|
||||
public func delete<S: Sequence>(_ objects: S) where S.Iterator.Element: ObjectRepresentation {
|
||||
|
||||
CoreStore.assert(
|
||||
Internals.assert(
|
||||
self.isRunningInAllowedQueue(),
|
||||
"Attempted to delete entities outside their designated queue."
|
||||
)
|
||||
let context = self.context
|
||||
objects.forEach { context.fetchExisting($0).flatMap({ context.delete($0.cs_toRaw()) }) }
|
||||
objects.forEach {
|
||||
|
||||
$0.asEditable(in: self).map({ context.delete($0.cs_toRaw()) })
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -204,7 +211,7 @@ public /*abstract*/ class BaseDataTransaction {
|
||||
*/
|
||||
public func refreshAndMergeAllObjects() {
|
||||
|
||||
CoreStore.assert(
|
||||
Internals.assert(
|
||||
self.isRunningInAllowedQueue(),
|
||||
"Attempted to refresh entities outside their designated queue."
|
||||
)
|
||||
@@ -213,6 +220,25 @@ public /*abstract*/ class BaseDataTransaction {
|
||||
|
||||
|
||||
// MARK: Inspecting Pending Objects
|
||||
|
||||
/**
|
||||
Returns `true` if the object has any property values changed. This method should not be called after the `commit()` method was called.
|
||||
|
||||
- parameter object: the `DynamicObject` instance
|
||||
- returns: `true` if the object has any property values changed.
|
||||
*/
|
||||
public func objectHasPersistentChangedValues<O: DynamicObject>(_ object: O) -> Bool {
|
||||
|
||||
Internals.assert(
|
||||
self.isRunningInAllowedQueue(),
|
||||
"Attempted to access inserted objects from a \(Internals.typeName(self)) outside its designated queue."
|
||||
)
|
||||
Internals.assert(
|
||||
!self.isCommitted,
|
||||
"Attempted to access inserted objects from an already committed \(Internals.typeName(self))."
|
||||
)
|
||||
return object.cs_toRaw().hasPersistentChangedValues
|
||||
}
|
||||
|
||||
/**
|
||||
Returns all pending `DynamicObject`s of the specified type that were inserted to the transaction. This method should not be called after the `commit()` method was called.
|
||||
@@ -220,15 +246,15 @@ public /*abstract*/ class BaseDataTransaction {
|
||||
- parameter entity: the `DynamicObject` subclass to filter
|
||||
- returns: a `Set` of pending `DynamicObject`s of the specified type that were inserted to the transaction.
|
||||
*/
|
||||
public func insertedObjects<D: DynamicObject>(_ entity: D.Type) -> Set<D> {
|
||||
public func insertedObjects<O: DynamicObject>(_ entity: O.Type) -> Set<O> {
|
||||
|
||||
CoreStore.assert(
|
||||
Internals.assert(
|
||||
self.isRunningInAllowedQueue(),
|
||||
"Attempted to access inserted objects from a \(cs_typeName(self)) outside its designated queue."
|
||||
"Attempted to access inserted objects from a \(Internals.typeName(self)) outside its designated queue."
|
||||
)
|
||||
CoreStore.assert(
|
||||
Internals.assert(
|
||||
!self.isCommitted,
|
||||
"Attempted to access inserted objects from an already committed \(cs_typeName(self))."
|
||||
"Attempted to access inserted objects from an already committed \(Internals.typeName(self))."
|
||||
)
|
||||
return Set(self.context.insertedObjects.compactMap({ entity.cs_matches(object: $0) ? entity.cs_fromRaw(object: $0) : nil }))
|
||||
}
|
||||
@@ -240,13 +266,13 @@ public /*abstract*/ class BaseDataTransaction {
|
||||
*/
|
||||
public func insertedObjectIDs() -> Set<NSManagedObjectID> {
|
||||
|
||||
CoreStore.assert(
|
||||
Internals.assert(
|
||||
self.isRunningInAllowedQueue(),
|
||||
"Attempted to access inserted object IDs from a \(cs_typeName(self)) outside its designated queue."
|
||||
"Attempted to access inserted object IDs from a \(Internals.typeName(self)) outside its designated queue."
|
||||
)
|
||||
CoreStore.assert(
|
||||
Internals.assert(
|
||||
!self.isCommitted,
|
||||
"Attempted to access inserted objects IDs from an already committed \(cs_typeName(self))."
|
||||
"Attempted to access inserted objects IDs from an already committed \(Internals.typeName(self))."
|
||||
)
|
||||
return Set(self.context.insertedObjects.map { $0.objectID })
|
||||
}
|
||||
@@ -257,15 +283,15 @@ public /*abstract*/ class BaseDataTransaction {
|
||||
- parameter entity: the `DynamicObject` subclass to filter
|
||||
- returns: a `Set` of pending `NSManagedObjectID`s of the specified type that were inserted to the transaction.
|
||||
*/
|
||||
public func insertedObjectIDs<D: DynamicObject>(_ entity: D.Type) -> Set<NSManagedObjectID> {
|
||||
public func insertedObjectIDs<O: DynamicObject>(_ entity: O.Type) -> Set<NSManagedObjectID> {
|
||||
|
||||
CoreStore.assert(
|
||||
Internals.assert(
|
||||
self.isRunningInAllowedQueue(),
|
||||
"Attempted to access inserted object IDs from a \(cs_typeName(self)) outside its designated queue."
|
||||
"Attempted to access inserted object IDs from a \(Internals.typeName(self)) outside its designated queue."
|
||||
)
|
||||
CoreStore.assert(
|
||||
Internals.assert(
|
||||
!self.isCommitted,
|
||||
"Attempted to access inserted objects IDs from an already committed \(cs_typeName(self))."
|
||||
"Attempted to access inserted objects IDs from an already committed \(Internals.typeName(self))."
|
||||
)
|
||||
return Set(self.context.insertedObjects.compactMap({ entity.cs_matches(object: $0) ? $0.objectID : nil }))
|
||||
}
|
||||
@@ -276,15 +302,15 @@ public /*abstract*/ class BaseDataTransaction {
|
||||
- parameter entity: the `DynamicObject` subclass to filter
|
||||
- returns: a `Set` of pending `DynamicObject`s of the specified type that were updated in the transaction.
|
||||
*/
|
||||
public func updatedObjects<D: DynamicObject>(_ entity: D.Type) -> Set<D> {
|
||||
public func updatedObjects<O: DynamicObject>(_ entity: O.Type) -> Set<O> {
|
||||
|
||||
CoreStore.assert(
|
||||
Internals.assert(
|
||||
self.isRunningInAllowedQueue(),
|
||||
"Attempted to access updated objects from a \(cs_typeName(self)) outside its designated queue."
|
||||
"Attempted to access updated objects from a \(Internals.typeName(self)) outside its designated queue."
|
||||
)
|
||||
CoreStore.assert(
|
||||
Internals.assert(
|
||||
!self.isCommitted,
|
||||
"Attempted to access updated objects from an already committed \(cs_typeName(self))."
|
||||
"Attempted to access updated objects from an already committed \(Internals.typeName(self))."
|
||||
)
|
||||
return Set(self.context.updatedObjects.compactMap({ entity.cs_matches(object: $0) ? entity.cs_fromRaw(object: $0) : nil }))
|
||||
}
|
||||
@@ -296,13 +322,13 @@ public /*abstract*/ class BaseDataTransaction {
|
||||
*/
|
||||
public func updatedObjectIDs() -> Set<NSManagedObjectID> {
|
||||
|
||||
CoreStore.assert(
|
||||
Internals.assert(
|
||||
self.isRunningInAllowedQueue(),
|
||||
"Attempted to access updated object IDs from a \(cs_typeName(self)) outside its designated queue."
|
||||
"Attempted to access updated object IDs from a \(Internals.typeName(self)) outside its designated queue."
|
||||
)
|
||||
CoreStore.assert(
|
||||
Internals.assert(
|
||||
!self.isCommitted,
|
||||
"Attempted to access updated object IDs from an already committed \(cs_typeName(self))."
|
||||
"Attempted to access updated object IDs from an already committed \(Internals.typeName(self))."
|
||||
)
|
||||
return Set(self.context.updatedObjects.map { $0.objectID })
|
||||
}
|
||||
@@ -313,15 +339,15 @@ public /*abstract*/ class BaseDataTransaction {
|
||||
- parameter entity: the `DynamicObject` subclass to filter
|
||||
- returns: a `Set` of pending `NSManagedObjectID`s of the specified type that were updated in the transaction.
|
||||
*/
|
||||
public func updatedObjectIDs<D: DynamicObject>(_ entity: D.Type) -> Set<NSManagedObjectID> {
|
||||
public func updatedObjectIDs<O: DynamicObject>(_ entity: O.Type) -> Set<NSManagedObjectID> {
|
||||
|
||||
CoreStore.assert(
|
||||
Internals.assert(
|
||||
self.isRunningInAllowedQueue(),
|
||||
"Attempted to access updated object IDs from a \(cs_typeName(self)) outside its designated queue."
|
||||
"Attempted to access updated object IDs from a \(Internals.typeName(self)) outside its designated queue."
|
||||
)
|
||||
CoreStore.assert(
|
||||
Internals.assert(
|
||||
!self.isCommitted,
|
||||
"Attempted to access updated object IDs from an already committed \(cs_typeName(self))."
|
||||
"Attempted to access updated object IDs from an already committed \(Internals.typeName(self))."
|
||||
)
|
||||
return Set(self.context.updatedObjects.compactMap({ entity.cs_matches(object: $0) ? $0.objectID : nil }))
|
||||
}
|
||||
@@ -332,15 +358,15 @@ public /*abstract*/ class BaseDataTransaction {
|
||||
- parameter entity: the `DynamicObject` subclass to filter
|
||||
- returns: a `Set` of pending `DynamicObject`s of the specified type that were deleted from the transaction.
|
||||
*/
|
||||
public func deletedObjects<D: DynamicObject>(_ entity: D.Type) -> Set<D> {
|
||||
public func deletedObjects<O: DynamicObject>(_ entity: O.Type) -> Set<O> {
|
||||
|
||||
CoreStore.assert(
|
||||
Internals.assert(
|
||||
self.isRunningInAllowedQueue(),
|
||||
"Attempted to access deleted objects from a \(cs_typeName(self)) outside its designated queue."
|
||||
"Attempted to access deleted objects from a \(Internals.typeName(self)) outside its designated queue."
|
||||
)
|
||||
CoreStore.assert(
|
||||
Internals.assert(
|
||||
!self.isCommitted,
|
||||
"Attempted to access deleted objects from an already committed \(cs_typeName(self))."
|
||||
"Attempted to access deleted objects from an already committed \(Internals.typeName(self))."
|
||||
)
|
||||
return Set(self.context.deletedObjects.compactMap({ entity.cs_matches(object: $0) ? entity.cs_fromRaw(object: $0) : nil }))
|
||||
}
|
||||
@@ -353,13 +379,13 @@ public /*abstract*/ class BaseDataTransaction {
|
||||
*/
|
||||
public func deletedObjectIDs() -> Set<NSManagedObjectID> {
|
||||
|
||||
CoreStore.assert(
|
||||
Internals.assert(
|
||||
self.isRunningInAllowedQueue(),
|
||||
"Attempted to access deleted object IDs from a \(cs_typeName(self)) outside its designated queue."
|
||||
"Attempted to access deleted object IDs from a \(Internals.typeName(self)) outside its designated queue."
|
||||
)
|
||||
CoreStore.assert(
|
||||
Internals.assert(
|
||||
!self.isCommitted,
|
||||
"Attempted to access deleted object IDs from an already committed \(cs_typeName(self))."
|
||||
"Attempted to access deleted object IDs from an already committed \(Internals.typeName(self))."
|
||||
)
|
||||
return Set(self.context.deletedObjects.map { $0.objectID })
|
||||
}
|
||||
@@ -370,15 +396,15 @@ public /*abstract*/ class BaseDataTransaction {
|
||||
- parameter entity: the `DynamicObject` subclass to filter
|
||||
- returns: a `Set` of pending `NSManagedObjectID`s of the specified type that were deleted from the transaction.
|
||||
*/
|
||||
public func deletedObjectIDs<D: DynamicObject>(_ entity: D.Type) -> Set<NSManagedObjectID> {
|
||||
public func deletedObjectIDs<O: DynamicObject>(_ entity: O.Type) -> Set<NSManagedObjectID> {
|
||||
|
||||
CoreStore.assert(
|
||||
Internals.assert(
|
||||
self.isRunningInAllowedQueue(),
|
||||
"Attempted to access deleted object IDs from a \(cs_typeName(self)) outside its designated queue."
|
||||
"Attempted to access deleted object IDs from a \(Internals.typeName(self)) outside its designated queue."
|
||||
)
|
||||
CoreStore.assert(
|
||||
Internals.assert(
|
||||
!self.isCommitted,
|
||||
"Attempted to access deleted object IDs from an already committed \(cs_typeName(self))."
|
||||
"Attempted to access deleted object IDs from an already committed \(Internals.typeName(self))."
|
||||
)
|
||||
return Set(self.context.deletedObjects.compactMap({ entity.cs_matches(object: $0) ? $0.objectID : nil }))
|
||||
}
|
||||
|
||||
@@ -46,13 +46,13 @@ public final class CSAsynchronousDataTransaction: CSBaseDataTransaction, CoreSto
|
||||
@objc
|
||||
public func commitWithSuccess(_ success: (() -> Void)?, failure: ((CSError) -> Void)?) {
|
||||
|
||||
CoreStore.assert(
|
||||
Internals.assert(
|
||||
self.bridgeToSwift.transactionQueue.cs_isCurrentExecutionContext(),
|
||||
"Attempted to commit a \(cs_typeName(self)) outside its designated queue."
|
||||
"Attempted to commit a \(Internals.typeName(self)) outside its designated queue."
|
||||
)
|
||||
CoreStore.assert(
|
||||
Internals.assert(
|
||||
!self.bridgeToSwift.isCommitted,
|
||||
"Attempted to commit a \(cs_typeName(self)) more than once."
|
||||
"Attempted to commit a \(Internals.typeName(self)) more than once."
|
||||
)
|
||||
self.bridgeToSwift.autoCommit { (_, error) in
|
||||
|
||||
@@ -72,7 +72,7 @@ public final class CSAsynchronousDataTransaction: CSBaseDataTransaction, CoreSto
|
||||
|
||||
public override var description: String {
|
||||
|
||||
return "(\(String(reflecting: type(of: self)))) \(self.bridgeToSwift.coreStoreDumpString)"
|
||||
return "(\(String(reflecting: Self.self))) \(self.bridgeToSwift.coreStoreDumpString)"
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -89,9 +89,9 @@ extension CSBaseDataTransaction {
|
||||
@objc
|
||||
public func fetchOneFrom(_ from: CSFrom, fetchClauses: [CSFetchClause]) -> Any? {
|
||||
|
||||
CoreStore.assert(
|
||||
Internals.assert(
|
||||
self.swiftTransaction.isRunningInAllowedQueue(),
|
||||
"Attempted to fetch from a \(cs_typeName(self)) outside its designated queue."
|
||||
"Attempted to fetch from a \(Internals.typeName(self)) outside its designated queue."
|
||||
)
|
||||
return (try? self.swiftTransaction.context.fetchOne(from, fetchClauses))?
|
||||
.flatMap({ $0 })
|
||||
@@ -107,9 +107,9 @@ extension CSBaseDataTransaction {
|
||||
@objc
|
||||
public func fetchAllFrom(_ from: CSFrom, fetchClauses: [CSFetchClause]) -> [Any]? {
|
||||
|
||||
CoreStore.assert(
|
||||
Internals.assert(
|
||||
self.swiftTransaction.isRunningInAllowedQueue(),
|
||||
"Attempted to fetch from a \(cs_typeName(self)) outside its designated queue."
|
||||
"Attempted to fetch from a \(Internals.typeName(self)) outside its designated queue."
|
||||
)
|
||||
return (try? self.swiftTransaction.context.fetchAll(from, fetchClauses))
|
||||
.flatMap({ $0 })
|
||||
@@ -125,9 +125,9 @@ extension CSBaseDataTransaction {
|
||||
@objc
|
||||
public func fetchCountFrom(_ from: CSFrom, fetchClauses: [CSFetchClause]) -> NSNumber? {
|
||||
|
||||
CoreStore.assert(
|
||||
Internals.assert(
|
||||
self.swiftTransaction.isRunningInAllowedQueue(),
|
||||
"Attempted to fetch from a \(cs_typeName(self)) outside its designated queue."
|
||||
"Attempted to fetch from a \(Internals.typeName(self)) outside its designated queue."
|
||||
)
|
||||
return (try? self.swiftTransaction.context.fetchCount(from, fetchClauses))
|
||||
.flatMap({ NSNumber(value: $0) })
|
||||
@@ -143,9 +143,9 @@ extension CSBaseDataTransaction {
|
||||
@objc
|
||||
public func fetchObjectIDFrom(_ from: CSFrom, fetchClauses: [CSFetchClause]) -> NSManagedObjectID? {
|
||||
|
||||
CoreStore.assert(
|
||||
Internals.assert(
|
||||
self.swiftTransaction.isRunningInAllowedQueue(),
|
||||
"Attempted to fetch from a \(cs_typeName(self)) outside its designated queue."
|
||||
"Attempted to fetch from a \(Internals.typeName(self)) outside its designated queue."
|
||||
)
|
||||
return (try? self.swiftTransaction.context.fetchObjectID(from, fetchClauses))
|
||||
.flatMap({ $0 })
|
||||
@@ -164,9 +164,9 @@ extension CSBaseDataTransaction {
|
||||
@objc
|
||||
public func queryValueFrom(_ from: CSFrom, selectClause: CSSelect, queryClauses: [CSQueryClause]) -> Any? {
|
||||
|
||||
CoreStore.assert(
|
||||
Internals.assert(
|
||||
self.swiftTransaction.isRunningInAllowedQueue(),
|
||||
"Attempted to query from a \(cs_typeName(self)) outside its designated queue."
|
||||
"Attempted to query from a \(Internals.typeName(self)) outside its designated queue."
|
||||
)
|
||||
return (try? self.swiftTransaction.context.queryValue(from, selectClause, queryClauses))
|
||||
.flatMap({ $0 })
|
||||
@@ -185,9 +185,9 @@ extension CSBaseDataTransaction {
|
||||
@objc
|
||||
public func queryAttributesFrom(_ from: CSFrom, selectClause: CSSelect, queryClauses: [CSQueryClause]) -> [[String: Any]]? {
|
||||
|
||||
CoreStore.assert(
|
||||
Internals.assert(
|
||||
self.swiftTransaction.isRunningInAllowedQueue(),
|
||||
"Attempted to query from a \(cs_typeName(self)) outside its designated queue."
|
||||
"Attempted to query from a \(Internals.typeName(self)) outside its designated queue."
|
||||
)
|
||||
return (try? self.swiftTransaction.context.queryAttributes(from, selectClause, queryClauses))
|
||||
.flatMap({ $0 })
|
||||
|
||||
@@ -29,6 +29,7 @@ import CoreData
|
||||
|
||||
// MARK: - CSCoreStore
|
||||
|
||||
@available(*, deprecated, message: "Call methods directly from the CSDataStack instead")
|
||||
extension CSCoreStore {
|
||||
|
||||
/**
|
||||
|
||||
@@ -29,6 +29,7 @@ import CoreData
|
||||
|
||||
// MARK: - CSCoreStore
|
||||
|
||||
@available(*, deprecated, message: "Call methods directly from the CSDataStack instead")
|
||||
@available(macOS 10.12, *)
|
||||
extension CSCoreStore {
|
||||
|
||||
|
||||
@@ -29,6 +29,7 @@ import CoreData
|
||||
|
||||
// MARK: - CSCoreStore
|
||||
|
||||
@available(*, deprecated, message: "Call methods directly from the DataStack instead")
|
||||
extension CSCoreStore {
|
||||
|
||||
/**
|
||||
|
||||
@@ -29,6 +29,7 @@ import CoreData
|
||||
|
||||
// MARK: - CSCoreStore
|
||||
|
||||
@available(*, deprecated, message: "Call methods directly from the CSDataStack instead")
|
||||
extension CSCoreStore {
|
||||
|
||||
/**
|
||||
@@ -37,7 +38,7 @@ extension CSCoreStore {
|
||||
@objc
|
||||
public static var modelVersion: String {
|
||||
|
||||
return CoreStore.modelVersion
|
||||
return self.defaultStack.modelVersion
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -46,7 +47,7 @@ extension CSCoreStore {
|
||||
@objc
|
||||
public static func entityTypesByNameForType(_ type: NSManagedObject.Type) -> [EntityName: NSManagedObject.Type] {
|
||||
|
||||
return CoreStore.entityTypesByName(for: type)
|
||||
return self.defaultStack.bridgeToSwift.entityTypesByName(for: type)
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -55,7 +56,7 @@ extension CSCoreStore {
|
||||
@objc
|
||||
public static func entityDescriptionForClass(_ type: NSManagedObject.Type) -> NSEntityDescription? {
|
||||
|
||||
return CoreStore.entityDescription(for: type)
|
||||
return self.defaultStack.bridgeToSwift.entityDescription(for: type)
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -28,6 +28,7 @@ import Foundation
|
||||
|
||||
// MARK: - CSCoreStore
|
||||
|
||||
@available(*, deprecated, message: "Call methods directly from the CSDataStack instead")
|
||||
extension CSCoreStore {
|
||||
|
||||
/**
|
||||
@@ -64,7 +65,7 @@ extension CSCoreStore {
|
||||
|
||||
return bridge {
|
||||
|
||||
CoreStore.beginUnsafe()
|
||||
self.defaultStack.bridgeToSwift.beginUnsafe()
|
||||
}
|
||||
}
|
||||
|
||||
@@ -79,7 +80,7 @@ extension CSCoreStore {
|
||||
|
||||
return bridge {
|
||||
|
||||
CoreStore.beginUnsafe(supportsUndo: supportsUndo)
|
||||
self.defaultStack.bridgeToSwift.beginUnsafe(supportsUndo: supportsUndo)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -89,6 +90,6 @@ extension CSCoreStore {
|
||||
@objc
|
||||
public static func refreshAndMergeAllObjects() {
|
||||
|
||||
CoreStore.refreshAndMergeAllObjects()
|
||||
self.defaultStack.refreshAndMergeAllObjects()
|
||||
}
|
||||
}
|
||||
|
||||
@@ -33,6 +33,7 @@ import Foundation
|
||||
|
||||
- SeeAlso: `CoreStore`
|
||||
*/
|
||||
@available(*, deprecated, message: "Call methods directly from the CSDataStack instead")
|
||||
@objc
|
||||
public final class CSCoreStore: NSObject {
|
||||
|
||||
@@ -45,14 +46,8 @@ public final class CSCoreStore: NSObject {
|
||||
@objc
|
||||
public static var defaultStack: CSDataStack {
|
||||
|
||||
get {
|
||||
|
||||
return CoreStore.defaultStack.bridgeToObjectiveC
|
||||
}
|
||||
set {
|
||||
|
||||
CoreStore.defaultStack = newValue.bridgeToSwift
|
||||
}
|
||||
get { return CoreStoreDefaults.dataStack.bridgeToObjectiveC }
|
||||
set { CoreStoreDefaults.dataStack = newValue.bridgeToSwift }
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -36,7 +36,7 @@ extension CSDataStack {
|
||||
Creates a `CSObjectMonitor` for the specified `NSManagedObject`. Multiple `ObjectObserver`s may then register themselves to be notified when changes are made to the `NSManagedObject`.
|
||||
|
||||
- parameter object: the `NSManagedObject` to observe changes from
|
||||
- returns: a `ObjectMonitor` that monitors changes to `object`
|
||||
- returns: an `ObjectMonitor` that monitors changes to `object`
|
||||
*/
|
||||
@objc
|
||||
public func monitorObject(_ object: NSManagedObject) -> CSObjectMonitor {
|
||||
@@ -54,11 +54,11 @@ extension CSDataStack {
|
||||
@objc
|
||||
public func monitorListFrom(_ from: CSFrom, fetchClauses: [CSFetchClause]) -> CSListMonitor {
|
||||
|
||||
CoreStore.assert(
|
||||
Internals.assert(
|
||||
Thread.isMainThread,
|
||||
"Attempted to observe objects from \(cs_typeName(self)) outside the main thread."
|
||||
"Attempted to observe objects from \(Internals.typeName(self)) outside the main thread."
|
||||
)
|
||||
CoreStore.assert(
|
||||
Internals.assert(
|
||||
fetchClauses.contains { $0 is CSOrderBy },
|
||||
"A CSListMonitor requires a CSOrderBy clause."
|
||||
)
|
||||
@@ -83,11 +83,11 @@ extension CSDataStack {
|
||||
@objc
|
||||
public func monitorListByCreatingAsynchronously(_ createAsynchronously: @escaping (CSListMonitor) -> Void, from: CSFrom, fetchClauses: [CSFetchClause]) {
|
||||
|
||||
CoreStore.assert(
|
||||
Internals.assert(
|
||||
Thread.isMainThread,
|
||||
"Attempted to observe objects from \(cs_typeName(self)) outside the main thread."
|
||||
"Attempted to observe objects from \(Internals.typeName(self)) outside the main thread."
|
||||
)
|
||||
CoreStore.assert(
|
||||
Internals.assert(
|
||||
fetchClauses.contains { $0 is CSOrderBy },
|
||||
"A CSListMonitor requires an CSOrderBy clause."
|
||||
)
|
||||
@@ -117,11 +117,11 @@ extension CSDataStack {
|
||||
@objc
|
||||
public func monitorSectionedListFrom(_ from: CSFrom, sectionBy: CSSectionBy, fetchClauses: [CSFetchClause]) -> CSListMonitor {
|
||||
|
||||
CoreStore.assert(
|
||||
Internals.assert(
|
||||
Thread.isMainThread,
|
||||
"Attempted to observe objects from \(cs_typeName(self)) outside the main thread."
|
||||
"Attempted to observe objects from \(Internals.typeName(self)) outside the main thread."
|
||||
)
|
||||
CoreStore.assert(
|
||||
Internals.assert(
|
||||
fetchClauses.contains { $0 is CSOrderBy },
|
||||
"A CSListMonitor requires an CSOrderBy clause."
|
||||
)
|
||||
@@ -146,11 +146,11 @@ extension CSDataStack {
|
||||
*/
|
||||
public func monitorSectionedListByCreatingAsynchronously(_ createAsynchronously: @escaping (CSListMonitor) -> Void, from: CSFrom, sectionBy: CSSectionBy, fetchClauses: [CSFetchClause]) {
|
||||
|
||||
CoreStore.assert(
|
||||
Internals.assert(
|
||||
Thread.isMainThread,
|
||||
"Attempted to observe objects from \(cs_typeName(self)) outside the main thread."
|
||||
"Attempted to observe objects from \(Internals.typeName(self)) outside the main thread."
|
||||
)
|
||||
CoreStore.assert(
|
||||
Internals.assert(
|
||||
fetchClauses.contains { $0 is CSOrderBy },
|
||||
"A CSListMonitor requires an CSOrderBy clause."
|
||||
)
|
||||
|
||||
@@ -89,9 +89,9 @@ extension CSDataStack {
|
||||
@objc
|
||||
public func fetchOneFrom(_ from: CSFrom, fetchClauses: [CSFetchClause]) -> Any? {
|
||||
|
||||
CoreStore.assert(
|
||||
Internals.assert(
|
||||
Thread.isMainThread,
|
||||
"Attempted to fetch from a \(cs_typeName(self)) outside the main thread."
|
||||
"Attempted to fetch from a \(Internals.typeName(self)) outside the main thread."
|
||||
)
|
||||
return (try? self.bridgeToSwift.mainContext.fetchOne(from, fetchClauses))?
|
||||
.flatMap({ $0 })
|
||||
@@ -107,9 +107,9 @@ extension CSDataStack {
|
||||
@objc
|
||||
public func fetchAllFrom(_ from: CSFrom, fetchClauses: [CSFetchClause]) -> [Any]? {
|
||||
|
||||
CoreStore.assert(
|
||||
Internals.assert(
|
||||
Thread.isMainThread,
|
||||
"Attempted to fetch from a \(cs_typeName(self)) outside the main thread."
|
||||
"Attempted to fetch from a \(Internals.typeName(self)) outside the main thread."
|
||||
)
|
||||
return (try? self.bridgeToSwift.mainContext.fetchAll(from, fetchClauses))
|
||||
.flatMap({ $0 })
|
||||
@@ -125,9 +125,9 @@ extension CSDataStack {
|
||||
@objc
|
||||
public func fetchCountFrom(_ from: CSFrom, fetchClauses: [CSFetchClause]) -> NSNumber? {
|
||||
|
||||
CoreStore.assert(
|
||||
Internals.assert(
|
||||
Thread.isMainThread,
|
||||
"Attempted to fetch from a \(cs_typeName(self)) outside the main thread."
|
||||
"Attempted to fetch from a \(Internals.typeName(self)) outside the main thread."
|
||||
)
|
||||
return (try? self.bridgeToSwift.mainContext.fetchCount(from, fetchClauses))
|
||||
.flatMap({ NSNumber(value: $0) })
|
||||
@@ -143,9 +143,9 @@ extension CSDataStack {
|
||||
@objc
|
||||
public func fetchObjectIDFrom(_ from: CSFrom, fetchClauses: [CSFetchClause]) -> NSManagedObjectID? {
|
||||
|
||||
CoreStore.assert(
|
||||
Internals.assert(
|
||||
Thread.isMainThread,
|
||||
"Attempted to fetch from a \(cs_typeName(self)) outside the main thread."
|
||||
"Attempted to fetch from a \(Internals.typeName(self)) outside the main thread."
|
||||
)
|
||||
return (try? self.bridgeToSwift.mainContext.fetchObjectID(from, fetchClauses))?
|
||||
.flatMap({ $0 })
|
||||
@@ -161,9 +161,9 @@ extension CSDataStack {
|
||||
@objc
|
||||
public func fetchObjectIDsFrom(_ from: CSFrom, fetchClauses: [CSFetchClause]) -> [NSManagedObjectID]? {
|
||||
|
||||
CoreStore.assert(
|
||||
Internals.assert(
|
||||
Thread.isMainThread,
|
||||
"Attempted to fetch from a \(cs_typeName(self)) outside the main thread."
|
||||
"Attempted to fetch from a \(Internals.typeName(self)) outside the main thread."
|
||||
)
|
||||
return (try? self.bridgeToSwift.mainContext.fetchObjectIDs(from, fetchClauses))
|
||||
.flatMap({ $0 })
|
||||
@@ -182,9 +182,9 @@ extension CSDataStack {
|
||||
@objc
|
||||
public func queryValueFrom(_ from: CSFrom, selectClause: CSSelect, queryClauses: [CSQueryClause]) -> Any? {
|
||||
|
||||
CoreStore.assert(
|
||||
Internals.assert(
|
||||
Thread.isMainThread,
|
||||
"Attempted to query from a \(cs_typeName(self)) outside the main thread."
|
||||
"Attempted to query from a \(Internals.typeName(self)) outside the main thread."
|
||||
)
|
||||
return (try? self.bridgeToSwift.mainContext.queryValue(from, selectClause, queryClauses))
|
||||
.flatMap({ $0 })
|
||||
@@ -203,9 +203,9 @@ extension CSDataStack {
|
||||
@objc
|
||||
public func queryAttributesFrom(_ from: CSFrom, selectClause: CSSelect, queryClauses: [CSQueryClause]) -> [[String: Any]]? {
|
||||
|
||||
CoreStore.assert(
|
||||
Internals.assert(
|
||||
Thread.isMainThread,
|
||||
"Attempted to query from a \(cs_typeName(self)) outside the main thread."
|
||||
"Attempted to query from a \(Internals.typeName(self)) outside the main thread."
|
||||
)
|
||||
return (try? self.bridgeToSwift.mainContext.queryAttributes(from, selectClause, queryClauses))
|
||||
.flatMap({ $0 })
|
||||
|
||||
@@ -45,9 +45,9 @@ extension CSDataStack {
|
||||
closure(csTransaction)
|
||||
if !transaction.isCommitted && transaction.hasChanges {
|
||||
|
||||
CoreStore.log(
|
||||
Internals.log(
|
||||
.warning,
|
||||
message: "The closure for the \(cs_typeName(csTransaction)) completed without being committed. All changes made within the transaction were discarded."
|
||||
message: "The closure for the \(Internals.typeName(csTransaction)) completed without being committed. All changes made within the transaction were discarded."
|
||||
)
|
||||
}
|
||||
try transaction.cancel()
|
||||
@@ -77,9 +77,9 @@ extension CSDataStack {
|
||||
closure(csTransaction)
|
||||
if !transaction.isCommitted && transaction.hasChanges {
|
||||
|
||||
CoreStore.log(
|
||||
Internals.log(
|
||||
.warning,
|
||||
message: "The closure for the \(cs_typeName(csTransaction)) completed without being committed. All changes made within the transaction were discarded."
|
||||
message: "The closure for the \(Internals.typeName(csTransaction)) completed without being committed. All changes made within the transaction were discarded."
|
||||
)
|
||||
}
|
||||
try transaction.cancel()
|
||||
|
||||
@@ -191,7 +191,7 @@ public final class CSDataStack: NSObject, CoreStoreObjectiveCType {
|
||||
|
||||
public override var description: String {
|
||||
|
||||
return "(\(String(reflecting: type(of: self)))) \(self.bridgeToSwift.coreStoreDumpString)"
|
||||
return "(\(String(reflecting: Self.self))) \(self.bridgeToSwift.coreStoreDumpString)"
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -64,7 +64,7 @@ public final class CSError: NSError, CoreStoreObjectiveCType {
|
||||
|
||||
public override var description: String {
|
||||
|
||||
return "(\(String(reflecting: type(of: self)))) \(self.bridgeToSwift.coreStoreDumpString)"
|
||||
return "(\(String(reflecting: Self.self))) \(self.bridgeToSwift.coreStoreDumpString)"
|
||||
}
|
||||
|
||||
|
||||
@@ -274,7 +274,7 @@ extension Error {
|
||||
case let error as CSError:
|
||||
return error.bridgeToSwift
|
||||
|
||||
case let error as NSError where type(of: self) is NSError.Type:
|
||||
case let error as NSError where Self.self is NSError.Type:
|
||||
return .internalError(NSError: error)
|
||||
|
||||
default:
|
||||
|
||||
@@ -97,7 +97,7 @@ public final class CSFrom: NSObject {
|
||||
self.init(From(entityClass, nil))
|
||||
|
||||
default:
|
||||
CoreStore.abort("The configuration argument only accepts NSString and NSNull values")
|
||||
Internals.abort("The configuration argument only accepts NSString and NSNull values")
|
||||
}
|
||||
}
|
||||
|
||||
@@ -126,7 +126,7 @@ public final class CSFrom: NSObject {
|
||||
arguments.append(nil)
|
||||
|
||||
default:
|
||||
CoreStore.abort("The configurations argument only accepts NSString and NSNull values")
|
||||
Internals.abort("The configurations argument only accepts NSString and NSNull values")
|
||||
}
|
||||
}
|
||||
self.init(From(entityClass, arguments))
|
||||
@@ -137,7 +137,7 @@ public final class CSFrom: NSObject {
|
||||
|
||||
public override var description: String {
|
||||
|
||||
return "(\(String(reflecting: type(of: self)))) \(self.bridgeToSwift.coreStoreDumpString)"
|
||||
return "(\(String(reflecting: Self.self))) \(self.bridgeToSwift.coreStoreDumpString)"
|
||||
}
|
||||
|
||||
|
||||
@@ -145,7 +145,7 @@ public final class CSFrom: NSObject {
|
||||
|
||||
public let bridgeToSwift: From<NSManagedObject>
|
||||
|
||||
public init<D: NSManagedObject>(_ swiftValue: From<D>) {
|
||||
public init<O: NSManagedObject>(_ swiftValue: From<O>) {
|
||||
|
||||
self.bridgeToSwift = swiftValue.downcast()
|
||||
super.init()
|
||||
@@ -155,7 +155,7 @@ public final class CSFrom: NSObject {
|
||||
|
||||
// MARK: - From
|
||||
|
||||
extension From where D: NSManagedObject {
|
||||
extension From where O: NSManagedObject {
|
||||
|
||||
// MARK: CoreStoreSwiftType
|
||||
|
||||
|
||||
@@ -87,7 +87,7 @@ public final class CSGroupBy: NSObject, CSQueryClause {
|
||||
|
||||
public override var description: String {
|
||||
|
||||
return "(\(String(reflecting: type(of: self)))) \(self.bridgeToSwift.coreStoreDumpString)"
|
||||
return "(\(String(reflecting: Self.self))) \(self.bridgeToSwift.coreStoreDumpString)"
|
||||
}
|
||||
|
||||
|
||||
@@ -104,7 +104,7 @@ public final class CSGroupBy: NSObject, CSQueryClause {
|
||||
|
||||
public let bridgeToSwift: GroupBy<NSManagedObject>
|
||||
|
||||
public init<D: NSManagedObject>(_ swiftValue: GroupBy<D>) {
|
||||
public init<O: NSManagedObject>(_ swiftValue: GroupBy<O>) {
|
||||
|
||||
self.bridgeToSwift = swiftValue.downcast()
|
||||
super.init()
|
||||
@@ -114,7 +114,7 @@ public final class CSGroupBy: NSObject, CSQueryClause {
|
||||
|
||||
// MARK: - GroupBy
|
||||
|
||||
extension GroupBy where D: NSManagedObject {
|
||||
extension GroupBy where O: NSManagedObject {
|
||||
|
||||
// MARK: CoreStoreSwiftType
|
||||
|
||||
|
||||
@@ -103,7 +103,7 @@ public final class CSInMemoryStore: NSObject, CSStorageInterface, CoreStoreObjec
|
||||
|
||||
public override var description: String {
|
||||
|
||||
return "(\(String(reflecting: type(of: self)))) \(self.bridgeToSwift.coreStoreDumpString)"
|
||||
return "(\(String(reflecting: Self.self))) \(self.bridgeToSwift.coreStoreDumpString)"
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -104,7 +104,7 @@ public final class CSInto: NSObject {
|
||||
|
||||
public override var description: String {
|
||||
|
||||
return "(\(String(reflecting: type(of: self)))) \(self.bridgeToSwift.coreStoreDumpString)"
|
||||
return "(\(String(reflecting: Self.self))) \(self.bridgeToSwift.coreStoreDumpString)"
|
||||
}
|
||||
|
||||
|
||||
@@ -112,7 +112,7 @@ public final class CSInto: NSObject {
|
||||
|
||||
public let bridgeToSwift: Into<NSManagedObject>
|
||||
|
||||
public required init<D: NSManagedObject>(_ swiftValue: Into<D>) {
|
||||
public required init<O: NSManagedObject>(_ swiftValue: Into<O>) {
|
||||
|
||||
self.bridgeToSwift = swiftValue.downcast()
|
||||
super.init()
|
||||
@@ -122,7 +122,7 @@ public final class CSInto: NSObject {
|
||||
|
||||
// MARK: - Into
|
||||
|
||||
extension Into where D: NSManagedObject {
|
||||
extension Into where O: NSManagedObject {
|
||||
|
||||
// MARK: CoreStoreSwiftType
|
||||
|
||||
|
||||
@@ -526,7 +526,7 @@ public final class CSListMonitor: NSObject {
|
||||
|
||||
public override var description: String {
|
||||
|
||||
return "(\(String(reflecting: type(of: self)))) \(self.bridgeToSwift.coreStoreDumpString)"
|
||||
return "(\(String(reflecting: Self.self))) \(self.bridgeToSwift.coreStoreDumpString)"
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -42,7 +42,7 @@ import CoreData
|
||||
*/
|
||||
@available(macOS 10.12, *)
|
||||
@objc
|
||||
public protocol CSListObserver: class {
|
||||
public protocol CSListObserver: AnyObject {
|
||||
|
||||
/**
|
||||
Handles processing just before a change to the observed list occurs
|
||||
|
||||
@@ -155,7 +155,7 @@ public final class CSMigrationResult: NSObject, CoreStoreObjectiveCType {
|
||||
|
||||
public override var description: String {
|
||||
|
||||
return "(\(String(reflecting: type(of: self)))) \(self.bridgeToSwift.coreStoreDumpString)"
|
||||
return "(\(String(reflecting: Self.self))) \(self.bridgeToSwift.coreStoreDumpString)"
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -101,7 +101,7 @@ public final class CSMigrationType: NSObject, CoreStoreObjectiveCType {
|
||||
|
||||
public override var description: String {
|
||||
|
||||
return "(\(String(reflecting: type(of: self)))) \(self.bridgeToSwift.coreStoreDumpString)"
|
||||
return "(\(String(reflecting: Self.self))) \(self.bridgeToSwift.coreStoreDumpString)"
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -119,7 +119,7 @@ public final class CSObjectMonitor: NSObject {
|
||||
|
||||
public override var description: String {
|
||||
|
||||
return "(\(String(reflecting: type(of: self)))) \(self.bridgeToSwift.coreStoreDumpString)"
|
||||
return "(\(String(reflecting: Self.self))) \(self.bridgeToSwift.coreStoreDumpString)"
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -40,7 +40,7 @@ import CoreData
|
||||
*/
|
||||
@available(macOS 10.12, *)
|
||||
@objc
|
||||
public protocol CSObjectObserver: class {
|
||||
public protocol CSObjectObserver: AnyObject {
|
||||
|
||||
/**
|
||||
Handles processing just before a change to the observed `object` occurs
|
||||
|
||||
@@ -95,7 +95,7 @@ public final class CSOrderBy: NSObject, CSFetchClause, CSQueryClause, CSDeleteCl
|
||||
|
||||
public override var description: String {
|
||||
|
||||
return "(\(String(reflecting: type(of: self)))) \(self.bridgeToSwift.coreStoreDumpString)"
|
||||
return "(\(String(reflecting: Self.self))) \(self.bridgeToSwift.coreStoreDumpString)"
|
||||
}
|
||||
|
||||
|
||||
@@ -112,7 +112,7 @@ public final class CSOrderBy: NSObject, CSFetchClause, CSQueryClause, CSDeleteCl
|
||||
|
||||
public let bridgeToSwift: OrderBy<NSManagedObject>
|
||||
|
||||
public init<D: NSManagedObject>(_ swiftValue: OrderBy<D>) {
|
||||
public init<O: NSManagedObject>(_ swiftValue: OrderBy<O>) {
|
||||
|
||||
self.bridgeToSwift = swiftValue.downcast()
|
||||
super.init()
|
||||
@@ -122,7 +122,7 @@ public final class CSOrderBy: NSObject, CSFetchClause, CSQueryClause, CSDeleteCl
|
||||
|
||||
// MARK: - OrderBy
|
||||
|
||||
extension OrderBy where D: NSManagedObject {
|
||||
extension OrderBy where O: NSManagedObject {
|
||||
|
||||
// MARK: CoreStoreSwiftType
|
||||
|
||||
|
||||
@@ -178,7 +178,7 @@ public final class CSSQLiteStore: NSObject, CSLocalStorage, CoreStoreObjectiveCT
|
||||
|
||||
public override var description: String {
|
||||
|
||||
return "(\(String(reflecting: type(of: self)))) \(self.bridgeToSwift.coreStoreDumpString)"
|
||||
return "(\(String(reflecting: Self.self))) \(self.bridgeToSwift.coreStoreDumpString)"
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -68,7 +68,7 @@ public final class CSSectionBy: NSObject {
|
||||
|
||||
public override var description: String {
|
||||
|
||||
return "(\(String(reflecting: type(of: self)))) \(self.bridgeToSwift.coreStoreDumpString)"
|
||||
return "(\(String(reflecting: Self.self))) \(self.bridgeToSwift.coreStoreDumpString)"
|
||||
}
|
||||
|
||||
|
||||
@@ -76,7 +76,7 @@ public final class CSSectionBy: NSObject {
|
||||
|
||||
public let bridgeToSwift: SectionBy<NSManagedObject>
|
||||
|
||||
public init<D>(_ swiftValue: SectionBy<D>) {
|
||||
public init<O>(_ swiftValue: SectionBy<O>) {
|
||||
|
||||
self.bridgeToSwift = swiftValue.downcast()
|
||||
super.init()
|
||||
|
||||
@@ -177,7 +177,7 @@ public final class CSSelectTerm: NSObject {
|
||||
|
||||
public let bridgeToSwift: SelectTerm<NSManagedObject>
|
||||
|
||||
public init<D: NSManagedObject>(_ swiftValue: SelectTerm<D>) {
|
||||
public init<O: NSManagedObject>(_ swiftValue: SelectTerm<O>) {
|
||||
|
||||
self.bridgeToSwift = swiftValue.downcast()
|
||||
super.init()
|
||||
@@ -187,7 +187,7 @@ public final class CSSelectTerm: NSObject {
|
||||
|
||||
// MARK: - SelectTerm
|
||||
|
||||
extension SelectTerm where D: NSManagedObject {
|
||||
extension SelectTerm where O: NSManagedObject {
|
||||
|
||||
// MARK: CoreStoreSwiftType
|
||||
|
||||
@@ -377,13 +377,13 @@ public final class CSSelect: NSObject {
|
||||
|
||||
public override var description: String {
|
||||
|
||||
return "(\(String(reflecting: type(of: self)))) \(self.bridgeToSwift.coreStoreDumpString)"
|
||||
return "(\(String(reflecting: Self.self))) \(self.bridgeToSwift.coreStoreDumpString)"
|
||||
}
|
||||
|
||||
|
||||
// MARK: CoreStoreObjectiveCType
|
||||
|
||||
public init<D: NSManagedObject, T: QueryableAttributeType>(_ swiftValue: Select<D, T>) {
|
||||
public init<O: NSManagedObject, T: QueryableAttributeType>(_ swiftValue: Select<O, T>) {
|
||||
|
||||
self.attributeType = T.cs_rawAttributeType
|
||||
self.selectTerms = swiftValue.selectTerms.map({ $0.downcast() })
|
||||
@@ -391,7 +391,7 @@ public final class CSSelect: NSObject {
|
||||
super.init()
|
||||
}
|
||||
|
||||
public init<D: NSManagedObject, T>(_ swiftValue: Select<D, T>) {
|
||||
public init<O: NSManagedObject, T>(_ swiftValue: Select<O, T>) {
|
||||
|
||||
self.attributeType = .undefinedAttributeType
|
||||
self.selectTerms = swiftValue.selectTerms.map({ $0.downcast() })
|
||||
@@ -467,9 +467,9 @@ public final class CSSelect: NSObject {
|
||||
}
|
||||
else {
|
||||
|
||||
CoreStore.log(
|
||||
Internals.log(
|
||||
.warning,
|
||||
message: "The key path \"\(keyPath)\" could not be resolved in entity \(cs_typeName(entityDescription.managedObjectClassName)) as an attribute and will be ignored by \(cs_typeName(self)) query clause."
|
||||
message: "The key path \"\(keyPath)\" could not be resolved in entity \(Internals.typeName(entityDescription.managedObjectClassName)) as an attribute and will be ignored by \(Internals.typeName(self)) query clause."
|
||||
)
|
||||
}
|
||||
|
||||
@@ -502,7 +502,7 @@ public final class CSSelect: NSObject {
|
||||
|
||||
// MARK: - Select
|
||||
|
||||
extension Select where D: NSManagedObject {
|
||||
extension Select where O: NSManagedObject {
|
||||
|
||||
// MARK: CoreStoreSwiftType
|
||||
|
||||
|
||||
@@ -146,7 +146,7 @@ public final class CSSetupResult: NSObject {
|
||||
|
||||
public override var description: String {
|
||||
|
||||
return "(\(String(reflecting: type(of: self)))) \(self.bridgeToSwift.coreStoreDumpString)"
|
||||
return "(\(String(reflecting: Self.self))) \(self.bridgeToSwift.coreStoreDumpString)"
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -60,7 +60,7 @@ public final class CSSynchronousDataTransaction: CSBaseDataTransaction, CoreStor
|
||||
|
||||
public override var description: String {
|
||||
|
||||
return "(\(String(reflecting: type(of: self)))) \(self.bridgeToSwift.coreStoreDumpString)"
|
||||
return "(\(String(reflecting: Self.self))) \(self.bridgeToSwift.coreStoreDumpString)"
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -63,7 +63,7 @@ public final class CSTweak: NSObject, CSFetchClause, CSQueryClause, CSDeleteClau
|
||||
|
||||
public override var description: String {
|
||||
|
||||
return "(\(String(reflecting: type(of: self)))) \(self.bridgeToSwift.coreStoreDumpString)"
|
||||
return "(\(String(reflecting: Self.self))) \(self.bridgeToSwift.coreStoreDumpString)"
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -71,7 +71,7 @@ public final class CSUnsafeDataModelSchema: NSObject, CSDynamicSchema, CoreStore
|
||||
|
||||
public override var description: String {
|
||||
|
||||
return "(\(String(reflecting: type(of: self)))) \(self.bridgeToSwift.coreStoreDumpString)"
|
||||
return "(\(String(reflecting: Self.self))) \(self.bridgeToSwift.coreStoreDumpString)"
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -181,7 +181,7 @@ public final class CSUnsafeDataTransaction: CSBaseDataTransaction, CoreStoreObje
|
||||
|
||||
public override var description: String {
|
||||
|
||||
return "(\(String(reflecting: type(of: self)))) \(self.bridgeToSwift.coreStoreDumpString)"
|
||||
return "(\(String(reflecting: Self.self))) \(self.bridgeToSwift.coreStoreDumpString)"
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -134,7 +134,7 @@ public final class CSWhere: NSObject, CSFetchClause, CSQueryClause, CSDeleteClau
|
||||
|
||||
public override var description: String {
|
||||
|
||||
return "(\(String(reflecting: type(of: self)))) \(self.bridgeToSwift.coreStoreDumpString)"
|
||||
return "(\(String(reflecting: Self.self))) \(self.bridgeToSwift.coreStoreDumpString)"
|
||||
}
|
||||
|
||||
|
||||
@@ -151,7 +151,7 @@ public final class CSWhere: NSObject, CSFetchClause, CSQueryClause, CSDeleteClau
|
||||
|
||||
public let bridgeToSwift: Where<NSManagedObject>
|
||||
|
||||
public init<D: NSManagedObject>(_ swiftValue: Where<D>) {
|
||||
public init<O: NSManagedObject>(_ swiftValue: Where<O>) {
|
||||
|
||||
self.bridgeToSwift = swiftValue.downcast()
|
||||
super.init()
|
||||
@@ -161,7 +161,7 @@ public final class CSWhere: NSObject, CSFetchClause, CSQueryClause, CSDeleteClau
|
||||
|
||||
// MARK: - Where
|
||||
|
||||
extension Where where D: NSManagedObject {
|
||||
extension Where where O: NSManagedObject {
|
||||
|
||||
// MARK: CoreStoreSwiftType
|
||||
|
||||
|
||||
@@ -71,7 +71,7 @@ public final class CSXcodeDataModelSchema: NSObject, CSDynamicSchema, CoreStoreO
|
||||
|
||||
public override var description: String {
|
||||
|
||||
return "(\(String(reflecting: type(of: self)))) \(self.bridgeToSwift.coreStoreDumpString)"
|
||||
return "(\(String(reflecting: Self.self))) \(self.bridgeToSwift.coreStoreDumpString)"
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -33,7 +33,7 @@ import CoreData
|
||||
Objective-C Foundation types that are natively supported by Core Data managed attributes all conform to `CoreDataNativeType`.
|
||||
*/
|
||||
@objc
|
||||
public protocol CoreDataNativeType: class, NSObjectProtocol {}
|
||||
public protocol CoreDataNativeType: AnyObject, NSObjectProtocol {}
|
||||
|
||||
|
||||
// MARK: - NSNumber
|
||||
|
||||
@@ -54,50 +54,6 @@ extension AsynchronousDataTransaction: CustomDebugStringConvertible, CoreStoreDe
|
||||
}
|
||||
|
||||
|
||||
// MARK: - CloudStorageOptions
|
||||
|
||||
extension CloudStorageOptions: CustomDebugStringConvertible, CoreStoreDebugStringConvertible {
|
||||
|
||||
// MARK: CustomDebugStringConvertible
|
||||
|
||||
public var debugDescription: String {
|
||||
|
||||
return formattedDebugDescription(self)
|
||||
}
|
||||
|
||||
|
||||
// MARK: CoreStoreDebugStringConvertible
|
||||
|
||||
public var coreStoreDumpString: String {
|
||||
|
||||
var flags = [String]()
|
||||
if self.contains(.recreateLocalStoreOnModelMismatch) {
|
||||
|
||||
flags.append(".recreateLocalStoreOnModelMismatch")
|
||||
}
|
||||
if self.contains(.allowSynchronousLightweightMigration) {
|
||||
|
||||
flags.append(".allowSynchronousLightweightMigration")
|
||||
}
|
||||
switch flags.count {
|
||||
|
||||
case 0:
|
||||
return "[.none]"
|
||||
|
||||
case 1:
|
||||
return "[.\(flags[0])]"
|
||||
|
||||
default:
|
||||
var string = "[\n"
|
||||
string.append(flags.joined(separator: ",\n"))
|
||||
string.indent(1)
|
||||
string.append("\n]")
|
||||
return string
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// MARK: - CoreStoreError
|
||||
|
||||
extension CoreStoreError: CustomDebugStringConvertible, CoreStoreDebugStringConvertible {
|
||||
@@ -116,7 +72,7 @@ extension CoreStoreError: CustomDebugStringConvertible, CoreStoreDebugStringConv
|
||||
|
||||
let firstLine: String
|
||||
var info: DumpInfo = [
|
||||
("errorDomain", type(of: self).errorDomain),
|
||||
("errorDomain", Self.errorDomain),
|
||||
("errorCode", self.errorCode),
|
||||
]
|
||||
switch self {
|
||||
@@ -922,11 +878,11 @@ extension VersionLock: CustomStringConvertible, CustomDebugStringConvertible, Co
|
||||
for (index, keyValue) in self.hashesByEntityName.sorted(by: { $0.key < $1.key }).enumerated() {
|
||||
|
||||
let data = keyValue.value
|
||||
let count = data.count
|
||||
let bytes = data.withUnsafeBytes { (pointer) in
|
||||
|
||||
return (0 ..< (count / MemoryLayout<HashElement>.size))
|
||||
.map({ "\("0x\(String(pointer[$0], radix: 16, uppercase: false))")" })
|
||||
return pointer
|
||||
.bindMemory(to: VersionLock.HashElement.self)
|
||||
.map({ "\("0x\(String($0, radix: 16, uppercase: false))")" })
|
||||
}
|
||||
string.append("\(index == 0 ? "\n" : ",\n")\"\(keyValue.key)\": [\(bytes.joined(separator: ", "))]")
|
||||
}
|
||||
|
||||
@@ -26,22 +26,16 @@
|
||||
import Foundation
|
||||
|
||||
|
||||
// MARK: - CoreStore
|
||||
// MARK: - Internal
|
||||
|
||||
extension Internals {
|
||||
|
||||
extension CoreStore {
|
||||
|
||||
/**
|
||||
The `CoreStoreLogger` instance to be used. The default logger is an instance of a `DefaultLogger`.
|
||||
*/
|
||||
public static var logger: CoreStoreLogger = DefaultLogger()
|
||||
|
||||
|
||||
// MARK: Internal
|
||||
|
||||
|
||||
@inline(__always)
|
||||
internal static func log(_ level: LogLevel, message: String, fileName: StaticString = #file, lineNumber: Int = #line, functionName: StaticString = #function) {
|
||||
|
||||
self.logger.log(
|
||||
|
||||
CoreStoreDefaults.logger.log(
|
||||
level: level,
|
||||
message: message,
|
||||
fileName: fileName,
|
||||
@@ -49,11 +43,11 @@ extension CoreStore {
|
||||
functionName: functionName
|
||||
)
|
||||
}
|
||||
|
||||
|
||||
@inline(__always)
|
||||
internal static func log(_ error: CoreStoreError, _ message: String, fileName: StaticString = #file, lineNumber: Int = #line, functionName: StaticString = #function) {
|
||||
|
||||
self.logger.log(
|
||||
|
||||
CoreStoreDefaults.logger.log(
|
||||
error: error,
|
||||
message: message,
|
||||
fileName: fileName,
|
||||
@@ -61,11 +55,11 @@ extension CoreStore {
|
||||
functionName: functionName
|
||||
)
|
||||
}
|
||||
|
||||
|
||||
@inline(__always)
|
||||
internal static func assert( _ condition: @autoclosure () -> Bool, _ message: @autoclosure () -> String, fileName: StaticString = #file, lineNumber: Int = #line, functionName: StaticString = #function) {
|
||||
|
||||
self.logger.assert(
|
||||
|
||||
CoreStoreDefaults.logger.assert(
|
||||
condition(),
|
||||
message: message(),
|
||||
fileName: fileName,
|
||||
@@ -73,11 +67,11 @@ extension CoreStore {
|
||||
functionName: functionName
|
||||
)
|
||||
}
|
||||
|
||||
|
||||
@inline(__always)
|
||||
internal static func abort(_ message: String, fileName: StaticString = #file, lineNumber: Int = #line, functionName: StaticString = #function) -> Never {
|
||||
|
||||
self.logger.abort(
|
||||
|
||||
CoreStoreDefaults.logger.abort(
|
||||
message,
|
||||
fileName: fileName,
|
||||
lineNumber: lineNumber,
|
||||
|
||||
@@ -29,12 +29,13 @@ import CoreData
|
||||
|
||||
// MARK: - CoreStore
|
||||
|
||||
@available(*, deprecated, message: "Call methods directly from the DataStack instead")
|
||||
extension CoreStore {
|
||||
|
||||
/**
|
||||
Asynchronously adds a `StorageInterface` to the `defaultStack`. Migrations are also initiated by default.
|
||||
Asynchronously adds a `StorageInterface` to the `CoreStoreDefaults.dataStack`. Migrations are also initiated by default.
|
||||
```
|
||||
CoreStore.addStorage(
|
||||
dataStack.addStorage(
|
||||
InMemoryStore(configuration: "Config1"),
|
||||
completion: { result in
|
||||
switch result {
|
||||
@@ -49,13 +50,13 @@ extension CoreStore {
|
||||
*/
|
||||
public static func addStorage<T>(_ storage: T, completion: @escaping (SetupResult<T>) -> Void) {
|
||||
|
||||
self.defaultStack.addStorage(storage, completion: completion)
|
||||
CoreStoreDefaults.dataStack.addStorage(storage, completion: completion)
|
||||
}
|
||||
|
||||
/**
|
||||
Asynchronously adds a `LocalStorage` to the `defaultStack`. Migrations are also initiated by default.
|
||||
Asynchronously adds a `LocalStorage` to the `CoreStoreDefaults.dataStack`. Migrations are also initiated by default.
|
||||
```
|
||||
let migrationProgress = CoreStore.addStorage(
|
||||
let migrationProgress = dataStack.addStorage(
|
||||
SQLiteStore(fileName: "core_data.sqlite", configuration: "Config1"),
|
||||
completion: { result in
|
||||
switch result {
|
||||
@@ -71,43 +72,11 @@ extension CoreStore {
|
||||
*/
|
||||
public static func addStorage<T: LocalStorage>(_ storage: T, completion: @escaping (SetupResult<T>) -> Void) -> Progress? {
|
||||
|
||||
return self.defaultStack.addStorage(storage, completion: completion)
|
||||
}
|
||||
|
||||
/**
|
||||
Asynchronously adds a `CloudStorage` to the `defaultStack`. Migrations are also initiated by default.
|
||||
```
|
||||
guard let storage = ICloudStore(
|
||||
ubiquitousContentName: "MyAppCloudData",
|
||||
ubiquitousContentTransactionLogsSubdirectory: "logs/config1",
|
||||
ubiquitousContainerID: "iCloud.com.mycompany.myapp.containername",
|
||||
ubiquitousPeerToken: "9614d658014f4151a95d8048fb717cf0",
|
||||
configuration: "Config1",
|
||||
cloudStorageOptions: .recreateLocalStoreOnModelMismatch
|
||||
) else {
|
||||
// iCloud is not available on the device
|
||||
return
|
||||
}
|
||||
let migrationProgress = dataStack.addStorage(
|
||||
storage,
|
||||
completion: { result in
|
||||
switch result {
|
||||
case .success(let storage): // ...
|
||||
case .failure(let error): // ...
|
||||
}
|
||||
}
|
||||
)
|
||||
```
|
||||
- parameter storage: the cloud storage
|
||||
- parameter completion: the closure to be executed on the main queue when the process completes, either due to success or failure. The closure's `SetupResult` argument indicates the result. Note that the `CloudStorage` associated to the `SetupResult.success` may not always be the same instance as the parameter argument if a previous `CloudStorage` was already added at the same URL and with the same configuration.
|
||||
*/
|
||||
public static func addStorage<T: CloudStorage>(_ storage: T, completion: @escaping (SetupResult<T>) -> Void) {
|
||||
|
||||
self.defaultStack.addStorage(storage, completion: completion)
|
||||
return CoreStoreDefaults.dataStack.addStorage(storage, completion: completion)
|
||||
}
|
||||
|
||||
/**
|
||||
Migrates a local storage to match the `defaultStack`'s managed object model version. This method does NOT add the migrated store to the data stack.
|
||||
Migrates a local storage to match the `CoreStoreDefaults.dataStack`'s managed object model version. This method does NOT add the migrated store to the data stack.
|
||||
|
||||
- parameter storage: the local storage
|
||||
- parameter completion: the closure to be executed on the main queue when the migration completes, either due to success or failure. The closure's `MigrationResult` argument indicates the result. This closure is NOT executed if an error is thrown, but will be executed with a `.failure` result if an error occurs asynchronously.
|
||||
@@ -116,11 +85,11 @@ extension CoreStore {
|
||||
*/
|
||||
public static func upgradeStorageIfNeeded<T: LocalStorage>(_ storage: T, completion: @escaping (MigrationResult) -> Void) throws -> Progress? {
|
||||
|
||||
return try self.defaultStack.upgradeStorageIfNeeded(storage, completion: completion)
|
||||
return try CoreStoreDefaults.dataStack.upgradeStorageIfNeeded(storage, completion: completion)
|
||||
}
|
||||
|
||||
/**
|
||||
Checks the migration steps required for the storage to match the `defaultStack`'s managed object model version.
|
||||
Checks the migration steps required for the storage to match the `CoreStoreDefaults.dataStack`'s managed object model version.
|
||||
|
||||
- parameter storage: the local storage
|
||||
- throws: a `CoreStoreError` value indicating the failure
|
||||
@@ -128,6 +97,6 @@ extension CoreStore {
|
||||
*/
|
||||
public static func requiredMigrationsForStorage<T: LocalStorage>(_ storage: T) throws -> [MigrationType] {
|
||||
|
||||
return try self.defaultStack.requiredMigrationsForStorage(storage)
|
||||
return try CoreStoreDefaults.dataStack.requiredMigrationsForStorage(storage)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -29,48 +29,49 @@ import CoreData
|
||||
|
||||
// MARK: - CoreStore
|
||||
|
||||
@available(*, deprecated, message: "Call methods directly from the DataStack instead")
|
||||
@available(macOS 10.12, *)
|
||||
extension CoreStore {
|
||||
|
||||
/**
|
||||
Using the `defaultStack`, creates an `ObjectMonitor` for the specified `DynamicObject`. Multiple `ObjectObserver`s may then register themselves to be notified when changes are made to the `DynamicObject`.
|
||||
Using the `CoreStoreDefaults.dataStack`, creates an `ObjectMonitor` for the specified `DynamicObject`. Multiple `ObjectObserver`s may then register themselves to be notified when changes are made to the `DynamicObject`.
|
||||
|
||||
- parameter object: the `DynamicObject` to observe changes from
|
||||
- returns: a `ObjectMonitor` that monitors changes to `object`
|
||||
- returns: an `ObjectMonitor` that monitors changes to `object`
|
||||
*/
|
||||
public static func monitorObject<D>(_ object: D) -> ObjectMonitor<D> {
|
||||
public static func monitorObject<O: DynamicObject>(_ object: O) -> ObjectMonitor<O> {
|
||||
|
||||
return self.defaultStack.monitorObject(object)
|
||||
return CoreStoreDefaults.dataStack.monitorObject(object)
|
||||
}
|
||||
|
||||
/**
|
||||
Using the `defaultStack`, creates a `ListMonitor` for a list of `DynamicObject`s that satisfy the specified fetch clauses. Multiple `ListObserver`s may then register themselves to be notified when changes are made to the list.
|
||||
Using the `CoreStoreDefaults.dataStack`, creates a `ListMonitor` for a list of `DynamicObject`s that satisfy the specified fetch clauses. Multiple `ListObserver`s may then register themselves to be notified when changes are made to the list.
|
||||
|
||||
- parameter from: a `From` clause indicating the entity type
|
||||
- parameter fetchClauses: a series of `FetchClause` instances for fetching the object list. Accepts `Where`, `OrderBy`, and `Tweak` clauses.
|
||||
- returns: a `ListMonitor` instance that monitors changes to the list
|
||||
*/
|
||||
public static func monitorList<D>(_ from: From<D>, _ fetchClauses: FetchClause...) -> ListMonitor<D> {
|
||||
public static func monitorList<O>(_ from: From<O>, _ fetchClauses: FetchClause...) -> ListMonitor<O> {
|
||||
|
||||
return self.defaultStack.monitorList(from, fetchClauses)
|
||||
return CoreStoreDefaults.dataStack.monitorList(from, fetchClauses)
|
||||
}
|
||||
|
||||
/**
|
||||
Using the `defaultStack`, creates a `ListMonitor` for a list of `DynamicObject`s that satisfy the specified fetch clauses. Multiple `ListObserver`s may then register themselves to be notified when changes are made to the list.
|
||||
Using the `CoreStoreDefaults.dataStack`, creates a `ListMonitor` for a list of `DynamicObject`s that satisfy the specified fetch clauses. Multiple `ListObserver`s may then register themselves to be notified when changes are made to the list.
|
||||
|
||||
- parameter from: a `From` clause indicating the entity type
|
||||
- parameter fetchClauses: a series of `FetchClause` instances for fetching the object list. Accepts `Where`, `OrderBy`, and `Tweak` clauses.
|
||||
- returns: a `ListMonitor` instance that monitors changes to the list
|
||||
*/
|
||||
public static func monitorList<D>(_ from: From<D>, _ fetchClauses: [FetchClause]) -> ListMonitor<D> {
|
||||
public static func monitorList<O>(_ from: From<O>, _ fetchClauses: [FetchClause]) -> ListMonitor<O> {
|
||||
|
||||
return self.defaultStack.monitorList(from, fetchClauses)
|
||||
return CoreStoreDefaults.dataStack.monitorList(from, fetchClauses)
|
||||
}
|
||||
|
||||
/**
|
||||
Creates a `ListMonitor` for a list of `DynamicObject`s that satisfy the specified `FetchChainableBuilderType` built from a chain of clauses.
|
||||
```
|
||||
let monitor = CoreStore.monitorList(
|
||||
let monitor = dataStack.monitorList(
|
||||
From<MyPersonEntity>()
|
||||
.where(\.age > 18)
|
||||
.orderBy(.ascending(\.age))
|
||||
@@ -81,38 +82,38 @@ extension CoreStore {
|
||||
*/
|
||||
public static func monitorList<B: FetchChainableBuilderType>(_ clauseChain: B) -> ListMonitor<B.ObjectType> {
|
||||
|
||||
return self.defaultStack.monitorList(clauseChain.from, clauseChain.fetchClauses)
|
||||
return CoreStoreDefaults.dataStack.monitorList(clauseChain.from, clauseChain.fetchClauses)
|
||||
}
|
||||
|
||||
/**
|
||||
Using the `defaultStack`, asynchronously creates a `ListMonitor` for a list of `DynamicObject`s that satisfy the specified fetch clauses. Multiple `ListObserver`s may then register themselves to be notified when changes are made to the list. Since `NSFetchedResultsController` greedily locks the persistent store on initial fetch, you may prefer this method instead of the synchronous counterpart to avoid deadlocks while background updates/saves are being executed.
|
||||
Using the `CoreStoreDefaults.dataStack`, asynchronously creates a `ListMonitor` for a list of `DynamicObject`s that satisfy the specified fetch clauses. Multiple `ListObserver`s may then register themselves to be notified when changes are made to the list. Since `NSFetchedResultsController` greedily locks the persistent store on initial fetch, you may prefer this method instead of the synchronous counterpart to avoid deadlocks while background updates/saves are being executed.
|
||||
|
||||
- parameter createAsynchronously: the closure that receives the created `ListMonitor` instance
|
||||
- parameter from: a `From` clause indicating the entity type
|
||||
- parameter fetchClauses: a series of `FetchClause` instances for fetching the object list. Accepts `Where`, `OrderBy`, and `Tweak` clauses.
|
||||
*/
|
||||
public static func monitorList<D>(createAsynchronously: @escaping (ListMonitor<D>) -> Void, _ from: From<D>, _ fetchClauses: FetchClause...) {
|
||||
public static func monitorList<O>(createAsynchronously: @escaping (ListMonitor<O>) -> Void, _ from: From<O>, _ fetchClauses: FetchClause...) {
|
||||
|
||||
self.defaultStack.monitorList(createAsynchronously: createAsynchronously, from, fetchClauses)
|
||||
CoreStoreDefaults.dataStack.monitorList(createAsynchronously: createAsynchronously, from, fetchClauses)
|
||||
}
|
||||
|
||||
/**
|
||||
Using the `defaultStack`, asynchronously creates a `ListMonitor` for a list of `DynamicObject`s that satisfy the specified fetch clauses. Multiple `ListObserver`s may then register themselves to be notified when changes are made to the list. Since `NSFetchedResultsController` greedily locks the persistent store on initial fetch, you may prefer this method instead of the synchronous counterpart to avoid deadlocks while background updates/saves are being executed.
|
||||
Using the `CoreStoreDefaults.dataStack`, asynchronously creates a `ListMonitor` for a list of `DynamicObject`s that satisfy the specified fetch clauses. Multiple `ListObserver`s may then register themselves to be notified when changes are made to the list. Since `NSFetchedResultsController` greedily locks the persistent store on initial fetch, you may prefer this method instead of the synchronous counterpart to avoid deadlocks while background updates/saves are being executed.
|
||||
|
||||
- parameter createAsynchronously: the closure that receives the created `ListMonitor` instance
|
||||
- parameter from: a `From` clause indicating the entity type
|
||||
- parameter fetchClauses: a series of `FetchClause` instances for fetching the object list. Accepts `Where`, `OrderBy`, and `Tweak` clauses.
|
||||
*/
|
||||
public static func monitorList<D>(createAsynchronously: @escaping (ListMonitor<D>) -> Void, _ from: From<D>, _ fetchClauses: [FetchClause]) {
|
||||
public static func monitorList<O>(createAsynchronously: @escaping (ListMonitor<O>) -> Void, _ from: From<O>, _ fetchClauses: [FetchClause]) {
|
||||
|
||||
self.defaultStack.monitorList(createAsynchronously: createAsynchronously, from, fetchClauses)
|
||||
CoreStoreDefaults.dataStack.monitorList(createAsynchronously: createAsynchronously, from, fetchClauses)
|
||||
}
|
||||
|
||||
/**
|
||||
Asynchronously creates a `ListMonitor` for a list of `DynamicObject`s that satisfy the specified `FetchChainableBuilderType` built from a chain of clauses. Since `NSFetchedResultsController` greedily locks the persistent store on initial fetch, you may prefer this method instead of the synchronous counterpart to avoid deadlocks while background updates/saves are being executed.
|
||||
|
||||
```
|
||||
CoreStore.monitorList(
|
||||
dataStack.monitorList(
|
||||
createAsynchronously: { (monitor) in
|
||||
self.monitor = monitor
|
||||
},
|
||||
@@ -126,7 +127,7 @@ extension CoreStore {
|
||||
*/
|
||||
public static func monitorList<B: FetchChainableBuilderType>(createAsynchronously: @escaping (ListMonitor<B.ObjectType>) -> Void, _ clauseChain: B) {
|
||||
|
||||
self.defaultStack.monitorList(
|
||||
CoreStoreDefaults.dataStack.monitorList(
|
||||
createAsynchronously: createAsynchronously,
|
||||
clauseChain.from,
|
||||
clauseChain.fetchClauses
|
||||
@@ -134,35 +135,35 @@ extension CoreStore {
|
||||
}
|
||||
|
||||
/**
|
||||
Using the `defaultStack`, creates a `ListMonitor` for a sectioned list of `DynamicObject`s that satisfy the specified fetch clauses. Multiple `ListObserver`s may then register themselves to be notified when changes are made to the list.
|
||||
Using the `CoreStoreDefaults.dataStack`, creates a `ListMonitor` for a sectioned list of `DynamicObject`s that satisfy the specified fetch clauses. Multiple `ListObserver`s may then register themselves to be notified when changes are made to the list.
|
||||
|
||||
- parameter from: a `From` clause indicating the entity type
|
||||
- parameter sectionBy: a `SectionBy` clause indicating the keyPath for the attribute to use when sorting the list into sections.
|
||||
- parameter fetchClauses: a series of `FetchClause` instances for fetching the object list. Accepts `Where`, `OrderBy`, and `Tweak` clauses.
|
||||
- returns: a `ListMonitor` instance that monitors changes to the list
|
||||
*/
|
||||
public static func monitorSectionedList<D>(_ from: From<D>, _ sectionBy: SectionBy<D>, _ fetchClauses: FetchClause...) -> ListMonitor<D> {
|
||||
public static func monitorSectionedList<O>(_ from: From<O>, _ sectionBy: SectionBy<O>, _ fetchClauses: FetchClause...) -> ListMonitor<O> {
|
||||
|
||||
return self.defaultStack.monitorSectionedList(from, sectionBy, fetchClauses)
|
||||
return CoreStoreDefaults.dataStack.monitorSectionedList(from, sectionBy, fetchClauses)
|
||||
}
|
||||
|
||||
/**
|
||||
Using the `defaultStack`, creates a `ListMonitor` for a sectioned list of `DynamicObject`s that satisfy the specified fetch clauses. Multiple `ListObserver`s may then register themselves to be notified when changes are made to the list.
|
||||
Using the `CoreStoreDefaults.dataStack`, creates a `ListMonitor` for a sectioned list of `DynamicObject`s that satisfy the specified fetch clauses. Multiple `ListObserver`s may then register themselves to be notified when changes are made to the list.
|
||||
|
||||
- parameter from: a `From` clause indicating the entity type
|
||||
- parameter sectionBy: a `SectionBy` clause indicating the keyPath for the attribute to use when sorting the list into sections.
|
||||
- parameter fetchClauses: a series of `FetchClause` instances for fetching the object list. Accepts `Where`, `OrderBy`, and `Tweak` clauses.
|
||||
- returns: a `ListMonitor` instance that monitors changes to the list
|
||||
*/
|
||||
public static func monitorSectionedList<D>(_ from: From<D>, _ sectionBy: SectionBy<D>, _ fetchClauses: [FetchClause]) -> ListMonitor<D> {
|
||||
public static func monitorSectionedList<O>(_ from: From<O>, _ sectionBy: SectionBy<O>, _ fetchClauses: [FetchClause]) -> ListMonitor<O> {
|
||||
|
||||
return self.defaultStack.monitorSectionedList(from, sectionBy, fetchClauses)
|
||||
return CoreStoreDefaults.dataStack.monitorSectionedList(from, sectionBy, fetchClauses)
|
||||
}
|
||||
|
||||
/**
|
||||
Creates a `ListMonitor` for a sectioned list of `DynamicObject`s that satisfy the specified `SectionMonitorBuilderType` built from a chain of clauses.
|
||||
```
|
||||
let monitor = CoreStore.monitorSectionedList(
|
||||
let monitor = dataStack.monitorSectionedList(
|
||||
From<MyPersonEntity>()
|
||||
.sectionBy(\.age, { "\($0!) years old" })
|
||||
.where(\.age > 18)
|
||||
@@ -174,7 +175,7 @@ extension CoreStore {
|
||||
*/
|
||||
public static func monitorSectionedList<B: SectionMonitorBuilderType>(_ clauseChain: B) -> ListMonitor<B.ObjectType> {
|
||||
|
||||
return self.defaultStack.monitorSectionedList(
|
||||
return CoreStoreDefaults.dataStack.monitorSectionedList(
|
||||
clauseChain.from,
|
||||
clauseChain.sectionBy,
|
||||
clauseChain.fetchClauses
|
||||
@@ -182,35 +183,35 @@ extension CoreStore {
|
||||
}
|
||||
|
||||
/**
|
||||
Using the `defaultStack`, asynchronously creates a `ListMonitor` for a sectioned list of `DynamicObject`s that satisfy the specified fetch clauses. Multiple `ListObserver`s may then register themselves to be notified when changes are made to the list. Since `NSFetchedResultsController` greedily locks the persistent store on initial fetch, you may prefer this method instead of the synchronous counterpart to avoid deadlocks while background updates/saves are being executed.
|
||||
Using the `CoreStoreDefaults.dataStack`, asynchronously creates a `ListMonitor` for a sectioned list of `DynamicObject`s that satisfy the specified fetch clauses. Multiple `ListObserver`s may then register themselves to be notified when changes are made to the list. Since `NSFetchedResultsController` greedily locks the persistent store on initial fetch, you may prefer this method instead of the synchronous counterpart to avoid deadlocks while background updates/saves are being executed.
|
||||
|
||||
- parameter createAsynchronously: the closure that receives the created `ListMonitor` instance
|
||||
- parameter from: a `From` clause indicating the entity type
|
||||
- parameter sectionBy: a `SectionBy` clause indicating the keyPath for the attribute to use when sorting the list into sections.
|
||||
- parameter fetchClauses: a series of `FetchClause` instances for fetching the object list. Accepts `Where`, `OrderBy`, and `Tweak` clauses.
|
||||
*/
|
||||
public static func monitorSectionedList<D>(createAsynchronously: @escaping (ListMonitor<D>) -> Void, _ from: From<D>, _ sectionBy: SectionBy<D>, _ fetchClauses: FetchClause...) {
|
||||
public static func monitorSectionedList<O>(createAsynchronously: @escaping (ListMonitor<O>) -> Void, _ from: From<O>, _ sectionBy: SectionBy<O>, _ fetchClauses: FetchClause...) {
|
||||
|
||||
self.defaultStack.monitorSectionedList(createAsynchronously: createAsynchronously, from, sectionBy, fetchClauses)
|
||||
CoreStoreDefaults.dataStack.monitorSectionedList(createAsynchronously: createAsynchronously, from, sectionBy, fetchClauses)
|
||||
}
|
||||
|
||||
/**
|
||||
Using the `defaultStack`, asynchronously creates a `ListMonitor` for a sectioned list of `DynamicObject`s that satisfy the specified fetch clauses. Multiple `ListObserver`s may then register themselves to be notified when changes are made to the list. Since `NSFetchedResultsController` greedily locks the persistent store on initial fetch, you may prefer this method instead of the synchronous counterpart to avoid deadlocks while background updates/saves are being executed.
|
||||
Using the `CoreStoreDefaults.dataStack`, asynchronously creates a `ListMonitor` for a sectioned list of `DynamicObject`s that satisfy the specified fetch clauses. Multiple `ListObserver`s may then register themselves to be notified when changes are made to the list. Since `NSFetchedResultsController` greedily locks the persistent store on initial fetch, you may prefer this method instead of the synchronous counterpart to avoid deadlocks while background updates/saves are being executed.
|
||||
|
||||
- parameter createAsynchronously: the closure that receives the created `ListMonitor` instance
|
||||
- parameter from: a `From` clause indicating the entity type
|
||||
- parameter sectionBy: a `SectionBy` clause indicating the keyPath for the attribute to use when sorting the list into sections.
|
||||
- parameter fetchClauses: a series of `FetchClause` instances for fetching the object list. Accepts `Where`, `OrderBy`, and `Tweak` clauses.
|
||||
*/
|
||||
public static func monitorSectionedList<D>(createAsynchronously: @escaping (ListMonitor<D>) -> Void, _ from: From<D>, _ sectionBy: SectionBy<D>, _ fetchClauses: [FetchClause]) {
|
||||
public static func monitorSectionedList<O>(createAsynchronously: @escaping (ListMonitor<O>) -> Void, _ from: From<O>, _ sectionBy: SectionBy<O>, _ fetchClauses: [FetchClause]) {
|
||||
|
||||
self.defaultStack.monitorSectionedList(createAsynchronously: createAsynchronously, from, sectionBy, fetchClauses)
|
||||
CoreStoreDefaults.dataStack.monitorSectionedList(createAsynchronously: createAsynchronously, from, sectionBy, fetchClauses)
|
||||
}
|
||||
|
||||
/**
|
||||
Asynchronously creates a `ListMonitor` for a sectioned list of `DynamicObject`s that satisfy the specified `SectionMonitorBuilderType` built from a chain of clauses.
|
||||
```
|
||||
CoreStore.monitorSectionedList(
|
||||
dataStack.monitorSectionedList(
|
||||
createAsynchronously: { (monitor) in
|
||||
self.monitor = monitor
|
||||
},
|
||||
@@ -225,7 +226,7 @@ extension CoreStore {
|
||||
*/
|
||||
public static func monitorSectionedList<B: SectionMonitorBuilderType>(createAsynchronously: @escaping (ListMonitor<B.ObjectType>) -> Void, _ clauseChain: B) {
|
||||
|
||||
self.defaultStack.monitorSectionedList(
|
||||
CoreStoreDefaults.dataStack.monitorSectionedList(
|
||||
createAsynchronously: createAsynchronously,
|
||||
clauseChain.from,
|
||||
clauseChain.sectionBy,
|
||||
|
||||
@@ -29,82 +29,83 @@ import CoreData
|
||||
|
||||
// MARK: - CoreStore
|
||||
|
||||
@available(*, deprecated, message: "Call methods directly from the DataStack instead")
|
||||
extension CoreStore {
|
||||
|
||||
/**
|
||||
Using the `defaultStack`, fetches the `DynamicObject` instance in the `DataStack`'s context from a reference created from a transaction or from a different managed object context.
|
||||
Using the `CoreStoreDefaults.dataStack`, fetches the `DynamicObject` instance in the `DataStack`'s context from a reference created from a transaction or from a different managed object context.
|
||||
|
||||
- parameter object: a reference to the object created/fetched outside the `DataStack`
|
||||
- returns: the `DynamicObject` instance if the object exists in the `DataStack`, or `nil` if not found.
|
||||
*/
|
||||
public static func fetchExisting<D: DynamicObject>(_ object: D) -> D? {
|
||||
public static func fetchExisting<O: DynamicObject>(_ object: O) -> O? {
|
||||
|
||||
return self.defaultStack.fetchExisting(object)
|
||||
return CoreStoreDefaults.dataStack.fetchExisting(object)
|
||||
}
|
||||
|
||||
/**
|
||||
Using the `defaultStack`, fetches the `DynamicObject` instance in the `DataStack`'s context from an `NSManagedObjectID`.
|
||||
Using the `CoreStoreDefaults.dataStack`, fetches the `DynamicObject` instance in the `DataStack`'s context from an `NSManagedObjectID`.
|
||||
|
||||
- parameter objectID: the `NSManagedObjectID` for the object
|
||||
- returns: the `DynamicObject` instance if the object exists in the `DataStack`, or `nil` if not found.
|
||||
*/
|
||||
public static func fetchExisting<D: DynamicObject>(_ objectID: NSManagedObjectID) -> D? {
|
||||
public static func fetchExisting<O: DynamicObject>(_ objectID: NSManagedObjectID) -> O? {
|
||||
|
||||
return self.defaultStack.fetchExisting(objectID)
|
||||
return CoreStoreDefaults.dataStack.fetchExisting(objectID)
|
||||
}
|
||||
|
||||
/**
|
||||
Using the `defaultStack`, fetches the `DynamicObject` instances in the `DataStack`'s context from references created from a transaction or from a different managed object context.
|
||||
Using the `CoreStoreDefaults.dataStack`, fetches the `DynamicObject` instances in the `DataStack`'s context from references created from a transaction or from a different managed object context.
|
||||
|
||||
- parameter objects: an array of `DynamicObject`s created/fetched outside the `DataStack`
|
||||
- returns: the `DynamicObject` array for objects that exists in the `DataStack`
|
||||
*/
|
||||
public static func fetchExisting<D: DynamicObject, S: Sequence>(_ objects: S) -> [D] where S.Iterator.Element == D {
|
||||
public static func fetchExisting<O: DynamicObject, S: Sequence>(_ objects: S) -> [O] where S.Iterator.Element == O {
|
||||
|
||||
return self.defaultStack.fetchExisting(objects)
|
||||
return CoreStoreDefaults.dataStack.fetchExisting(objects)
|
||||
}
|
||||
|
||||
/**
|
||||
Using the `defaultStack`, fetches the `DynamicObject` instances in the `DataStack`'s context from a list of `NSManagedObjectID`.
|
||||
Using the `CoreStoreDefaults.dataStack`, fetches the `DynamicObject` instances in the `DataStack`'s context from a list of `NSManagedObjectID`.
|
||||
|
||||
- parameter objectIDs: the `NSManagedObjectID` array for the objects
|
||||
- returns: the `DynamicObject` array for objects that exists in the `DataStack`
|
||||
*/
|
||||
public static func fetchExisting<D: DynamicObject, S: Sequence>(_ objectIDs: S) -> [D] where S.Iterator.Element == NSManagedObjectID {
|
||||
public static func fetchExisting<O: DynamicObject, S: Sequence>(_ objectIDs: S) -> [O] where S.Iterator.Element == NSManagedObjectID {
|
||||
|
||||
return self.defaultStack.fetchExisting(objectIDs)
|
||||
return CoreStoreDefaults.dataStack.fetchExisting(objectIDs)
|
||||
}
|
||||
|
||||
/**
|
||||
Using the `defaultStack`, fetches the first `DynamicObject` instance that satisfies the specified `FetchClause`s. Accepts `Where`, `OrderBy`, and `Tweak` clauses.
|
||||
Using the `CoreStoreDefaults.dataStack`, fetches the first `DynamicObject` instance that satisfies the specified `FetchClause`s. Accepts `Where`, `OrderBy`, and `Tweak` clauses.
|
||||
|
||||
- parameter from: a `From` clause indicating the entity type
|
||||
- parameter fetchClauses: a series of `FetchClause` instances for the fetch request. Accepts `Where`, `OrderBy`, and `Tweak` clauses.
|
||||
- returns: the first `DynamicObject` instance that satisfies the specified `FetchClause`s, or `nil` if no match was found
|
||||
- throws: `CoreStoreError.persistentStoreNotFound` if the specified entity could not be found in any store's schema.
|
||||
*/
|
||||
public static func fetchOne<D>(_ from: From<D>, _ fetchClauses: FetchClause...) throws -> D? {
|
||||
public static func fetchOne<O>(_ from: From<O>, _ fetchClauses: FetchClause...) throws -> O? {
|
||||
|
||||
return try self.defaultStack.fetchOne(from, fetchClauses)
|
||||
return try CoreStoreDefaults.dataStack.fetchOne(from, fetchClauses)
|
||||
}
|
||||
|
||||
/**
|
||||
Using the `defaultStack`, fetches the first `DynamicObject` instance that satisfies the specified `FetchClause`s. Accepts `Where`, `OrderBy`, and `Tweak` clauses.
|
||||
Using the `CoreStoreDefaults.dataStack`, fetches the first `DynamicObject` instance that satisfies the specified `FetchClause`s. Accepts `Where`, `OrderBy`, and `Tweak` clauses.
|
||||
|
||||
- parameter from: a `From` clause indicating the entity type
|
||||
- parameter fetchClauses: a series of `FetchClause` instances for the fetch request. Accepts `Where`, `OrderBy`, and `Tweak` clauses.
|
||||
- returns: the first `DynamicObject` instance that satisfies the specified `FetchClause`s, or `nil` if no match was found
|
||||
- throws: `CoreStoreError.persistentStoreNotFound` if the specified entity could not be found in any store's schema.
|
||||
*/
|
||||
public static func fetchOne<D>(_ from: From<D>, _ fetchClauses: [FetchClause]) throws -> D? {
|
||||
public static func fetchOne<O>(_ from: From<O>, _ fetchClauses: [FetchClause]) throws -> O? {
|
||||
|
||||
return try self.defaultStack.fetchOne(from, fetchClauses)
|
||||
return try CoreStoreDefaults.dataStack.fetchOne(from, fetchClauses)
|
||||
}
|
||||
|
||||
/**
|
||||
Fetches the first `DynamicObject` instance that satisfies the specified `FetchChainableBuilderType` built from a chain of clauses.
|
||||
```
|
||||
let youngestTeen = CoreStore.fetchOne(
|
||||
let youngestTeen = dataStack.fetchOne(
|
||||
From<MyPersonEntity>()
|
||||
.where(\.age > 18)
|
||||
.orderBy(.ascending(\.age))
|
||||
@@ -116,39 +117,39 @@ extension CoreStore {
|
||||
*/
|
||||
public static func fetchOne<B: FetchChainableBuilderType>(_ clauseChain: B) throws -> B.ObjectType? {
|
||||
|
||||
return try self.defaultStack.fetchOne(clauseChain)
|
||||
return try CoreStoreDefaults.dataStack.fetchOne(clauseChain)
|
||||
}
|
||||
|
||||
/**
|
||||
Using the `defaultStack`, fetches all `DynamicObject` instances that satisfy the specified `FetchClause`s. Accepts `Where`, `OrderBy`, and `Tweak` clauses.
|
||||
Using the `CoreStoreDefaults.dataStack`, fetches all `DynamicObject` instances that satisfy the specified `FetchClause`s. Accepts `Where`, `OrderBy`, and `Tweak` clauses.
|
||||
|
||||
- parameter from: a `From` clause indicating the entity type
|
||||
- parameter fetchClauses: a series of `FetchClause` instances for the fetch request. Accepts `Where`, `OrderBy`, and `Tweak` clauses.
|
||||
- returns: all `DynamicObject` instances that satisfy the specified `FetchClause`s, or an empty array if no match was found
|
||||
- throws: `CoreStoreError.persistentStoreNotFound` if the specified entity could not be found in any store's schema.
|
||||
*/
|
||||
public static func fetchAll<D>(_ from: From<D>, _ fetchClauses: FetchClause...) throws -> [D] {
|
||||
public static func fetchAll<O>(_ from: From<O>, _ fetchClauses: FetchClause...) throws -> [O] {
|
||||
|
||||
return try self.defaultStack.fetchAll(from, fetchClauses)
|
||||
return try CoreStoreDefaults.dataStack.fetchAll(from, fetchClauses)
|
||||
}
|
||||
|
||||
/**
|
||||
Using the `defaultStack`, fetches all `DynamicObject` instances that satisfy the specified `FetchClause`s. Accepts `Where`, `OrderBy`, and `Tweak` clauses.
|
||||
Using the `CoreStoreDefaults.dataStack`, fetches all `DynamicObject` instances that satisfy the specified `FetchClause`s. Accepts `Where`, `OrderBy`, and `Tweak` clauses.
|
||||
|
||||
- parameter from: a `From` clause indicating the entity type
|
||||
- parameter fetchClauses: a series of `FetchClause` instances for the fetch request. Accepts `Where`, `OrderBy`, and `Tweak` clauses.
|
||||
- returns: all `DynamicObject` instances that satisfy the specified `FetchClause`s, or an empty array if no match was found
|
||||
- throws: `CoreStoreError.persistentStoreNotFound` if the specified entity could not be found in any store's schema.
|
||||
*/
|
||||
public static func fetchAll<D>(_ from: From<D>, _ fetchClauses: [FetchClause]) throws -> [D] {
|
||||
public static func fetchAll<O>(_ from: From<O>, _ fetchClauses: [FetchClause]) throws -> [O] {
|
||||
|
||||
return try self.defaultStack.fetchAll(from, fetchClauses)
|
||||
return try CoreStoreDefaults.dataStack.fetchAll(from, fetchClauses)
|
||||
}
|
||||
|
||||
/**
|
||||
Fetches all `DynamicObject` instances that satisfy the specified `FetchChainableBuilderType` built from a chain of clauses.
|
||||
```
|
||||
let people = CoreStore.fetchAll(
|
||||
let people = dataStack.fetchAll(
|
||||
From<MyPersonEntity>()
|
||||
.where(\.age > 18)
|
||||
.orderBy(.ascending(\.age))
|
||||
@@ -160,39 +161,39 @@ extension CoreStore {
|
||||
*/
|
||||
public static func fetchAll<B: FetchChainableBuilderType>(_ clauseChain: B) throws -> [B.ObjectType] {
|
||||
|
||||
return try self.defaultStack.fetchAll(clauseChain)
|
||||
return try CoreStoreDefaults.dataStack.fetchAll(clauseChain)
|
||||
}
|
||||
|
||||
/**
|
||||
Using the `defaultStack`, fetches the number of `DynamicObject`s that satisfy the specified `FetchClause`s. Accepts `Where`, `OrderBy`, and `Tweak` clauses.
|
||||
Using the `CoreStoreDefaults.dataStack`, fetches the number of `DynamicObject`s that satisfy the specified `FetchClause`s. Accepts `Where`, `OrderBy`, and `Tweak` clauses.
|
||||
|
||||
- parameter from: a `From` clause indicating the entity type
|
||||
- parameter fetchClauses: a series of `FetchClause` instances for the fetch request. Accepts `Where`, `OrderBy`, and `Tweak` clauses.
|
||||
- returns: the number of `DynamicObject`s that satisfy the specified `FetchClause`s
|
||||
- throws: `CoreStoreError.persistentStoreNotFound` if the specified entity could not be found in any store's schema.
|
||||
*/
|
||||
public static func fetchCount<D>(_ from: From<D>, _ fetchClauses: FetchClause...) throws -> Int {
|
||||
public static func fetchCount<O>(_ from: From<O>, _ fetchClauses: FetchClause...) throws -> Int {
|
||||
|
||||
return try self.defaultStack.fetchCount(from, fetchClauses)
|
||||
return try CoreStoreDefaults.dataStack.fetchCount(from, fetchClauses)
|
||||
}
|
||||
|
||||
/**
|
||||
Using the `defaultStack`, fetches the number of `DynamicObject`s that satisfy the specified `FetchClause`s. Accepts `Where`, `OrderBy`, and `Tweak` clauses.
|
||||
Using the `CoreStoreDefaults.dataStack`, fetches the number of `DynamicObject`s that satisfy the specified `FetchClause`s. Accepts `Where`, `OrderBy`, and `Tweak` clauses.
|
||||
|
||||
- parameter from: a `From` clause indicating the entity type
|
||||
- parameter fetchClauses: a series of `FetchClause` instances for the fetch request. Accepts `Where`, `OrderBy`, and `Tweak` clauses.
|
||||
- returns: the number of `DynamicObject`s that satisfy the specified `FetchClause`s
|
||||
- throws: `CoreStoreError.persistentStoreNotFound` if the specified entity could not be found in any store's schema.
|
||||
*/
|
||||
public static func fetchCount<D>(_ from: From<D>, _ fetchClauses: [FetchClause]) throws -> Int {
|
||||
public static func fetchCount<O>(_ from: From<O>, _ fetchClauses: [FetchClause]) throws -> Int {
|
||||
|
||||
return try self.defaultStack.fetchCount(from, fetchClauses)
|
||||
return try CoreStoreDefaults.dataStack.fetchCount(from, fetchClauses)
|
||||
}
|
||||
|
||||
/**
|
||||
Fetches the number of `DynamicObject`s that satisfy the specified `FetchChainableBuilderType` built from a chain of clauses.
|
||||
```
|
||||
let numberOfAdults = CoreStore.fetchCount(
|
||||
let numberOfAdults = dataStack.fetchCount(
|
||||
From<MyPersonEntity>()
|
||||
.where(\.age > 18)
|
||||
.orderBy(.ascending(\.age))
|
||||
@@ -204,39 +205,39 @@ extension CoreStore {
|
||||
*/
|
||||
public static func fetchCount<B: FetchChainableBuilderType>(_ clauseChain: B) throws -> Int {
|
||||
|
||||
return try self.defaultStack.fetchCount(clauseChain)
|
||||
return try CoreStoreDefaults.dataStack.fetchCount(clauseChain)
|
||||
}
|
||||
|
||||
/**
|
||||
Using the `defaultStack`, fetches the `NSManagedObjectID` for the first `DynamicObject` that satisfies the specified `FetchClause`s. Accepts `Where`, `OrderBy`, and `Tweak` clauses.
|
||||
Using the `CoreStoreDefaults.dataStack`, fetches the `NSManagedObjectID` for the first `DynamicObject` that satisfies the specified `FetchClause`s. Accepts `Where`, `OrderBy`, and `Tweak` clauses.
|
||||
|
||||
- parameter from: a `From` clause indicating the entity type
|
||||
- parameter fetchClauses: a series of `FetchClause` instances for the fetch request. Accepts `Where`, `OrderBy`, and `Tweak` clauses.
|
||||
- returns: the `NSManagedObjectID` for the first `DynamicObject` that satisfies the specified `FetchClause`s, or `nil` if no match was found
|
||||
- throws: `CoreStoreError.persistentStoreNotFound` if the specified entity could not be found in any store's schema.
|
||||
*/
|
||||
public static func fetchObjectID<D>(_ from: From<D>, _ fetchClauses: FetchClause...) throws -> NSManagedObjectID? {
|
||||
public static func fetchObjectID<O>(_ from: From<O>, _ fetchClauses: FetchClause...) throws -> NSManagedObjectID? {
|
||||
|
||||
return try self.defaultStack.fetchObjectID(from, fetchClauses)
|
||||
return try CoreStoreDefaults.dataStack.fetchObjectID(from, fetchClauses)
|
||||
}
|
||||
|
||||
/**
|
||||
Using the `defaultStack`, fetches the `NSManagedObjectID` for the first `DynamicObject` that satisfies the specified `FetchClause`s. Accepts `Where`, `OrderBy`, and `Tweak` clauses.
|
||||
Using the `CoreStoreDefaults.dataStack`, fetches the `NSManagedObjectID` for the first `DynamicObject` that satisfies the specified `FetchClause`s. Accepts `Where`, `OrderBy`, and `Tweak` clauses.
|
||||
|
||||
- parameter from: a `From` clause indicating the entity type
|
||||
- parameter fetchClauses: a series of `FetchClause` instances for the fetch request. Accepts `Where`, `OrderBy`, and `Tweak` clauses.
|
||||
- returns: the `NSManagedObjectID` for the first `DynamicObject` that satisfies the specified `FetchClause`s, or `nil` if no match was found
|
||||
- throws: `CoreStoreError.persistentStoreNotFound` if the specified entity could not be found in any store's schema.
|
||||
*/
|
||||
public static func fetchObjectID<D>(_ from: From<D>, _ fetchClauses: [FetchClause]) throws -> NSManagedObjectID? {
|
||||
public static func fetchObjectID<O>(_ from: From<O>, _ fetchClauses: [FetchClause]) throws -> NSManagedObjectID? {
|
||||
|
||||
return try self.defaultStack.fetchObjectID(from, fetchClauses)
|
||||
return try CoreStoreDefaults.dataStack.fetchObjectID(from, fetchClauses)
|
||||
}
|
||||
|
||||
/**
|
||||
Fetches the `NSManagedObjectID` for the first `DynamicObject` that satisfies the specified `FetchChainableBuilderType` built from a chain of clauses.
|
||||
```
|
||||
let youngestTeenID = CoreStore.fetchObjectID(
|
||||
let youngestTeenID = dataStack.fetchObjectID(
|
||||
From<MyPersonEntity>()
|
||||
.where(\.age > 18)
|
||||
.orderBy(.ascending(\.age))
|
||||
@@ -248,33 +249,33 @@ extension CoreStore {
|
||||
*/
|
||||
public static func fetchObjectID<B: FetchChainableBuilderType>(_ clauseChain: B) throws -> NSManagedObjectID? {
|
||||
|
||||
return try self.defaultStack.fetchObjectID(clauseChain)
|
||||
return try CoreStoreDefaults.dataStack.fetchObjectID(clauseChain)
|
||||
}
|
||||
|
||||
/**
|
||||
Using the `defaultStack`, fetches the `NSManagedObjectID` for all `DynamicObject`s that satisfy the specified `FetchClause`s. Accepts `Where`, `OrderBy`, and `Tweak` clauses.
|
||||
Using the `CoreStoreDefaults.dataStack`, fetches the `NSManagedObjectID` for all `DynamicObject`s that satisfy the specified `FetchClause`s. Accepts `Where`, `OrderBy`, and `Tweak` clauses.
|
||||
|
||||
- parameter from: a `From` clause indicating the entity type
|
||||
- parameter fetchClauses: a series of `FetchClause` instances for the fetch request. Accepts `Where`, `OrderBy`, and `Tweak` clauses.
|
||||
- returns: the `NSManagedObjectID` for all `DynamicObject`s that satisfy the specified `FetchClause`s, or an empty array if no match was found
|
||||
- throws: `CoreStoreError.persistentStoreNotFound` if the specified entity could not be found in any store's schema.
|
||||
*/
|
||||
public static func fetchObjectIDs<D>(_ from: From<D>, _ fetchClauses: FetchClause...) throws -> [NSManagedObjectID] {
|
||||
public static func fetchObjectIDs<O>(_ from: From<O>, _ fetchClauses: FetchClause...) throws -> [NSManagedObjectID] {
|
||||
|
||||
return try self.defaultStack.fetchObjectIDs(from, fetchClauses)
|
||||
return try CoreStoreDefaults.dataStack.fetchObjectIDs(from, fetchClauses)
|
||||
}
|
||||
|
||||
/**
|
||||
Using the `defaultStack`, fetches the `NSManagedObjectID` for all `DynamicObject`s that satisfy the specified `FetchClause`s. Accepts `Where`, `OrderBy`, and `Tweak` clauses.
|
||||
Using the `CoreStoreDefaults.dataStack`, fetches the `NSManagedObjectID` for all `DynamicObject`s that satisfy the specified `FetchClause`s. Accepts `Where`, `OrderBy`, and `Tweak` clauses.
|
||||
|
||||
- parameter from: a `From` clause indicating the entity type
|
||||
- parameter fetchClauses: a series of `FetchClause` instances for the fetch request. Accepts `Where`, `OrderBy`, and `Tweak` clauses.
|
||||
- returns: the `NSManagedObjectID` for all `DynamicObject`s that satisfy the specified `FetchClause`s, or an empty array if no match was found
|
||||
- throws: `CoreStoreError.persistentStoreNotFound` if the specified entity could not be found in any store's schema.
|
||||
*/
|
||||
public static func fetchObjectIDs<D>(_ from: From<D>, _ fetchClauses: [FetchClause]) throws -> [NSManagedObjectID] {
|
||||
public static func fetchObjectIDs<O>(_ from: From<O>, _ fetchClauses: [FetchClause]) throws -> [NSManagedObjectID] {
|
||||
|
||||
return try self.defaultStack.fetchObjectIDs(from, fetchClauses)
|
||||
return try CoreStoreDefaults.dataStack.fetchObjectIDs(from, fetchClauses)
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -292,11 +293,11 @@ extension CoreStore {
|
||||
*/
|
||||
public static func fetchObjectIDs<B: FetchChainableBuilderType>(_ clauseChain: B) throws -> [NSManagedObjectID] {
|
||||
|
||||
return try self.defaultStack.fetchObjectIDs(clauseChain)
|
||||
return try CoreStoreDefaults.dataStack.fetchObjectIDs(clauseChain)
|
||||
}
|
||||
|
||||
/**
|
||||
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.
|
||||
Using the `CoreStoreDefaults.dataStack`, 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.
|
||||
|
||||
@@ -306,13 +307,13 @@ extension CoreStore {
|
||||
- returns: the result of the the query, or `nil` if no match was found. The type of the return value is specified by the generic type of the `Select<U>` parameter.
|
||||
- throws: `CoreStoreError.persistentStoreNotFound` if the specified entity could not be found in any store's schema.
|
||||
*/
|
||||
public static func queryValue<D, U: QueryableAttributeType>(_ from: From<D>, _ selectClause: Select<D, U>, _ queryClauses: QueryClause...) throws -> U? {
|
||||
public static func queryValue<O, U: QueryableAttributeType>(_ from: From<O>, _ selectClause: Select<O, U>, _ queryClauses: QueryClause...) throws -> U? {
|
||||
|
||||
return try self.defaultStack.queryValue(from, selectClause, queryClauses)
|
||||
return try CoreStoreDefaults.dataStack.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.
|
||||
Using the `CoreStoreDefaults.dataStack`, 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.
|
||||
|
||||
@@ -322,9 +323,9 @@ extension CoreStore {
|
||||
- returns: the result of the the query, or `nil` if no match was found. The type of the return value is specified by the generic type of the `Select<U>` parameter.
|
||||
- throws: `CoreStoreError.persistentStoreNotFound` if the specified entity could not be found in any store's schema.
|
||||
*/
|
||||
public static func queryValue<D, U: QueryableAttributeType>(_ from: From<D>, _ selectClause: Select<D, U>, _ queryClauses: [QueryClause]) throws -> U? {
|
||||
public static func queryValue<O, U: QueryableAttributeType>(_ from: From<O>, _ selectClause: Select<O, U>, _ queryClauses: [QueryClause]) throws -> U? {
|
||||
|
||||
return try self.defaultStack.queryValue(from, selectClause, queryClauses)
|
||||
return try CoreStoreDefaults.dataStack.queryValue(from, selectClause, queryClauses)
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -332,7 +333,7 @@ extension CoreStore {
|
||||
|
||||
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.
|
||||
```
|
||||
let averageAdultAge = CoreStore.queryValue(
|
||||
let averageAdultAge = dataStack.queryValue(
|
||||
From<MyPersonEntity>()
|
||||
.select(Int.self, .average(\.age))
|
||||
.where(\.age > 18)
|
||||
@@ -344,11 +345,11 @@ extension CoreStore {
|
||||
*/
|
||||
public static func queryValue<B: QueryChainableBuilderType>(_ clauseChain: B) throws -> B.ResultType? where B.ResultType: QueryableAttributeType {
|
||||
|
||||
return try self.defaultStack.queryValue(clauseChain)
|
||||
return try CoreStoreDefaults.dataStack.queryValue(clauseChain)
|
||||
}
|
||||
|
||||
/**
|
||||
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.
|
||||
Using the `CoreStoreDefaults.dataStack`, 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.
|
||||
|
||||
@@ -358,13 +359,13 @@ extension CoreStore {
|
||||
- returns: the result of the the query. The type of the return value is specified by the generic type of the `Select<U>` parameter.
|
||||
- throws: `CoreStoreError.persistentStoreNotFound` if the specified entity could not be found in any store's schema.
|
||||
*/
|
||||
public static func queryAttributes<D>(_ from: From<D>, _ selectClause: Select<D, NSDictionary>, _ queryClauses: QueryClause...) throws -> [[String: Any]] {
|
||||
public static func queryAttributes<O>(_ from: From<O>, _ selectClause: Select<O, NSDictionary>, _ queryClauses: QueryClause...) throws -> [[String: Any]] {
|
||||
|
||||
return try self.defaultStack.queryAttributes(from, selectClause, queryClauses)
|
||||
return try CoreStoreDefaults.dataStack.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.
|
||||
Using the `CoreStoreDefaults.dataStack`, 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.
|
||||
|
||||
@@ -374,9 +375,9 @@ extension CoreStore {
|
||||
- returns: the result of the the query. The type of the return value is specified by the generic type of the `Select<U>` parameter.
|
||||
- throws: `CoreStoreError.persistentStoreNotFound` if the specified entity could not be found in any store's schema.
|
||||
*/
|
||||
public static func queryAttributes<D>(_ from: From<D>, _ selectClause: Select<D, NSDictionary>, _ queryClauses: [QueryClause]) throws -> [[String: Any]] {
|
||||
public static func queryAttributes<O>(_ from: From<O>, _ selectClause: Select<O, NSDictionary>, _ queryClauses: [QueryClause]) throws -> [[String: Any]] {
|
||||
|
||||
return try self.defaultStack.queryAttributes(from, selectClause, queryClauses)
|
||||
return try CoreStoreDefaults.dataStack.queryAttributes(from, selectClause, queryClauses)
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -384,7 +385,7 @@ extension CoreStore {
|
||||
|
||||
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.
|
||||
```
|
||||
let results = CoreStore.queryAttributes(
|
||||
let results = dataStack.queryAttributes(
|
||||
From<MyPersonEntity>()
|
||||
.select(
|
||||
NSDictionary.self,
|
||||
@@ -405,6 +406,6 @@ extension CoreStore {
|
||||
*/
|
||||
public static func queryAttributes<B: QueryChainableBuilderType>(_ clauseChain: B) throws -> [[String: Any]] where B.ResultType == NSDictionary {
|
||||
|
||||
return try self.defaultStack.queryAttributes(clauseChain)
|
||||
return try CoreStoreDefaults.dataStack.queryAttributes(clauseChain)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -29,114 +29,89 @@ import CoreData
|
||||
|
||||
// MARK: - CoreStore
|
||||
|
||||
@available(*, deprecated, message: "Call methods directly from the DataStack instead")
|
||||
extension CoreStore {
|
||||
|
||||
/**
|
||||
Returns the `defaultStack`'s model version. The version string is the same as the name of a version-specific .xcdatamodeld file or `CoreStoreSchema`.
|
||||
Returns the `CoreStoreDefaults.dataStack`'s model version. The version string is the same as the name of a version-specific .xcdatamodeld file or `CoreStoreSchema`.
|
||||
*/
|
||||
public static var modelVersion: String {
|
||||
|
||||
return self.defaultStack.modelVersion
|
||||
return CoreStoreDefaults.dataStack.modelVersion
|
||||
}
|
||||
|
||||
/**
|
||||
Returns the entity name-to-class type mapping from the `defaultStack`'s model.
|
||||
Returns the entity name-to-class type mapping from the `CoreStoreDefaults.dataStack`'s model.
|
||||
*/
|
||||
public static func entityTypesByName(for type: NSManagedObject.Type) -> [EntityName: NSManagedObject.Type] {
|
||||
|
||||
return self.defaultStack.entityTypesByName(for: type)
|
||||
return CoreStoreDefaults.dataStack.entityTypesByName(for: type)
|
||||
}
|
||||
|
||||
/**
|
||||
Returns the entity name-to-class type mapping from the `defaultStack`'s model.
|
||||
Returns the entity name-to-class type mapping from the `CoreStoreDefaults.dataStack`'s model.
|
||||
*/
|
||||
public static func entityTypesByName(for type: CoreStoreObject.Type) -> [EntityName: CoreStoreObject.Type] {
|
||||
|
||||
return self.defaultStack.entityTypesByName(for: type)
|
||||
return CoreStoreDefaults.dataStack.entityTypesByName(for: type)
|
||||
}
|
||||
|
||||
/**
|
||||
Returns the `NSEntityDescription` for the specified `NSManagedObject` subclass from `defaultStack`'s model.
|
||||
Returns the `NSEntityDescription` for the specified `NSManagedObject` subclass from `CoreStoreDefaults.dataStack`'s model.
|
||||
*/
|
||||
public static func entityDescription(for type: NSManagedObject.Type) -> NSEntityDescription? {
|
||||
|
||||
return self.defaultStack.entityDescription(for: type)
|
||||
return CoreStoreDefaults.dataStack.entityDescription(for: type)
|
||||
}
|
||||
|
||||
/**
|
||||
Returns the `NSEntityDescription` for the specified `CoreStoreObject` subclass from `defaultStack`'s model.
|
||||
Returns the `NSEntityDescription` for the specified `CoreStoreObject` subclass from `CoreStoreDefaults.dataStack`'s model.
|
||||
*/
|
||||
public static func entityDescription(for type: CoreStoreObject.Type) -> NSEntityDescription? {
|
||||
|
||||
return self.defaultStack.entityDescription(for: type)
|
||||
return CoreStoreDefaults.dataStack.entityDescription(for: type)
|
||||
}
|
||||
|
||||
/**
|
||||
Creates an `SQLiteStore` with default parameters and adds it to the `defaultStack`. This method blocks until completion.
|
||||
Creates an `SQLiteStore` with default parameters and adds it to the `CoreStoreDefaults.dataStack`. This method blocks until completion.
|
||||
```
|
||||
try CoreStore.addStorageAndWait()
|
||||
```
|
||||
- returns: the local SQLite storage added to the `defaultStack`
|
||||
- returns: the local SQLite storage added to the `CoreStoreDefaults.dataStack`
|
||||
*/
|
||||
@discardableResult
|
||||
public static func addStorageAndWait() throws -> SQLiteStore {
|
||||
|
||||
return try self.defaultStack.addStorageAndWait(SQLiteStore())
|
||||
return try CoreStoreDefaults.dataStack.addStorageAndWait(SQLiteStore())
|
||||
}
|
||||
|
||||
/**
|
||||
Adds a `StorageInterface` to the `defaultStack` and blocks until completion.
|
||||
Adds a `StorageInterface` to the `CoreStoreDefaults.dataStack` and blocks until completion.
|
||||
```
|
||||
try CoreStore.addStorageAndWait(InMemoryStore(configuration: "Config1"))
|
||||
```
|
||||
- parameter storage: the `StorageInterface`
|
||||
- throws: a `CoreStoreError` value indicating the failure
|
||||
- returns: the `StorageInterface` added to the `defaultStack`
|
||||
- returns: the `StorageInterface` added to the `CoreStoreDefaults.dataStack`
|
||||
*/
|
||||
@discardableResult
|
||||
public static func addStorageAndWait<T: StorageInterface>(_ storage: T) throws -> T {
|
||||
|
||||
return try self.defaultStack.addStorageAndWait(storage)
|
||||
return try CoreStoreDefaults.dataStack.addStorageAndWait(storage)
|
||||
}
|
||||
|
||||
/**
|
||||
Adds a `LocalStorage` to the `defaultStack` and blocks until completion.
|
||||
Adds a `LocalStorage` to the `CoreStoreDefaults.dataStack` and blocks until completion.
|
||||
```
|
||||
try CoreStore.addStorageAndWait(SQLiteStore(configuration: "Config1"))
|
||||
```
|
||||
- parameter storage: the local storage
|
||||
- throws: a `CoreStoreError` value indicating the failure
|
||||
- returns: the local storage added to the `defaultStack`. Note that this may not always be the same instance as the parameter argument if a previous `LocalStorage` was already added at the same URL and with the same configuration.
|
||||
- returns: the local storage added to the `CoreStoreDefaults.dataStack`. Note that this may not always be the same instance as the parameter argument if a previous `LocalStorage` was already added at the same URL and with the same configuration.
|
||||
*/
|
||||
@discardableResult
|
||||
public static func addStorageAndWait<T: LocalStorage>(_ storage: T) throws -> T {
|
||||
|
||||
return try self.defaultStack.addStorageAndWait(storage)
|
||||
}
|
||||
|
||||
/**
|
||||
Adds a `CloudStorage` to the `defaultStack` and blocks until completion.
|
||||
```
|
||||
guard let storage = ICloudStore(
|
||||
ubiquitousContentName: "MyAppCloudData",
|
||||
ubiquitousContentTransactionLogsSubdirectory: "logs/config1",
|
||||
ubiquitousContainerID: "iCloud.com.mycompany.myapp.containername",
|
||||
ubiquitousPeerToken: "9614d658014f4151a95d8048fb717cf0",
|
||||
configuration: "Config1",
|
||||
cloudStorageOptions: .recreateLocalStoreOnModelMismatch
|
||||
) else {
|
||||
// iCloud is not available on the device
|
||||
return
|
||||
}
|
||||
try CoreStore.addStorageAndWait(storage)
|
||||
```
|
||||
- parameter storage: the local storage
|
||||
- throws: a `CoreStoreError` value indicating the failure
|
||||
- returns: the cloud storage added to the stack. Note that this may not always be the same instance as the parameter argument if a previous `CloudStorage` was already added at the same URL and with the same configuration.
|
||||
*/
|
||||
@discardableResult
|
||||
public static func addStorageAndWait<T: CloudStorage>(_ storage: T) throws -> T {
|
||||
|
||||
return try self.defaultStack.addStorageAndWait(storage)
|
||||
return try CoreStoreDefaults.dataStack.addStorageAndWait(storage)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -28,21 +28,22 @@ import Foundation
|
||||
|
||||
// MARK: - CoreStore
|
||||
|
||||
@available(*, deprecated, message: "Call methods directly from the DataStack instead")
|
||||
extension CoreStore {
|
||||
|
||||
/**
|
||||
Using the `defaultStack`, performs a transaction asynchronously where `NSManagedObject` or `CoreStoreObject` creates, updates, and deletes can be made. The changes are commited automatically after the `task` closure returns. On success, the value returned from closure will be the wrapped as `.success(T)` in the `completion`'s `Result<T>`. Any errors thrown from inside the `task` will be reported as `.failure(CoreStoreError)`. To cancel/rollback changes, call `try transaction.cancel()`, which throws a `CoreStoreError.userCancelled`.
|
||||
Using the `CoreStoreDefaults.dataStack`, performs a transaction asynchronously where `NSManagedObject` or `CoreStoreObject` creates, updates, and deletes can be made. The changes are commited automatically after the `task` closure returns. On success, the value returned from closure will be the wrapped as `.success(T)` in the `completion`'s `Result<T>`. Any errors thrown from inside the `task` will be reported as `.failure(CoreStoreError)`. To cancel/rollback changes, call `try transaction.cancel()`, which throws a `CoreStoreError.userCancelled`.
|
||||
|
||||
- parameter task: the asynchronous closure 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`.
|
||||
- parameter completion: the closure executed after the save completes. The `Result` argument of the closure will either wrap the return value of `task`, or any uncaught errors thrown from within `task`. Cancelled `task`s will be indicated by `.failure(error: CoreStoreError.userCancelled)`. Custom errors thrown by the user will be wrapped in `CoreStoreError.userError(error: Error)`.
|
||||
*/
|
||||
public static func perform<T>(asynchronous task: @escaping (_ transaction: AsynchronousDataTransaction) throws -> T, completion: @escaping (AsynchronousDataTransaction.Result<T>) -> Void) {
|
||||
|
||||
self.defaultStack.perform(asynchronous: task, completion: completion)
|
||||
CoreStoreDefaults.dataStack.perform(asynchronous: task, completion: completion)
|
||||
}
|
||||
|
||||
/**
|
||||
Using the `defaultStack`, performs a transaction asynchronously where `NSManagedObject` or `CoreStoreObject` creates, updates, and deletes can be made. The changes are commited automatically after the `task` closure returns. On success, the value returned from closure will be the argument of the `success` closure. Any errors thrown from inside the `task` will be wrapped in a `CoreStoreError` and reported in the `failure` closure. To cancel/rollback changes, call `try transaction.cancel()`, which throws a `CoreStoreError.userCancelled`.
|
||||
Using the `CoreStoreDefaults.dataStack`, performs a transaction asynchronously where `NSManagedObject` or `CoreStoreObject` creates, updates, and deletes can be made. The changes are commited automatically after the `task` closure returns. On success, the value returned from closure will be the argument of the `success` closure. Any errors thrown from inside the `task` will be wrapped in a `CoreStoreError` and reported in the `failure` closure. To cancel/rollback changes, call `try transaction.cancel()`, which throws a `CoreStoreError.userCancelled`.
|
||||
|
||||
- parameter task: the asynchronous closure 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`.
|
||||
- parameter success: the closure executed after the save succeeds. The `T` argument of the closure will be the value returned from `task`.
|
||||
@@ -50,11 +51,11 @@ extension CoreStore {
|
||||
*/
|
||||
public static func perform<T>(asynchronous task: @escaping (_ transaction: AsynchronousDataTransaction) throws -> T, success: @escaping (T) -> Void, failure: @escaping (CoreStoreError) -> Void) {
|
||||
|
||||
self.defaultStack.perform(asynchronous: task, success: success, failure: failure)
|
||||
CoreStoreDefaults.dataStack.perform(asynchronous: task, success: success, failure: failure)
|
||||
}
|
||||
|
||||
/**
|
||||
Using the `defaultStack`, performs a transaction synchronously where `NSManagedObject` or `CoreStoreObject` creates, updates, and deletes can be made. The changes are commited automatically after the `task` closure returns. On success, the value returned from closure will be the return value of `perform(synchronous:)`. Any errors thrown from inside the `task` will be thrown from `perform(synchronous:)`. To cancel/rollback changes, call `try transaction.cancel()`, which throws a `CoreStoreError.userCancelled`.
|
||||
Using the `CoreStoreDefaults.dataStack`, performs a transaction synchronously where `NSManagedObject` or `CoreStoreObject` creates, updates, and deletes can be made. The changes are commited automatically after the `task` closure returns. On success, the value returned from closure will be the return value of `perform(synchronous:)`. Any errors thrown from inside the `task` will be thrown from `perform(synchronous:)`. To cancel/rollback changes, call `try transaction.cancel()`, which throws a `CoreStoreError.userCancelled`.
|
||||
|
||||
- parameter task: the synchronous non-escaping closure 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`.
|
||||
- parameter waitForAllObservers: When `true`, this method waits for all observers to be notified of the changes before returning. This results in more predictable data update order, but may risk triggering deadlocks. When `false`, this method does not wait for observers to be notified of the changes before returning. This results in lower risk for deadlocks, but the updated data may not have been propagated to the `DataStack` after returning. Defaults to `true`.
|
||||
@@ -63,25 +64,25 @@ extension CoreStore {
|
||||
*/
|
||||
public static func perform<T>(synchronous task: ((_ transaction: SynchronousDataTransaction) throws -> T), waitForAllObservers: Bool = true) throws -> T {
|
||||
|
||||
return try self.defaultStack.perform(synchronous: task, waitForAllObservers: waitForAllObservers)
|
||||
return try CoreStoreDefaults.dataStack.perform(synchronous: task, waitForAllObservers: waitForAllObservers)
|
||||
}
|
||||
|
||||
/**
|
||||
Using the `defaultStack`, begins a non-contiguous transaction where `NSManagedObject` or `CoreStoreObject` creates, updates, and deletes can be made. This is useful for making temporary changes, such as partially filled forms.
|
||||
Using the `CoreStoreDefaults.dataStack`, begins a non-contiguous transaction where `NSManagedObject` or `CoreStoreObject` creates, updates, and deletes can be made. This is useful for making temporary changes, such as partially filled forms.
|
||||
|
||||
- prameter supportsUndo: `undo()`, `redo()`, and `rollback()` methods are only available when this parameter is `true`, otherwise those method will raise an exception. Defaults to `false`. Note that turning on Undo support may heavily impact performance especially on iOS or watchOS where memory is limited.
|
||||
- returns: a `UnsafeDataTransaction` instance where creates, updates, and deletes can be made.
|
||||
*/
|
||||
public static func beginUnsafe(supportsUndo: Bool = false) -> UnsafeDataTransaction {
|
||||
|
||||
return self.defaultStack.beginUnsafe(supportsUndo: supportsUndo)
|
||||
return CoreStoreDefaults.dataStack.beginUnsafe(supportsUndo: supportsUndo)
|
||||
}
|
||||
|
||||
/**
|
||||
Refreshes all registered objects `NSManagedObject`s or `CoreStoreObject`s in the `defaultStack`.
|
||||
Refreshes all registered objects `NSManagedObject`s or `CoreStoreObject`s in the `CoreStoreDefaults.dataStack`.
|
||||
*/
|
||||
public static func refreshAndMergeAllObjects() {
|
||||
|
||||
self.defaultStack.refreshAndMergeAllObjects()
|
||||
CoreStoreDefaults.dataStack.refreshAndMergeAllObjects()
|
||||
}
|
||||
}
|
||||
|
||||
@@ -31,39 +31,20 @@ import CoreData
|
||||
/**
|
||||
`CoreStore` is the main entry point for all other APIs.
|
||||
*/
|
||||
@available(*, deprecated, message: "Call methods directly from the DataStack instead")
|
||||
public enum CoreStore {
|
||||
|
||||
/**
|
||||
The default `DataStack` instance to be used. If `defaultStack` is not set before the first time accessed, a default-configured `DataStack` will be created.
|
||||
- SeeAlso: `DataStack`
|
||||
- Note: Changing the `defaultStack` is thread safe, but it is recommended to setup `DataStacks` on a common queue (e.g. the main queue).
|
||||
*/
|
||||
|
||||
@available(*, unavailable, renamed: "CoreStoreDefaults.logger")
|
||||
public static var logger: CoreStoreLogger {
|
||||
|
||||
get { return CoreStoreDefaults.logger }
|
||||
set { CoreStoreDefaults.logger = newValue }
|
||||
}
|
||||
|
||||
@available(*, unavailable, renamed: "CoreStoreDefaults.dataStack")
|
||||
public static var defaultStack: DataStack {
|
||||
|
||||
get {
|
||||
|
||||
self.defaultStackBarrierQueue.sync(flags: .barrier) {
|
||||
|
||||
if self.defaultStackInstance == nil {
|
||||
|
||||
self.defaultStackInstance = DataStack()
|
||||
}
|
||||
}
|
||||
return self.defaultStackInstance!
|
||||
}
|
||||
set {
|
||||
|
||||
self.defaultStackBarrierQueue.async(flags: .barrier) {
|
||||
|
||||
self.defaultStackInstance = newValue
|
||||
}
|
||||
}
|
||||
get { return CoreStoreDefaults.dataStack }
|
||||
set { CoreStoreDefaults.dataStack = newValue }
|
||||
}
|
||||
|
||||
|
||||
// MARK: Private
|
||||
|
||||
private static let defaultStackBarrierQueue = DispatchQueue.concurrent("com.coreStore.defaultStackBarrierQueue")
|
||||
|
||||
private static var defaultStackInstance: DataStack?
|
||||
}
|
||||
|
||||
@@ -31,7 +31,7 @@ import Foundation
|
||||
/**
|
||||
`CoreStoreObjectiveCType`s are Objective-C accessible classes that represent CoreStore's Swift types.
|
||||
*/
|
||||
public protocol CoreStoreObjectiveCType: class {
|
||||
public protocol CoreStoreObjectiveCType: AnyObject {
|
||||
|
||||
/**
|
||||
The corresponding Swift type
|
||||
|
||||
75
Sources/CoreStoreDefaults.swift
Normal file
75
Sources/CoreStoreDefaults.swift
Normal file
@@ -0,0 +1,75 @@
|
||||
//
|
||||
// CoreStoreDefaults.swift
|
||||
// CoreStore
|
||||
//
|
||||
// Copyright © 2018 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: - CoreStoreDefaults
|
||||
|
||||
/**
|
||||
Global utilities
|
||||
*/
|
||||
public enum CoreStoreDefaults {
|
||||
|
||||
/**
|
||||
The `CoreStoreLogger` instance to be used. The default logger is an instance of a `DefaultLogger`.
|
||||
*/
|
||||
public static var logger: CoreStoreLogger = DefaultLogger()
|
||||
|
||||
/**
|
||||
The default `DataStack` instance to be used. If `defaultStack` is not set during the first time accessed, a default-configured `DataStack` will be created.
|
||||
- SeeAlso: `DataStack`
|
||||
- Note: Changing `dataStack` is thread safe, but it is recommended to setup `DataStacks` on a common queue (e.g. the main queue).
|
||||
- Important: If `dataStack` is not set during the first time accessed, a default-configured `DataStack` will be created.
|
||||
*/
|
||||
public static var dataStack: DataStack {
|
||||
|
||||
get {
|
||||
|
||||
self.defaultStackBarrierQueue.sync(flags: .barrier) {
|
||||
|
||||
if self.defaultStackInstance == nil {
|
||||
|
||||
self.defaultStackInstance = DataStack()
|
||||
}
|
||||
}
|
||||
return self.defaultStackInstance!
|
||||
}
|
||||
set {
|
||||
|
||||
self.defaultStackBarrierQueue.async(flags: .barrier) {
|
||||
|
||||
self.defaultStackInstance = newValue
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// MARK: Private
|
||||
|
||||
private static let defaultStackBarrierQueue = DispatchQueue.concurrent("com.coreStore.defaultStackBarrierQueue")
|
||||
|
||||
private static var defaultStackInstance: DataStack?
|
||||
}
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user