Compare commits

..

1 Commits

Author SHA1 Message Date
John Estropia
81c5b0c650 fix iOS 10 NSFetchedResultsController bug for iOS 7-supporting branch 2016-11-08 10:04:49 +09:00
878 changed files with 33342 additions and 622448 deletions

View File

@@ -1,2 +0,0 @@
try:
project: 'CoreStore.xcworkspace'

3
.github/FUNDING.yml vendored
View File

@@ -1,3 +0,0 @@
# These are supported funding model platforms
github: [JohnEstropia]

7
.gitignore vendored
View File

@@ -7,10 +7,3 @@ CoreStore.xcworkspace/xcuserdata
.DS_Store
DerivedData
*.orig
build
Playground_macOS.playground/playground.xcworkspace/xcuserdata
.swiftpm/xcode/package.xcworkspace/xcuserdata
.swiftpm/xcode/xcuserdata
Playground_iOS.playground/playground.xcworkspace/xcuserdata
LegacyDemo/LegacyDemo.xcodeproj/xcuserdata
Demo/Demo.xcodeproj/xcuserdata

3
.gitmodules vendored
View File

@@ -0,0 +1,3 @@
[submodule "Carthage/Checkouts/GCDKit"]
path = Carthage/Checkouts/GCDKit
url = https://github.com/JohnEstropia/GCDKit.git

View File

@@ -1,15 +0,0 @@
author: John Estropia
author_url: https://github.com/JohnEstropia
github_url: https://github.com/JohnEstropia/CoreStore
module: CoreStore
readme: README.md
include: Sources/*
output: docs
theme: fullwidth
clean: true
skip_undocumented: true
xcodebuild_arguments:
- -sdk
- iphonesimulator
- -scheme
- CoreStore iOS

View File

@@ -1,7 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<Workspace
version = "1.0">
<FileRef
location = "self:">
</FileRef>
</Workspace>

43
.travis.yml Normal file
View File

@@ -0,0 +1,43 @@
language: objective-c
osx_image: xcode7.3
sudo: false
git:
submodules: false
notifications:
email: false
env:
global:
- LC_CTYPE=en_US.UTF-8
- LANG=en_US.UTF-8
matrix:
- DESTINATION="OS=9.3,name=iPhone 6s" SCHEME="CoreStore iOS" SDK=iphonesimulator9.3 RUN_TESTS="YES" POD_LINT="NO"
- DESTINATION="OS=9.0,name=iPhone 6 Plus" SCHEME="CoreStore iOS" SDK=iphonesimulator9.3 RUN_TESTS="YES" POD_LINT="NO"
- DESTINATION="OS=8.4,name=iPhone 6" SCHEME="CoreStore iOS" SDK=iphonesimulator9.3 RUN_TESTS="YES" POD_LINT="NO"
- DESTINATION="OS=8.3,name=iPhone 5S" SCHEME="CoreStore iOS" SDK=iphonesimulator9.3 RUN_TESTS="YES" POD_LINT="NO"
- DESTINATION="OS=8.2,name=iPhone 5" SCHEME="CoreStore iOS" SDK=iphonesimulator9.3 RUN_TESTS="YES" POD_LINT="NO"
- DESTINATION="OS=8.1,name=iPhone 4S" SCHEME="CoreStore iOS" SDK=iphonesimulator9.3 RUN_TESTS="YES" POD_LINT="YES"
- DESTINATION="OS=8.1,name=iPhone 4S" SCHEME="CoreStore iOS7" SDK=iphonesimulator9.3 RUN_TESTS="YES" POD_LINT="YES"
- DESTINATION="arch=x86_64" SCHEME="CoreStore OSX" SDK=macosx10.11 RUN_TESTS="YES" POD_LINT="NO"
- DESTINATION="OS=2.2,name=Apple Watch - 42mm" SCHEME="CoreStore watchOS" SDK=watchsimulator2.2 RUN_TESTS="NO" POD_LINT="NO"
- DESTINATION="OS=9.2,name=Apple TV 1080p" SCHEME="CoreStore tvOS" SDK=appletvsimulator9.2 RUN_TESTS="YES" POD_LINT="NO"
before_install:
- gem install cocoapods --no-rdoc --no-ri --no-document --quiet
- gem install xcpretty --no-rdoc --no-ri --no-document --quiet
- curl -OlL "https://github.com/Carthage/Carthage/releases/download/0.11/Carthage.pkg"
- sudo installer -pkg "Carthage.pkg" -target /
- rm "Carthage.pkg"
before_script:
- carthage update --use-submodules
script:
- set -o pipefail
- xcodebuild -version
- xcodebuild -showsdks
- if [ $RUN_TESTS == "YES" ]; then
xcodebuild -workspace CoreStore.xcworkspace -scheme "$SCHEME" -sdk "$SDK" -destination "$DESTINATION" -configuration Debug ONLY_ACTIVE_ARCH=NO clean test | xcpretty -c;
xcodebuild -workspace CoreStore.xcworkspace -scheme "$SCHEME" -sdk "$SDK" -destination "$DESTINATION" -configuration Release ONLY_ACTIVE_ARCH=NO clean test | xcpretty -c;
fi
- xcodebuild -workspace "CoreStore.xcworkspace" -scheme "CoreStore iOS" -sdk "iphonesimulator9.3" -destination "OS=9.3,name=iPhone 6s" -configuration Debug ONLY_ACTIVE_ARCH=NO clean test | xcpretty -c;
- xcodebuild -workspace "CoreStore.xcworkspace" -scheme "CoreStore iOS" -sdk "iphonesimulator9.3" -destination "OS=9.3,name=iPhone 6s" -configuration Release ONLY_ACTIVE_ARCH=NO clean test | xcpretty -c;
- if [ $POD_LINT == "YES" ]; then
pod lib lint --quick;
fi

1
Cartfile Normal file
View File

@@ -0,0 +1 @@
github "JohnEstropia/GCDKit" == 1.2.6

1
Cartfile.resolved Normal file
View File

@@ -0,0 +1 @@
github "JohnEstropia/GCDKit" "1.2.6"

1
Carthage/Checkouts/GCDKit vendored Submodule

Binary file not shown.

Before

Width:  |  Height:  |  Size: 61 KiB

After

Width:  |  Height:  |  Size: 53 KiB

View File

@@ -1,34 +1,24 @@
Pod::Spec.new do |s|
s.name = "CoreStore"
s.version = "9.1.0"
s.swift_version = "5.7"
s.version = "2.0.7"
s.license = "MIT"
s.homepage = "https://github.com/JohnEstropia/CoreStore"
s.documentation_url = "https://JohnEstropia.github.io/CoreStore"
s.summary = "Unleashing the real power of Core Data with the elegance and safety of Swift"
s.homepage = "https://github.com/JohnEstropia/CoreStore"
s.author = { "John Rommel Estropia" => "rommel.estropia@gmail.com" }
s.source = { :git => "https://github.com/JohnEstropia/CoreStore.git", :tag => s.version.to_s }
s.ios.deployment_target = "13.0"
s.osx.deployment_target = "10.15"
s.tvos.deployment_target = "13.0"
s.watchos.deployment_target = "7.4"
s.ios.deployment_target = "8.0"
s.osx.deployment_target = "10.10"
s.watchos.deployment_target = "2.0"
s.tvos.deployment_target = "9.0"
s.source_files = "Sources", "Sources/**/*.swift"
s.source_files = "Sources", "Sources/**/*.{swift,h,m}"
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', 'OTHER_LDFLAGS' => '-weak_framework Combine -weak_framework SwiftUI' }
s.pod_target_xcconfig = { 'OTHER_SWIFT_FLAGS[config=Debug]' => '-D USE_FRAMEWORKS -D DEBUG',
'OTHER_SWIFT_FLAGS[config=Release]' => '-D USE_FRAMEWORKS',
'GCC_PREPROCESSOR_DEFINITIONS' => 'USE_FRAMEWORKS=1' }
s.test_spec "CoreStoreTests" do |ts|
ts.source_files = "CoreStoreTests", "CoreStoreTests/**/*.swift", "CoreStoreTests/**/*.xcdatamodeld", "CoreStoreTests/**/*.xcdatamodel"
ts.public_header_files = "CoreStoreTests/**/*.h"
ts.resources = [ "CoreStoreTests/**/*.xcdatamodeld", "CoreStoreTests/**/*.xcdatamodel" ]
ts.preserve_paths = "CoreStoreTests/**/*.xcdatamodeld"
ts.frameworks = "Foundation", "CoreData"
ts.requires_arc = true
ts.ios.deployment_target = "13.0"
ts.osx.deployment_target = "10.15"
ts.tvos.deployment_target = "13.0"
end
s.dependency "GCDKit", "1.2.6"
end

Binary file not shown.

File diff suppressed because it is too large Load Diff

View File

@@ -10,10 +10,10 @@
"DVTSourceControlWorkspaceBlueprintIdentifierKey" : "F347F55F-7F5C-4476-9148-6E902F06E4AD",
"DVTSourceControlWorkspaceBlueprintWorkingCopyPathsKey" : {
"8B2E522D57154DFA93A06982C36315ECBEA4FA97" : "CoreStoreLibraries\/GCDKit",
"4B60F1BCB491FF717C56441AE7783C74F417BE48" : "CoreStore\/"
"4B60F1BCB491FF717C56441AE7783C74F417BE48" : "CoreStore"
},
"DVTSourceControlWorkspaceBlueprintNameKey" : "CoreStore",
"DVTSourceControlWorkspaceBlueprintVersion" : 204,
"DVTSourceControlWorkspaceBlueprintVersion" : 203,
"DVTSourceControlWorkspaceBlueprintRelativePathToProjectKey" : "CoreStore.xcodeproj",
"DVTSourceControlWorkspaceBlueprintRemoteRepositoriesKey" : [
{

View File

@@ -1,8 +0,0 @@
<?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>

View File

@@ -1,6 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<Scheme
LastUpgradeVersion = "1400"
LastUpgradeVersion = "0710"
version = "1.3">
<BuildAction
parallelizeBuildables = "YES"
@@ -27,15 +27,6 @@
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">
@@ -48,6 +39,17 @@
</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"
@@ -68,6 +70,8 @@
ReferencedContainer = "container:CoreStore.xcodeproj">
</BuildableReference>
</MacroExpansion>
<AdditionalOptions>
</AdditionalOptions>
</LaunchAction>
<ProfileAction
buildConfiguration = "Release"

View File

@@ -1,6 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<Scheme
LastUpgradeVersion = "1400"
LastUpgradeVersion = "0700"
version = "1.3">
<BuildAction
parallelizeBuildables = "YES"
@@ -11,7 +11,8 @@
buildForRunning = "YES"
buildForProfiling = "YES"
buildForArchiving = "YES"
buildForAnalyzing = "YES">
buildForAnalyzing = "YES"
hideIssues = "NO">
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "2F03A52F19C5C6DA005002A5"
@@ -25,7 +26,8 @@
buildForRunning = "NO"
buildForProfiling = "NO"
buildForArchiving = "NO"
buildForAnalyzing = "NO">
buildForAnalyzing = "NO"
hideIssues = "NO">
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "2F03A53A19C5C6DA005002A5"
@@ -41,22 +43,6 @@
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
shouldUseLaunchSchemeArgsEnv = "YES">
<MacroExpansion>
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "2F03A52F19C5C6DA005002A5"
BuildableName = "CoreStore.framework"
BlueprintName = "CoreStore iOS"
ReferencedContainer = "container:CoreStore.xcodeproj">
</BuildableReference>
</MacroExpansion>
<AdditionalOptions>
<AdditionalOption
key = "NSZombieEnabled"
value = "YES"
isEnabled = "YES">
</AdditionalOption>
</AdditionalOptions>
<Testables>
<TestableReference
skipped = "NO">
@@ -69,6 +55,17 @@
</BuildableReference>
</TestableReference>
</Testables>
<MacroExpansion>
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "2F03A52F19C5C6DA005002A5"
BuildableName = "CoreStore.framework"
BlueprintName = "CoreStore iOS"
ReferencedContainer = "container:CoreStore.xcodeproj">
</BuildableReference>
</MacroExpansion>
<AdditionalOptions>
</AdditionalOptions>
</TestAction>
<LaunchAction
buildConfiguration = "Debug"
@@ -89,12 +86,8 @@
ReferencedContainer = "container:CoreStore.xcodeproj">
</BuildableReference>
</MacroExpansion>
<CommandLineArguments>
<CommandLineArgument
argument = "-com.apple.CoreData.SQLDebug 2"
isEnabled = "NO">
</CommandLineArgument>
</CommandLineArguments>
<AdditionalOptions>
</AdditionalOptions>
</LaunchAction>
<ProfileAction
buildConfiguration = "Release"

View File

@@ -0,0 +1,104 @@
<?xml version="1.0" encoding="UTF-8"?>
<Scheme
LastUpgradeVersion = "0700"
version = "1.3">
<BuildAction
parallelizeBuildables = "YES"
buildImplicitDependencies = "YES">
<BuildActionEntries>
<BuildActionEntry
buildForTesting = "YES"
buildForRunning = "YES"
buildForProfiling = "YES"
buildForArchiving = "YES"
buildForAnalyzing = "YES">
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "B5D9E2ED1CA2C317007A9D52"
BuildableName = "CoreStore_iOS7.framework"
BlueprintName = "CoreStore iOS7"
ReferencedContainer = "container:CoreStore.xcodeproj">
</BuildableReference>
</BuildActionEntry>
<BuildActionEntry
buildForTesting = "YES"
buildForRunning = "NO"
buildForProfiling = "NO"
buildForArchiving = "NO"
buildForAnalyzing = "NO">
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "2F03A53A19C5C6DA005002A5"
BuildableName = "CoreStoreTests.xctest"
BlueprintName = "CoreStoreTests iOS"
ReferencedContainer = "container:CoreStore.xcodeproj">
</BuildableReference>
</BuildActionEntry>
</BuildActionEntries>
</BuildAction>
<TestAction
buildConfiguration = "Debug"
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
shouldUseLaunchSchemeArgsEnv = "YES">
<Testables>
<TestableReference
skipped = "NO">
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "2F03A53A19C5C6DA005002A5"
BuildableName = "CoreStoreTests.xctest"
BlueprintName = "CoreStoreTests iOS"
ReferencedContainer = "container:CoreStore.xcodeproj">
</BuildableReference>
</TestableReference>
</Testables>
<MacroExpansion>
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "2F03A52F19C5C6DA005002A5"
BuildableName = "CoreStore.framework"
BlueprintName = "CoreStore iOS"
ReferencedContainer = "container:CoreStore.xcodeproj">
</BuildableReference>
</MacroExpansion>
<AdditionalOptions>
</AdditionalOptions>
</TestAction>
<LaunchAction
buildConfiguration = "Debug"
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
launchStyle = "0"
useCustomWorkingDirectory = "NO"
ignoresPersistentStateOnLaunch = "NO"
debugDocumentVersioning = "YES"
debugServiceExtension = "internal"
allowLocationSimulation = "YES">
<MacroExpansion>
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "B5D9E2ED1CA2C317007A9D52"
BuildableName = "CoreStore_iOS7.framework"
BlueprintName = "CoreStore iOS7"
ReferencedContainer = "container:CoreStore.xcodeproj">
</BuildableReference>
</MacroExpansion>
<AdditionalOptions>
</AdditionalOptions>
</LaunchAction>
<ProfileAction
buildConfiguration = "Release"
shouldUseLaunchSchemeArgsEnv = "YES"
savedToolIdentifier = ""
useCustomWorkingDirectory = "NO"
debugDocumentVersioning = "YES">
</ProfileAction>
<AnalyzeAction
buildConfiguration = "Release">
</AnalyzeAction>
<ArchiveAction
buildConfiguration = "Release"
revealArchiveInOrganizer = "YES">
</ArchiveAction>
</Scheme>

View File

@@ -1,6 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<Scheme
LastUpgradeVersion = "1400"
LastUpgradeVersion = "0720"
version = "1.3">
<BuildAction
parallelizeBuildables = "YES"
@@ -27,15 +27,6 @@
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">
@@ -48,6 +39,17 @@
</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"
@@ -68,6 +70,8 @@
ReferencedContainer = "container:CoreStore.xcodeproj">
</BuildableReference>
</MacroExpansion>
<AdditionalOptions>
</AdditionalOptions>
</LaunchAction>
<ProfileAction
buildConfiguration = "Release"

View File

@@ -1,6 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<Scheme
LastUpgradeVersion = "1400"
LastUpgradeVersion = "0700"
version = "1.3">
<BuildAction
parallelizeBuildables = "YES"
@@ -20,20 +20,6 @@
ReferencedContainer = "container:CoreStore.xcodeproj">
</BuildableReference>
</BuildActionEntry>
<BuildActionEntry
buildForTesting = "YES"
buildForRunning = "NO"
buildForProfiling = "NO"
buildForArchiving = "NO"
buildForAnalyzing = "NO">
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "B5114DA328CEEE5400EEAE78"
BuildableName = "CoreStoreTests.xctest"
BlueprintName = "CoreStoreTests watchOS"
ReferencedContainer = "container:CoreStore.xcodeproj">
</BuildableReference>
</BuildActionEntry>
</BuildActionEntries>
</BuildAction>
<TestAction
@@ -42,17 +28,9 @@
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
shouldUseLaunchSchemeArgsEnv = "YES">
<Testables>
<TestableReference
skipped = "NO">
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "B5114DA328CEEE5400EEAE78"
BuildableName = "CoreStoreTests.xctest"
BlueprintName = "CoreStoreTests watchOS"
ReferencedContainer = "container:CoreStore.xcodeproj">
</BuildableReference>
</TestableReference>
</Testables>
<AdditionalOptions>
</AdditionalOptions>
</TestAction>
<LaunchAction
buildConfiguration = "Debug"
@@ -73,6 +51,8 @@
ReferencedContainer = "container:CoreStore.xcodeproj">
</BuildableReference>
</MacroExpansion>
<AdditionalOptions>
</AdditionalOptions>
</LaunchAction>
<ProfileAction
buildConfiguration = "Release"

View File

@@ -1,10 +1,13 @@
<?xml version="1.0" encoding="UTF-8"?>
<Workspace
version = "1.0">
<FileRef
location = "group:Demo/Demo.xcodeproj">
</FileRef>
<FileRef
location = "group:CoreStore.xcodeproj">
</FileRef>
<FileRef
location = "group:CoreStoreDemo/CoreStoreDemo.xcodeproj">
</FileRef>
<FileRef
location = "group:Carthage/Checkouts/GCDKit/GCDKit.xcodeproj">
</FileRef>
</Workspace>

View File

@@ -1,8 +0,0 @@
<?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>

View File

@@ -1,8 +0,0 @@
<?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>PreviewsEnabled</key>
<false/>
</dict>
</plist>

View File

@@ -0,0 +1,538 @@
// !$*UTF8*$!
{
archiveVersion = 1;
classes = {
};
objectVersion = 46;
objects = {
/* Begin PBXBuildFile section */
B503FADF1AFDC71700F90881 /* ListObserverDemoViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = B503FADB1AFDC71700F90881 /* ListObserverDemoViewController.swift */; };
B503FAE01AFDC71700F90881 /* ObjectObserverDemoViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = B503FADC1AFDC71700F90881 /* ObjectObserverDemoViewController.swift */; };
B503FAE11AFDC71700F90881 /* Palette.swift in Sources */ = {isa = PBXBuildFile; fileRef = B503FADD1AFDC71700F90881 /* Palette.swift */; };
B503FAE21AFDC71700F90881 /* PaletteTableViewCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = B503FADE1AFDC71700F90881 /* PaletteTableViewCell.swift */; };
B5125C121B521B78003A42C7 /* OrganismV2ToV3.xcmappingmodel in Sources */ = {isa = PBXBuildFile; fileRef = B5125C111B521B78003A42C7 /* OrganismV2ToV3.xcmappingmodel */; };
B5125C141B521BA7003A42C7 /* OrganismV3ToV2.xcmappingmodel in Sources */ = {isa = PBXBuildFile; fileRef = B5125C131B521BA7003A42C7 /* OrganismV3ToV2.xcmappingmodel */; };
B52977D91B120B80003D50A5 /* ObserversViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = B52977D81B120B80003D50A5 /* ObserversViewController.swift */; };
B52977DD1B120F3B003D50A5 /* TransactionsDemoViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = B52977DC1B120F3B003D50A5 /* TransactionsDemoViewController.swift */; };
B52977DF1B120F83003D50A5 /* MapKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = B52977DE1B120F83003D50A5 /* MapKit.framework */; };
B52977E11B120F8A003D50A5 /* CoreLocation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = B52977E01B120F8A003D50A5 /* CoreLocation.framework */; };
B52977E41B121635003D50A5 /* Place.swift in Sources */ = {isa = PBXBuildFile; fileRef = B52977E31B121635003D50A5 /* Place.swift */; };
B54AAD4F1AF4D26E00848AE0 /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = B54AAD4E1AF4D26E00848AE0 /* AppDelegate.swift */; };
B54AAD521AF4D26E00848AE0 /* CoreStoreDemo.xcdatamodeld in Sources */ = {isa = PBXBuildFile; fileRef = B54AAD501AF4D26E00848AE0 /* CoreStoreDemo.xcdatamodeld */; };
B54AAD591AF4D26E00848AE0 /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = B54AAD571AF4D26E00848AE0 /* Main.storyboard */; };
B54AAD5B1AF4D26E00848AE0 /* Images.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = B54AAD5A1AF4D26E00848AE0 /* Images.xcassets */; };
B54AAD5E1AF4D26E00848AE0 /* LaunchScreen.xib in Resources */ = {isa = PBXBuildFile; fileRef = B54AAD5C1AF4D26E00848AE0 /* LaunchScreen.xib */; };
B560070F1B3EC90F00A9A8F9 /* OrganismV2ToV3MigrationPolicy.swift in Sources */ = {isa = PBXBuildFile; fileRef = B560070E1B3EC90F00A9A8F9 /* OrganismV2ToV3MigrationPolicy.swift */; };
B566E32A1B117B1F00F4F0C6 /* StackSetupDemoViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = B566E3291B117B1F00F4F0C6 /* StackSetupDemoViewController.swift */; };
B566E3321B11DF3200F4F0C6 /* UserAccount.swift in Sources */ = {isa = PBXBuildFile; fileRef = B566E3311B11DF3200F4F0C6 /* UserAccount.swift */; };
B56964C91B20AC780075EE4A /* CustomLoggerViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = B56964C81B20AC780075EE4A /* CustomLoggerViewController.swift */; };
B56964D71B231AE90075EE4A /* StackSetupDemo.xcdatamodeld in Sources */ = {isa = PBXBuildFile; fileRef = B56964D51B231AE90075EE4A /* StackSetupDemo.xcdatamodeld */; };
B56964DA1B231BCA0075EE4A /* MaleAccount.swift in Sources */ = {isa = PBXBuildFile; fileRef = B56964D91B231BCA0075EE4A /* MaleAccount.swift */; };
B56964DC1B231BCB0075EE4A /* FemaleAccount.swift in Sources */ = {isa = PBXBuildFile; fileRef = B56964DB1B231BCB0075EE4A /* FemaleAccount.swift */; };
B569650C1B2B36E10075EE4A /* FetchingAndQueryingDemoViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = B569650B1B2B36E10075EE4A /* FetchingAndQueryingDemoViewController.swift */; };
B56965181B2E20CC0075EE4A /* TimeZone.swift in Sources */ = {isa = PBXBuildFile; fileRef = B56965171B2E20CC0075EE4A /* TimeZone.swift */; };
B569651A1B30888A0075EE4A /* FetchingResultsViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = B56965191B30888A0075EE4A /* FetchingResultsViewController.swift */; };
B569651C1B30889A0075EE4A /* QueryingResultsViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = B569651B1B30889A0075EE4A /* QueryingResultsViewController.swift */; };
B56965291B3582D30075EE4A /* MigrationDemo.xcdatamodeld in Sources */ = {isa = PBXBuildFile; fileRef = B56965271B3582D30075EE4A /* MigrationDemo.xcdatamodeld */; };
B5E599321B5240F50084BD5F /* OrganismTableViewCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = B5E599311B5240F50084BD5F /* OrganismTableViewCell.swift */; };
B5E89ACD1C52929C003B04A9 /* GCDKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = B5BDC9241C202429008147CD /* GCDKit.framework */; };
B5E89ACE1C52929C003B04A9 /* GCDKit.framework in Embed Frameworks */ = {isa = PBXBuildFile; fileRef = B5BDC9241C202429008147CD /* GCDKit.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; };
B5E89AD01C5292A2003B04A9 /* CoreStore.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = B5BDC9211C202429008147CD /* CoreStore.framework */; };
B5E89AD11C5292A2003B04A9 /* CoreStore.framework in Embed Frameworks */ = {isa = PBXBuildFile; fileRef = B5BDC9211C202429008147CD /* CoreStore.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; };
B5EE25851B36E23C0000406B /* OrganismV1.swift in Sources */ = {isa = PBXBuildFile; fileRef = B5EE25841B36E23C0000406B /* OrganismV1.swift */; };
B5EE25871B36E2520000406B /* OrganismV2.swift in Sources */ = {isa = PBXBuildFile; fileRef = B5EE25861B36E2520000406B /* OrganismV2.swift */; };
B5EE258C1B36E40D0000406B /* MigrationsDemoViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = B5EE258B1B36E40D0000406B /* MigrationsDemoViewController.swift */; };
B5EE259B1B3EA4890000406B /* OrganismV3.swift in Sources */ = {isa = PBXBuildFile; fileRef = B5EE259A1B3EA4890000406B /* OrganismV3.swift */; };
B5EE259E1B3EC1B20000406B /* OrganismProtocol.swift in Sources */ = {isa = PBXBuildFile; fileRef = B5EE259D1B3EC1B20000406B /* OrganismProtocol.swift */; };
/* End PBXBuildFile section */
/* Begin PBXCopyFilesBuildPhase section */
B5E89ACF1C52929C003B04A9 /* Embed Frameworks */ = {
isa = PBXCopyFilesBuildPhase;
buildActionMask = 2147483647;
dstPath = "";
dstSubfolderSpec = 10;
files = (
B5E89ACE1C52929C003B04A9 /* GCDKit.framework in Embed Frameworks */,
B5E89AD11C5292A2003B04A9 /* CoreStore.framework in Embed Frameworks */,
);
name = "Embed Frameworks";
runOnlyForDeploymentPostprocessing = 0;
};
/* End PBXCopyFilesBuildPhase section */
/* Begin PBXFileReference section */
B503FADB1AFDC71700F90881 /* ListObserverDemoViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ListObserverDemoViewController.swift; sourceTree = "<group>"; };
B503FADC1AFDC71700F90881 /* ObjectObserverDemoViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ObjectObserverDemoViewController.swift; sourceTree = "<group>"; };
B503FADD1AFDC71700F90881 /* Palette.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Palette.swift; sourceTree = "<group>"; };
B503FADE1AFDC71700F90881 /* PaletteTableViewCell.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = PaletteTableViewCell.swift; sourceTree = "<group>"; };
B5125C111B521B78003A42C7 /* OrganismV2ToV3.xcmappingmodel */ = {isa = PBXFileReference; lastKnownFileType = wrapper.xcmappingmodel; path = OrganismV2ToV3.xcmappingmodel; sourceTree = "<group>"; };
B5125C131B521BA7003A42C7 /* OrganismV3ToV2.xcmappingmodel */ = {isa = PBXFileReference; lastKnownFileType = wrapper.xcmappingmodel; path = OrganismV3ToV2.xcmappingmodel; sourceTree = "<group>"; };
B52977D81B120B80003D50A5 /* ObserversViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ObserversViewController.swift; sourceTree = "<group>"; };
B52977DC1B120F3B003D50A5 /* TransactionsDemoViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = TransactionsDemoViewController.swift; sourceTree = "<group>"; };
B52977DE1B120F83003D50A5 /* MapKit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = MapKit.framework; path = System/Library/Frameworks/MapKit.framework; sourceTree = SDKROOT; };
B52977E01B120F8A003D50A5 /* CoreLocation.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = CoreLocation.framework; path = System/Library/Frameworks/CoreLocation.framework; sourceTree = SDKROOT; };
B52977E31B121635003D50A5 /* Place.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Place.swift; sourceTree = "<group>"; };
B54AAD491AF4D26E00848AE0 /* CoreStoreDemo.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = CoreStoreDemo.app; sourceTree = BUILT_PRODUCTS_DIR; };
B54AAD4D1AF4D26E00848AE0 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = "<group>"; };
B54AAD4E1AF4D26E00848AE0 /* AppDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = "<group>"; };
B54AAD511AF4D26E00848AE0 /* CoreStoreDemo.xcdatamodel */ = {isa = PBXFileReference; lastKnownFileType = wrapper.xcdatamodel; path = CoreStoreDemo.xcdatamodel; sourceTree = "<group>"; };
B54AAD581AF4D26E00848AE0 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/Main.storyboard; sourceTree = "<group>"; };
B54AAD5A1AF4D26E00848AE0 /* Images.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Images.xcassets; sourceTree = "<group>"; };
B54AAD5D1AF4D26E00848AE0 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.xib; name = Base; path = Base.lproj/LaunchScreen.xib; sourceTree = "<group>"; };
B560070E1B3EC90F00A9A8F9 /* OrganismV2ToV3MigrationPolicy.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = OrganismV2ToV3MigrationPolicy.swift; sourceTree = "<group>"; };
B566E3291B117B1F00F4F0C6 /* StackSetupDemoViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = StackSetupDemoViewController.swift; sourceTree = "<group>"; };
B566E3311B11DF3200F4F0C6 /* UserAccount.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = UserAccount.swift; sourceTree = "<group>"; };
B56964C81B20AC780075EE4A /* CustomLoggerViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = CustomLoggerViewController.swift; sourceTree = "<group>"; };
B56964D61B231AE90075EE4A /* StackSetupDemo.xcdatamodel */ = {isa = PBXFileReference; lastKnownFileType = wrapper.xcdatamodel; path = StackSetupDemo.xcdatamodel; sourceTree = "<group>"; };
B56964D91B231BCA0075EE4A /* MaleAccount.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = MaleAccount.swift; sourceTree = "<group>"; };
B56964DB1B231BCB0075EE4A /* FemaleAccount.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = FemaleAccount.swift; sourceTree = "<group>"; };
B569650B1B2B36E10075EE4A /* FetchingAndQueryingDemoViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = FetchingAndQueryingDemoViewController.swift; sourceTree = "<group>"; };
B56965171B2E20CC0075EE4A /* TimeZone.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = TimeZone.swift; sourceTree = "<group>"; };
B56965191B30888A0075EE4A /* FetchingResultsViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = FetchingResultsViewController.swift; sourceTree = "<group>"; };
B569651B1B30889A0075EE4A /* QueryingResultsViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = QueryingResultsViewController.swift; sourceTree = "<group>"; };
B56965281B3582D30075EE4A /* MigrationDemo.xcdatamodel */ = {isa = PBXFileReference; lastKnownFileType = wrapper.xcdatamodel; path = MigrationDemo.xcdatamodel; sourceTree = "<group>"; };
B5BDC9211C202429008147CD /* CoreStore.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; path = CoreStore.framework; sourceTree = BUILT_PRODUCTS_DIR; };
B5BDC9241C202429008147CD /* GCDKit.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; path = GCDKit.framework; sourceTree = BUILT_PRODUCTS_DIR; };
B5E599311B5240F50084BD5F /* OrganismTableViewCell.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = OrganismTableViewCell.swift; path = "CoreStoreDemo/MIgrations Demo/OrganismTableViewCell.swift"; sourceTree = SOURCE_ROOT; };
B5EE25801B36E1B00000406B /* MigrationDemoV2.xcdatamodel */ = {isa = PBXFileReference; lastKnownFileType = wrapper.xcdatamodel; path = MigrationDemoV2.xcdatamodel; sourceTree = "<group>"; };
B5EE25841B36E23C0000406B /* OrganismV1.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = OrganismV1.swift; sourceTree = "<group>"; };
B5EE25861B36E2520000406B /* OrganismV2.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = OrganismV2.swift; sourceTree = "<group>"; };
B5EE25881B36E2750000406B /* MigrationDemoV3.xcdatamodel */ = {isa = PBXFileReference; lastKnownFileType = wrapper.xcdatamodel; path = MigrationDemoV3.xcdatamodel; sourceTree = "<group>"; };
B5EE258B1B36E40D0000406B /* MigrationsDemoViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = MigrationsDemoViewController.swift; sourceTree = "<group>"; };
B5EE259A1B3EA4890000406B /* OrganismV3.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = OrganismV3.swift; sourceTree = "<group>"; };
B5EE259D1B3EC1B20000406B /* OrganismProtocol.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = OrganismProtocol.swift; sourceTree = "<group>"; };
/* End PBXFileReference section */
/* Begin PBXFrameworksBuildPhase section */
B54AAD461AF4D26E00848AE0 /* Frameworks */ = {
isa = PBXFrameworksBuildPhase;
buildActionMask = 2147483647;
files = (
B5E89ACD1C52929C003B04A9 /* GCDKit.framework in Frameworks */,
B5E89AD01C5292A2003B04A9 /* CoreStore.framework in Frameworks */,
B52977E11B120F8A003D50A5 /* CoreLocation.framework in Frameworks */,
B52977DF1B120F83003D50A5 /* MapKit.framework in Frameworks */,
);
runOnlyForDeploymentPostprocessing = 0;
};
/* End PBXFrameworksBuildPhase section */
/* Begin PBXGroup section */
B503FADA1AFDC71700F90881 /* List and Object Observers Demo */ = {
isa = PBXGroup;
children = (
B52977D81B120B80003D50A5 /* ObserversViewController.swift */,
B503FADB1AFDC71700F90881 /* ListObserverDemoViewController.swift */,
B503FADC1AFDC71700F90881 /* ObjectObserverDemoViewController.swift */,
B503FADD1AFDC71700F90881 /* Palette.swift */,
B503FADE1AFDC71700F90881 /* PaletteTableViewCell.swift */,
);
path = "List and Object Observers Demo";
sourceTree = "<group>";
};
B52977DB1B120F2C003D50A5 /* Transactions Demo */ = {
isa = PBXGroup;
children = (
B52977E31B121635003D50A5 /* Place.swift */,
B52977DC1B120F3B003D50A5 /* TransactionsDemoViewController.swift */,
);
path = "Transactions Demo";
sourceTree = "<group>";
};
B52977E21B120F90003D50A5 /* Frameworks */ = {
isa = PBXGroup;
children = (
B52977E01B120F8A003D50A5 /* CoreLocation.framework */,
B5BDC9211C202429008147CD /* CoreStore.framework */,
B5BDC9241C202429008147CD /* GCDKit.framework */,
B52977DE1B120F83003D50A5 /* MapKit.framework */,
);
name = Frameworks;
sourceTree = "<group>";
};
B54AAD401AF4D26E00848AE0 = {
isa = PBXGroup;
children = (
B52977E21B120F90003D50A5 /* Frameworks */,
B54AAD4B1AF4D26E00848AE0 /* CoreStoreDemo */,
B54AAD4A1AF4D26E00848AE0 /* Products */,
);
sourceTree = "<group>";
};
B54AAD4A1AF4D26E00848AE0 /* Products */ = {
isa = PBXGroup;
children = (
B54AAD491AF4D26E00848AE0 /* CoreStoreDemo.app */,
);
name = Products;
sourceTree = "<group>";
};
B54AAD4B1AF4D26E00848AE0 /* CoreStoreDemo */ = {
isa = PBXGroup;
children = (
B54AAD4E1AF4D26E00848AE0 /* AppDelegate.swift */,
B566E3271B117AE700F4F0C6 /* Stack Setup Demo */,
B503FADA1AFDC71700F90881 /* List and Object Observers Demo */,
B52977DB1B120F2C003D50A5 /* Transactions Demo */,
B56965091B2B35370075EE4A /* Fetching and Querying Demo */,
B569652F1B3591460075EE4A /* Migrations Demo */,
B56964C61B20AC200075EE4A /* Loggers Demo */,
B54AAD571AF4D26E00848AE0 /* Main.storyboard */,
B54AAD5A1AF4D26E00848AE0 /* Images.xcassets */,
B54AAD5C1AF4D26E00848AE0 /* LaunchScreen.xib */,
B54AAD501AF4D26E00848AE0 /* CoreStoreDemo.xcdatamodeld */,
B56964D51B231AE90075EE4A /* StackSetupDemo.xcdatamodeld */,
B56965271B3582D30075EE4A /* MigrationDemo.xcdatamodeld */,
B54AAD4C1AF4D26E00848AE0 /* Supporting Files */,
);
path = CoreStoreDemo;
sourceTree = "<group>";
};
B54AAD4C1AF4D26E00848AE0 /* Supporting Files */ = {
isa = PBXGroup;
children = (
B54AAD4D1AF4D26E00848AE0 /* Info.plist */,
);
name = "Supporting Files";
sourceTree = "<group>";
};
B566E3271B117AE700F4F0C6 /* Stack Setup Demo */ = {
isa = PBXGroup;
children = (
B56964DB1B231BCB0075EE4A /* FemaleAccount.swift */,
B56964D91B231BCA0075EE4A /* MaleAccount.swift */,
B566E3311B11DF3200F4F0C6 /* UserAccount.swift */,
B566E3291B117B1F00F4F0C6 /* StackSetupDemoViewController.swift */,
);
path = "Stack Setup Demo";
sourceTree = "<group>";
};
B56964C61B20AC200075EE4A /* Loggers Demo */ = {
isa = PBXGroup;
children = (
B56964C81B20AC780075EE4A /* CustomLoggerViewController.swift */,
);
path = "Loggers Demo";
sourceTree = "<group>";
};
B56965091B2B35370075EE4A /* Fetching and Querying Demo */ = {
isa = PBXGroup;
children = (
B56965171B2E20CC0075EE4A /* TimeZone.swift */,
B569650B1B2B36E10075EE4A /* FetchingAndQueryingDemoViewController.swift */,
B56965191B30888A0075EE4A /* FetchingResultsViewController.swift */,
B569651B1B30889A0075EE4A /* QueryingResultsViewController.swift */,
);
path = "Fetching and Querying Demo";
sourceTree = "<group>";
};
B569652F1B3591460075EE4A /* Migrations Demo */ = {
isa = PBXGroup;
children = (
B5EE259D1B3EC1B20000406B /* OrganismProtocol.swift */,
B5EE259A1B3EA4890000406B /* OrganismV3.swift */,
B5EE25861B36E2520000406B /* OrganismV2.swift */,
B5EE25841B36E23C0000406B /* OrganismV1.swift */,
B5EE258B1B36E40D0000406B /* MigrationsDemoViewController.swift */,
B5E599311B5240F50084BD5F /* OrganismTableViewCell.swift */,
B5125C111B521B78003A42C7 /* OrganismV2ToV3.xcmappingmodel */,
B560070E1B3EC90F00A9A8F9 /* OrganismV2ToV3MigrationPolicy.swift */,
B5125C131B521BA7003A42C7 /* OrganismV3ToV2.xcmappingmodel */,
);
path = "Migrations Demo";
sourceTree = "<group>";
};
/* End PBXGroup section */
/* Begin PBXNativeTarget section */
B54AAD481AF4D26E00848AE0 /* CoreStoreDemo */ = {
isa = PBXNativeTarget;
buildConfigurationList = B54AAD6D1AF4D26E00848AE0 /* Build configuration list for PBXNativeTarget "CoreStoreDemo" */;
buildPhases = (
B54AAD451AF4D26E00848AE0 /* Sources */,
B54AAD461AF4D26E00848AE0 /* Frameworks */,
B54AAD471AF4D26E00848AE0 /* Resources */,
B5E89ACF1C52929C003B04A9 /* Embed Frameworks */,
);
buildRules = (
);
dependencies = (
);
name = CoreStoreDemo;
productName = CoreStoreDemo;
productReference = B54AAD491AF4D26E00848AE0 /* CoreStoreDemo.app */;
productType = "com.apple.product-type.application";
};
/* End PBXNativeTarget section */
/* Begin PBXProject section */
B54AAD411AF4D26E00848AE0 /* Project object */ = {
isa = PBXProject;
attributes = {
LastSwiftUpdateCheck = 0700;
LastUpgradeCheck = 0700;
ORGANIZATIONNAME = "John Rommel Estropia";
TargetAttributes = {
B54AAD481AF4D26E00848AE0 = {
CreatedOnToolsVersion = 6.3;
};
};
};
buildConfigurationList = B54AAD441AF4D26E00848AE0 /* Build configuration list for PBXProject "CoreStoreDemo" */;
compatibilityVersion = "Xcode 3.2";
developmentRegion = English;
hasScannedForEncodings = 0;
knownRegions = (
en,
Base,
);
mainGroup = B54AAD401AF4D26E00848AE0;
productRefGroup = B54AAD4A1AF4D26E00848AE0 /* Products */;
projectDirPath = "";
projectRoot = "";
targets = (
B54AAD481AF4D26E00848AE0 /* CoreStoreDemo */,
);
};
/* End PBXProject section */
/* Begin PBXResourcesBuildPhase section */
B54AAD471AF4D26E00848AE0 /* Resources */ = {
isa = PBXResourcesBuildPhase;
buildActionMask = 2147483647;
files = (
B54AAD591AF4D26E00848AE0 /* Main.storyboard in Resources */,
B54AAD5E1AF4D26E00848AE0 /* LaunchScreen.xib in Resources */,
B54AAD5B1AF4D26E00848AE0 /* Images.xcassets in Resources */,
);
runOnlyForDeploymentPostprocessing = 0;
};
/* End PBXResourcesBuildPhase section */
/* Begin PBXSourcesBuildPhase section */
B54AAD451AF4D26E00848AE0 /* Sources */ = {
isa = PBXSourcesBuildPhase;
buildActionMask = 2147483647;
files = (
B56965181B2E20CC0075EE4A /* TimeZone.swift in Sources */,
B56965291B3582D30075EE4A /* MigrationDemo.xcdatamodeld in Sources */,
B5E599321B5240F50084BD5F /* OrganismTableViewCell.swift in Sources */,
B5EE25851B36E23C0000406B /* OrganismV1.swift in Sources */,
B52977DD1B120F3B003D50A5 /* TransactionsDemoViewController.swift in Sources */,
B52977E41B121635003D50A5 /* Place.swift in Sources */,
B569650C1B2B36E10075EE4A /* FetchingAndQueryingDemoViewController.swift in Sources */,
B569651A1B30888A0075EE4A /* FetchingResultsViewController.swift in Sources */,
B5EE25871B36E2520000406B /* OrganismV2.swift in Sources */,
B503FAE01AFDC71700F90881 /* ObjectObserverDemoViewController.swift in Sources */,
B52977D91B120B80003D50A5 /* ObserversViewController.swift in Sources */,
B56964C91B20AC780075EE4A /* CustomLoggerViewController.swift in Sources */,
B566E32A1B117B1F00F4F0C6 /* StackSetupDemoViewController.swift in Sources */,
B56964DA1B231BCA0075EE4A /* MaleAccount.swift in Sources */,
B566E3321B11DF3200F4F0C6 /* UserAccount.swift in Sources */,
B54AAD521AF4D26E00848AE0 /* CoreStoreDemo.xcdatamodeld in Sources */,
B5EE259B1B3EA4890000406B /* OrganismV3.swift in Sources */,
B503FAE11AFDC71700F90881 /* Palette.swift in Sources */,
B503FAE21AFDC71700F90881 /* PaletteTableViewCell.swift in Sources */,
B560070F1B3EC90F00A9A8F9 /* OrganismV2ToV3MigrationPolicy.swift in Sources */,
B5125C141B521BA7003A42C7 /* OrganismV3ToV2.xcmappingmodel in Sources */,
B503FADF1AFDC71700F90881 /* ListObserverDemoViewController.swift in Sources */,
B54AAD4F1AF4D26E00848AE0 /* AppDelegate.swift in Sources */,
B56964D71B231AE90075EE4A /* StackSetupDemo.xcdatamodeld in Sources */,
B56964DC1B231BCB0075EE4A /* FemaleAccount.swift in Sources */,
B5EE259E1B3EC1B20000406B /* OrganismProtocol.swift in Sources */,
B5EE258C1B36E40D0000406B /* MigrationsDemoViewController.swift in Sources */,
B569651C1B30889A0075EE4A /* QueryingResultsViewController.swift in Sources */,
B5125C121B521B78003A42C7 /* OrganismV2ToV3.xcmappingmodel in Sources */,
);
runOnlyForDeploymentPostprocessing = 0;
};
/* End PBXSourcesBuildPhase section */
/* Begin PBXVariantGroup section */
B54AAD571AF4D26E00848AE0 /* Main.storyboard */ = {
isa = PBXVariantGroup;
children = (
B54AAD581AF4D26E00848AE0 /* Base */,
);
name = Main.storyboard;
sourceTree = "<group>";
};
B54AAD5C1AF4D26E00848AE0 /* LaunchScreen.xib */ = {
isa = PBXVariantGroup;
children = (
B54AAD5D1AF4D26E00848AE0 /* Base */,
);
name = LaunchScreen.xib;
sourceTree = "<group>";
};
/* End PBXVariantGroup section */
/* Begin XCBuildConfiguration section */
B54AAD6B1AF4D26E00848AE0 /* Debug */ = {
isa = XCBuildConfiguration;
buildSettings = {
ALWAYS_SEARCH_USER_PATHS = NO;
CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x";
CLANG_CXX_LIBRARY = "libc++";
CLANG_ENABLE_MODULES = YES;
CLANG_ENABLE_OBJC_ARC = YES;
CLANG_WARN_BOOL_CONVERSION = YES;
CLANG_WARN_CONSTANT_CONVERSION = YES;
CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
CLANG_WARN_EMPTY_BODY = YES;
CLANG_WARN_ENUM_CONVERSION = YES;
CLANG_WARN_INT_CONVERSION = YES;
CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
CLANG_WARN_UNREACHABLE_CODE = YES;
CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
"CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer";
COPY_PHASE_STRIP = NO;
DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
ENABLE_STRICT_OBJC_MSGSEND = YES;
ENABLE_TESTABILITY = YES;
GCC_C_LANGUAGE_STANDARD = gnu99;
GCC_DYNAMIC_NO_PIC = NO;
GCC_NO_COMMON_BLOCKS = YES;
GCC_OPTIMIZATION_LEVEL = 0;
GCC_PREPROCESSOR_DEFINITIONS = (
"DEBUG=1",
"$(inherited)",
);
GCC_SYMBOLS_PRIVATE_EXTERN = NO;
GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
GCC_WARN_UNDECLARED_SELECTOR = YES;
GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
GCC_WARN_UNUSED_FUNCTION = YES;
GCC_WARN_UNUSED_VARIABLE = YES;
IPHONEOS_DEPLOYMENT_TARGET = 8.0;
MTL_ENABLE_DEBUG_INFO = YES;
ONLY_ACTIVE_ARCH = YES;
SDKROOT = iphoneos;
SWIFT_OPTIMIZATION_LEVEL = "-Onone";
};
name = Debug;
};
B54AAD6C1AF4D26E00848AE0 /* Release */ = {
isa = XCBuildConfiguration;
buildSettings = {
ALWAYS_SEARCH_USER_PATHS = NO;
CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x";
CLANG_CXX_LIBRARY = "libc++";
CLANG_ENABLE_MODULES = YES;
CLANG_ENABLE_OBJC_ARC = YES;
CLANG_WARN_BOOL_CONVERSION = YES;
CLANG_WARN_CONSTANT_CONVERSION = YES;
CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
CLANG_WARN_EMPTY_BODY = YES;
CLANG_WARN_ENUM_CONVERSION = YES;
CLANG_WARN_INT_CONVERSION = YES;
CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
CLANG_WARN_UNREACHABLE_CODE = YES;
CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
"CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer";
COPY_PHASE_STRIP = NO;
DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
ENABLE_NS_ASSERTIONS = NO;
ENABLE_STRICT_OBJC_MSGSEND = YES;
GCC_C_LANGUAGE_STANDARD = gnu99;
GCC_NO_COMMON_BLOCKS = YES;
GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
GCC_WARN_UNDECLARED_SELECTOR = YES;
GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
GCC_WARN_UNUSED_FUNCTION = YES;
GCC_WARN_UNUSED_VARIABLE = YES;
IPHONEOS_DEPLOYMENT_TARGET = 8.0;
MTL_ENABLE_DEBUG_INFO = NO;
SDKROOT = iphoneos;
VALIDATE_PRODUCT = YES;
};
name = Release;
};
B54AAD6E1AF4D26E00848AE0 /* Debug */ = {
isa = XCBuildConfiguration;
buildSettings = {
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
INFOPLIST_FILE = CoreStoreDemo/Info.plist;
IPHONEOS_DEPLOYMENT_TARGET = 8.0;
LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks";
PRODUCT_BUNDLE_IDENTIFIER = com.johnestropia.corestore.demo;
PRODUCT_NAME = "$(TARGET_NAME)";
};
name = Debug;
};
B54AAD6F1AF4D26E00848AE0 /* Release */ = {
isa = XCBuildConfiguration;
buildSettings = {
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
INFOPLIST_FILE = CoreStoreDemo/Info.plist;
IPHONEOS_DEPLOYMENT_TARGET = 8.0;
LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks";
PRODUCT_BUNDLE_IDENTIFIER = com.johnestropia.corestore.demo;
PRODUCT_NAME = "$(TARGET_NAME)";
};
name = Release;
};
/* End XCBuildConfiguration section */
/* Begin XCConfigurationList section */
B54AAD441AF4D26E00848AE0 /* Build configuration list for PBXProject "CoreStoreDemo" */ = {
isa = XCConfigurationList;
buildConfigurations = (
B54AAD6B1AF4D26E00848AE0 /* Debug */,
B54AAD6C1AF4D26E00848AE0 /* Release */,
);
defaultConfigurationIsVisible = 0;
defaultConfigurationName = Release;
};
B54AAD6D1AF4D26E00848AE0 /* Build configuration list for PBXNativeTarget "CoreStoreDemo" */ = {
isa = XCConfigurationList;
buildConfigurations = (
B54AAD6E1AF4D26E00848AE0 /* Debug */,
B54AAD6F1AF4D26E00848AE0 /* Release */,
);
defaultConfigurationIsVisible = 0;
defaultConfigurationName = Release;
};
/* End XCConfigurationList section */
/* Begin XCVersionGroup section */
B54AAD501AF4D26E00848AE0 /* CoreStoreDemo.xcdatamodeld */ = {
isa = XCVersionGroup;
children = (
B54AAD511AF4D26E00848AE0 /* CoreStoreDemo.xcdatamodel */,
);
currentVersion = B54AAD511AF4D26E00848AE0 /* CoreStoreDemo.xcdatamodel */;
path = CoreStoreDemo.xcdatamodeld;
sourceTree = "<group>";
versionGroupType = wrapper.xcdatamodel;
};
B56964D51B231AE90075EE4A /* StackSetupDemo.xcdatamodeld */ = {
isa = XCVersionGroup;
children = (
B56964D61B231AE90075EE4A /* StackSetupDemo.xcdatamodel */,
);
currentVersion = B56964D61B231AE90075EE4A /* StackSetupDemo.xcdatamodel */;
path = StackSetupDemo.xcdatamodeld;
sourceTree = "<group>";
versionGroupType = wrapper.xcdatamodel;
};
B56965271B3582D30075EE4A /* MigrationDemo.xcdatamodeld */ = {
isa = XCVersionGroup;
children = (
B5EE25881B36E2750000406B /* MigrationDemoV3.xcdatamodel */,
B5EE25801B36E1B00000406B /* MigrationDemoV2.xcdatamodel */,
B56965281B3582D30075EE4A /* MigrationDemo.xcdatamodel */,
);
currentVersion = B5EE25881B36E2750000406B /* MigrationDemoV3.xcdatamodel */;
path = MigrationDemo.xcdatamodeld;
sourceTree = "<group>";
versionGroupType = wrapper.xcdatamodel;
};
/* End XCVersionGroup section */
};
rootObject = B54AAD411AF4D26E00848AE0 /* Project object */;
}

View File

@@ -2,6 +2,6 @@
<Workspace
version = "1.0">
<FileRef
location = "self:">
location = "self:CoreStoreDemo.xcodeproj">
</FileRef>
</Workspace>

View File

@@ -0,0 +1,53 @@
<?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>IDESourceControlProjectFavoriteDictionaryKey</key>
<false/>
<key>IDESourceControlProjectIdentifier</key>
<string>B6855E48-4B19-4321-B1C7-CB2706E12777</string>
<key>IDESourceControlProjectName</key>
<string>CoreStoreDemo</string>
<key>IDESourceControlProjectOriginsDictionary</key>
<dict>
<key>4B60F1BCB491FF717C56441AE7783C74F417BE48</key>
<string>github.com:JohnEstropia/CoreStore.git</string>
<key>8B2E522D57154DFA93A06982C36315ECBEA4FA97</key>
<string>github.com:JohnEstropia/GCDKit.git</string>
</dict>
<key>IDESourceControlProjectPath</key>
<string>CoreStoreDemo/CoreStoreDemo.xcodeproj</string>
<key>IDESourceControlProjectRelativeInstallPathDictionary</key>
<dict>
<key>4B60F1BCB491FF717C56441AE7783C74F417BE48</key>
<string>../../..</string>
<key>8B2E522D57154DFA93A06982C36315ECBEA4FA97</key>
<string>../../..Libraries/GCDKit</string>
</dict>
<key>IDESourceControlProjectURL</key>
<string>github.com:JohnEstropia/CoreStore.git</string>
<key>IDESourceControlProjectVersion</key>
<integer>111</integer>
<key>IDESourceControlProjectWCCIdentifier</key>
<string>4B60F1BCB491FF717C56441AE7783C74F417BE48</string>
<key>IDESourceControlProjectWCConfigurations</key>
<array>
<dict>
<key>IDESourceControlRepositoryExtensionIdentifierKey</key>
<string>public.vcs.git</string>
<key>IDESourceControlWCCIdentifierKey</key>
<string>4B60F1BCB491FF717C56441AE7783C74F417BE48</string>
<key>IDESourceControlWCCName</key>
<string>CoreStore</string>
</dict>
<dict>
<key>IDESourceControlRepositoryExtensionIdentifierKey</key>
<string>public.vcs.git</string>
<key>IDESourceControlWCCIdentifierKey</key>
<string>8B2E522D57154DFA93A06982C36315ECBEA4FA97</string>
<key>IDESourceControlWCCName</key>
<string>GCDKit</string>
</dict>
</array>
</dict>
</plist>

View File

@@ -0,0 +1,30 @@
{
"DVTSourceControlWorkspaceBlueprintPrimaryRemoteRepositoryKey" : "4B60F1BCB491FF717C56441AE7783C74F417BE48",
"DVTSourceControlWorkspaceBlueprintWorkingCopyRepositoryLocationsKey" : {
},
"DVTSourceControlWorkspaceBlueprintWorkingCopyStatesKey" : {
"8B2E522D57154DFA93A06982C36315ECBEA4FA97" : 0,
"4B60F1BCB491FF717C56441AE7783C74F417BE48" : 0
},
"DVTSourceControlWorkspaceBlueprintIdentifierKey" : "B6855E48-4B19-4321-B1C7-CB2706E12777",
"DVTSourceControlWorkspaceBlueprintWorkingCopyPathsKey" : {
"8B2E522D57154DFA93A06982C36315ECBEA4FA97" : "CoreStoreLibraries\/GCDKit",
"4B60F1BCB491FF717C56441AE7783C74F417BE48" : "CoreStore"
},
"DVTSourceControlWorkspaceBlueprintNameKey" : "CoreStoreDemo",
"DVTSourceControlWorkspaceBlueprintVersion" : 203,
"DVTSourceControlWorkspaceBlueprintRelativePathToProjectKey" : "CoreStoreDemo\/CoreStoreDemo.xcodeproj",
"DVTSourceControlWorkspaceBlueprintRemoteRepositoriesKey" : [
{
"DVTSourceControlWorkspaceBlueprintRemoteRepositoryURLKey" : "github.com:JohnEstropia\/CoreStore.git",
"DVTSourceControlWorkspaceBlueprintRemoteRepositorySystemKey" : "com.apple.dt.Xcode.sourcecontrol.Git",
"DVTSourceControlWorkspaceBlueprintRemoteRepositoryIdentifierKey" : "4B60F1BCB491FF717C56441AE7783C74F417BE48"
},
{
"DVTSourceControlWorkspaceBlueprintRemoteRepositoryURLKey" : "github.com:JohnEstropia\/GCDKit.git",
"DVTSourceControlWorkspaceBlueprintRemoteRepositorySystemKey" : "com.apple.dt.Xcode.sourcecontrol.Git",
"DVTSourceControlWorkspaceBlueprintRemoteRepositoryIdentifierKey" : "8B2E522D57154DFA93A06982C36315ECBEA4FA97"
}
]
}

View File

@@ -0,0 +1,53 @@
<?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>IDESourceControlProjectFavoriteDictionaryKey</key>
<false/>
<key>IDESourceControlProjectIdentifier</key>
<string>7C5E31AC-5DD0-43DA-A5C6-AF73B4532D86</string>
<key>IDESourceControlProjectName</key>
<string>project</string>
<key>IDESourceControlProjectOriginsDictionary</key>
<dict>
<key>4B60F1BCB491FF717C56441AE7783C74F417BE48</key>
<string>github.com:JohnEstropia/HardcoreData.git</string>
<key>8B2E522D57154DFA93A06982C36315ECBEA4FA97</key>
<string>github.com:JohnEstropia/GCDKit.git</string>
</dict>
<key>IDESourceControlProjectPath</key>
<string>HardcoreDataDemo/HardcoreDataDemo.xcodeproj/project.xcworkspace</string>
<key>IDESourceControlProjectRelativeInstallPathDictionary</key>
<dict>
<key>4B60F1BCB491FF717C56441AE7783C74F417BE48</key>
<string>../../..</string>
<key>8B2E522D57154DFA93A06982C36315ECBEA4FA97</key>
<string>../../..Libraries/GCDKit</string>
</dict>
<key>IDESourceControlProjectURL</key>
<string>github.com:JohnEstropia/HardcoreData.git</string>
<key>IDESourceControlProjectVersion</key>
<integer>111</integer>
<key>IDESourceControlProjectWCCIdentifier</key>
<string>4B60F1BCB491FF717C56441AE7783C74F417BE48</string>
<key>IDESourceControlProjectWCConfigurations</key>
<array>
<dict>
<key>IDESourceControlRepositoryExtensionIdentifierKey</key>
<string>public.vcs.git</string>
<key>IDESourceControlWCCIdentifierKey</key>
<string>8B2E522D57154DFA93A06982C36315ECBEA4FA97</string>
<key>IDESourceControlWCCName</key>
<string>GCDKit</string>
</dict>
<dict>
<key>IDESourceControlRepositoryExtensionIdentifierKey</key>
<string>public.vcs.git</string>
<key>IDESourceControlWCCIdentifierKey</key>
<string>4B60F1BCB491FF717C56441AE7783C74F417BE48</string>
<key>IDESourceControlWCCName</key>
<string>HardcoreData</string>
</dict>
</array>
</dict>
</plist>

View File

@@ -2,7 +2,9 @@
<!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>
<key>HasAskedToTakeAutomaticSnapshotBeforeSignificantChanges</key>
<true/>
<key>SnapshotAutomaticallyBeforeSignificantChanges</key>
<true/>
</dict>
</plist>

View File

@@ -0,0 +1,28 @@
//
// AppDelegate.swift
// CoreStoreDemo
//
// Created by John Rommel Estropia on 2015/05/02.
// Copyright © 2015 John Rommel Estropia. All rights reserved.
//
import UIKit
// MARK: - AppDelegate
@UIApplicationMain
class AppDelegate: UIResponder, UIApplicationDelegate {
// MARK: UIApplicationDelegate
var window: UIWindow?
func application(application: UIApplication, didFinishLaunchingWithOptions launchOptions: [NSObject: AnyObject]?) -> Bool {
application.statusBarStyle = .LightContent
return true
}
}

View File

@@ -0,0 +1,50 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<document type="com.apple.InterfaceBuilder3.CocoaTouch.XIB" version="3.0" toolsVersion="10112" systemVersion="15D21" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" launchScreen="YES" useTraitCollections="YES">
<dependencies>
<deployment identifier="iOS"/>
<plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="10083"/>
<capability name="Constraints with non-1.0 multipliers" minToolsVersion="5.1"/>
</dependencies>
<objects>
<placeholder placeholderIdentifier="IBFilesOwner" id="-1" userLabel="File's Owner"/>
<placeholder placeholderIdentifier="IBFirstResponder" id="-2" customClass="UIResponder"/>
<view contentMode="scaleToFill" id="iN0-l3-epB">
<rect key="frame" x="0.0" y="0.0" width="480" height="480"/>
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
<subviews>
<label opaque="NO" clipsSubviews="YES" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text=" Copyright © 2015 John Rommel Estropia. All rights reserved." textAlignment="center" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" minimumFontSize="9" translatesAutoresizingMaskIntoConstraints="NO" id="8ie-xW-0ye">
<rect key="frame" x="20" y="439" width="441" height="21"/>
<fontDescription key="fontDescription" type="system" pointSize="17"/>
<color key="textColor" red="0.92549019607843142" green="0.94117647058823528" blue="0.94509803921568625" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
<nil key="highlightedColor"/>
</label>
<imageView userInteractionEnabled="NO" contentMode="center" horizontalHuggingPriority="251" verticalHuggingPriority="251" image="CoreStoreIcon" translatesAutoresizingMaskIntoConstraints="NO" id="q8C-V6-gXH">
<rect key="frame" x="155" y="83" width="170" height="170"/>
</imageView>
<label opaque="NO" clipsSubviews="YES" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="CoreStore" textAlignment="center" lineBreakMode="middleTruncation" baselineAdjustment="alignBaselines" minimumFontSize="18" translatesAutoresizingMaskIntoConstraints="NO" id="kId-c2-rCX">
<rect key="frame" x="20" y="273" width="440" height="57.5"/>
<fontDescription key="fontDescription" name="HelveticaNeue-UltraLight" family="Helvetica Neue" pointSize="50"/>
<color key="textColor" red="0.92549019607843142" green="0.94117647058823528" blue="0.94509803921568625" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
<nil key="highlightedColor"/>
</label>
</subviews>
<color key="backgroundColor" red="0.20392156862745098" green="0.28627450980392155" blue="0.36862745098039218" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
<constraints>
<constraint firstAttribute="centerX" secondItem="kId-c2-rCX" secondAttribute="centerX" id="Koa-jz-hwk"/>
<constraint firstAttribute="bottom" secondItem="8ie-xW-0ye" secondAttribute="bottom" constant="20" id="Kzo-t9-V3l"/>
<constraint firstItem="8ie-xW-0ye" firstAttribute="leading" secondItem="iN0-l3-epB" secondAttribute="leading" constant="20" symbolic="YES" id="MfP-vx-nX0"/>
<constraint firstItem="q8C-V6-gXH" firstAttribute="centerY" secondItem="iN0-l3-epB" secondAttribute="centerY" multiplier="0.7" id="QW6-8Y-w15"/>
<constraint firstAttribute="centerX" secondItem="8ie-xW-0ye" secondAttribute="centerX" id="ZEH-qu-HZ9"/>
<constraint firstItem="q8C-V6-gXH" firstAttribute="centerX" secondItem="iN0-l3-epB" secondAttribute="centerX" id="fRb-1V-9iD"/>
<constraint firstItem="kId-c2-rCX" firstAttribute="leading" secondItem="iN0-l3-epB" secondAttribute="leading" constant="20" symbolic="YES" id="fvb-Df-36g"/>
<constraint firstItem="kId-c2-rCX" firstAttribute="top" secondItem="q8C-V6-gXH" secondAttribute="bottom" constant="20" id="s63-MP-ush"/>
</constraints>
<nil key="simulatedStatusBarMetrics"/>
<freeformSimulatedSizeMetrics key="simulatedDestinationMetrics"/>
<point key="canvasLocation" x="548" y="455"/>
</view>
</objects>
<resources>
<image name="CoreStoreIcon" width="170" height="170"/>
</resources>
</document>

View File

@@ -0,0 +1,53 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<<<<<<< Updated upstream
<document type="com.apple.InterfaceBuilder3.CocoaTouch.XIB" version="3.0" toolsVersion="9531" systemVersion="15C50" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" launchScreen="YES" useTraitCollections="YES">
<dependencies>
<plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="9529"/>
=======
<document type="com.apple.InterfaceBuilder3.CocoaTouch.XIB" version="3.0" toolsVersion="9532" systemVersion="15D21" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" launchScreen="YES" useTraitCollections="YES">
<dependencies>
<deployment identifier="iOS"/>
<plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="9530"/>
>>>>>>> Stashed changes
<capability name="Constraints with non-1.0 multipliers" minToolsVersion="5.1"/>
</dependencies>
<objects>
<placeholder placeholderIdentifier="IBFilesOwner" id="-1" userLabel="File's Owner"/>
<placeholder placeholderIdentifier="IBFirstResponder" id="-2" customClass="UIResponder"/>
<view contentMode="scaleToFill" id="iN0-l3-epB">
<rect key="frame" x="0.0" y="0.0" width="480" height="480"/>
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
<subviews>
<<<<<<< Updated upstream
<label opaque="NO" clipsSubviews="YES" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text=" Copyright © 2015 John Rommel Estropia. All rights reserved." textAlignment="center" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" minimumFontSize="9" translatesAutoresizingMaskIntoConstraints="NO" id="8ie-xW-0ye">
<rect key="frame" x="20" y="439" width="441" height="21"/>
=======
<label opaque="NO" clipsSubviews="YES" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text=" Copyright (c) 2015 John Rommel Estropia. All rights reserved." textAlignment="center" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" minimumFontSize="9" translatesAutoresizingMaskIntoConstraints="NO" id="8ie-xW-0ye">
<rect key="frame" x="20" y="439.5" width="441" height="20.5"/>
>>>>>>> Stashed changes
<fontDescription key="fontDescription" type="system" pointSize="17"/>
<color key="textColor" red="0.92549019607843142" green="0.94117647058823528" blue="0.94509803921568625" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
<nil key="highlightedColor"/>
</label>
<label opaque="NO" clipsSubviews="YES" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="CoreStore" textAlignment="center" lineBreakMode="middleTruncation" baselineAdjustment="alignBaselines" minimumFontSize="18" translatesAutoresizingMaskIntoConstraints="NO" id="kId-c2-rCX">
<rect key="frame" x="20" y="133" width="441" height="57.5"/>
<fontDescription key="fontDescription" name="HelveticaNeue-UltraLight" family="Helvetica Neue" pointSize="50"/>
<color key="textColor" red="0.92549019607843142" green="0.94117647058823528" blue="0.94509803921568625" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
<nil key="highlightedColor"/>
</label>
</subviews>
<color key="backgroundColor" red="0.20392156862745098" green="0.28627450980392155" blue="0.36862745098039218" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
<constraints>
<constraint firstItem="kId-c2-rCX" firstAttribute="centerY" secondItem="iN0-l3-epB" secondAttribute="bottom" multiplier="1/3" constant="1" id="5cJ-9S-tgC"/>
<constraint firstAttribute="centerX" secondItem="kId-c2-rCX" secondAttribute="centerX" id="Koa-jz-hwk"/>
<constraint firstAttribute="bottom" secondItem="8ie-xW-0ye" secondAttribute="bottom" constant="20" id="Kzo-t9-V3l"/>
<constraint firstItem="8ie-xW-0ye" firstAttribute="leading" secondItem="iN0-l3-epB" secondAttribute="leading" constant="20" symbolic="YES" id="MfP-vx-nX0"/>
<constraint firstAttribute="centerX" secondItem="8ie-xW-0ye" secondAttribute="centerX" id="ZEH-qu-HZ9"/>
<constraint firstItem="kId-c2-rCX" firstAttribute="leading" secondItem="iN0-l3-epB" secondAttribute="leading" constant="20" symbolic="YES" id="fvb-Df-36g"/>
</constraints>
<nil key="simulatedStatusBarMetrics"/>
<freeformSimulatedSizeMetrics key="simulatedDestinationMetrics"/>
<point key="canvasLocation" x="548" y="455"/>
</view>
</objects>
</document>

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,37 @@
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<model userDefinedModelVersionIdentifier="" type="com.apple.IDECoreDataModeler.DataModel" documentVersion="1.0" lastSavedToolsVersion="10169.1" systemVersion="15D21" minimumToolsVersion="Automatic">
<entity name="Palette" representedClassName="CoreStoreDemo.Palette">
<attribute name="brightness" optional="YES" attributeType="Float" defaultValueString="0.0" syncable="YES"/>
<attribute name="colorName" optional="YES" transient="YES" attributeType="String" syncable="YES"/>
<attribute name="hue" optional="YES" attributeType="Integer 32" defaultValueString="0.0" syncable="YES"/>
<attribute name="saturation" optional="YES" attributeType="Float" defaultValueString="0.0" syncable="YES"/>
<userInfo/>
</entity>
<entity name="Place" representedClassName="CoreStoreDemo.Place" syncable="YES">
<attribute name="latitude" optional="YES" attributeType="Double" defaultValueString="0.0" syncable="YES"/>
<attribute name="longitude" optional="YES" attributeType="Double" defaultValueString="0.0" syncable="YES"/>
<attribute name="subtitle" optional="YES" attributeType="String" syncable="YES"/>
<attribute name="title" optional="YES" attributeType="String" syncable="YES"/>
</entity>
<entity name="TimeZone" representedClassName="CoreStoreDemo.TimeZone" syncable="YES">
<attribute name="abbreviation" optional="YES" attributeType="String" syncable="YES"/>
<attribute name="daylightSavingTimeOffset" optional="YES" attributeType="Double" defaultValueString="0.0" syncable="YES"/>
<attribute name="hasDaylightSavingTime" optional="YES" attributeType="Boolean" syncable="YES"/>
<attribute name="name" optional="YES" attributeType="String" syncable="YES"/>
<attribute name="secondsFromGMT" optional="YES" attributeType="Integer 32" defaultValueString="0.0" syncable="YES"/>
</entity>
<configuration name="FetchingAndQueryingDemo">
<memberEntity name="TimeZone"/>
</configuration>
<configuration name="ObservingDemo">
<memberEntity name="Palette"/>
</configuration>
<configuration name="TransactionsDemo">
<memberEntity name="Place"/>
</configuration>
<elements>
<element name="Palette" positionX="261" positionY="189" width="128" height="105"/>
<element name="Place" positionX="261" positionY="225" width="128" height="105"/>
<element name="TimeZone" positionX="297" positionY="270" width="128" height="120"/>
</elements>
</model>

View File

@@ -0,0 +1,293 @@
//
// FetchingAndQueryingDemoViewController.swift
// CoreStoreDemo
//
// Created by John Rommel Estropia on 2015/06/12.
// Copyright © 2015 John Rommel Estropia. All rights reserved.
//
import UIKit
import CoreStore
private struct Static {
static let timeZonesStack: DataStack = {
let dataStack = DataStack()
try! dataStack.addStorageAndWait(
SQLiteStore(
fileName: "TimeZoneDemo.sqlite",
configuration: "FetchingAndQueryingDemo",
localStorageOptions: .RecreateStoreOnModelMismatch
)
)
dataStack.beginSynchronous { (transaction) -> Void in
transaction.deleteAll(From(TimeZone))
for name in NSTimeZone.knownTimeZoneNames() {
let rawTimeZone = NSTimeZone(name: name)!
let cachedTimeZone = transaction.create(Into(TimeZone))
cachedTimeZone.name = rawTimeZone.name
cachedTimeZone.abbreviation = rawTimeZone.abbreviation ?? ""
cachedTimeZone.secondsFromGMT = Int32(rawTimeZone.secondsFromGMT)
cachedTimeZone.hasDaylightSavingTime = rawTimeZone.daylightSavingTime
cachedTimeZone.daylightSavingTimeOffset = rawTimeZone.daylightSavingTimeOffset
}
transaction.commitAndWait()
}
return dataStack
}()
}
// MARK: - FetchingAndQueryingDemoViewController
class FetchingAndQueryingDemoViewController: UIViewController, UITableViewDataSource, UITableViewDelegate {
// MARK: UIViewController
override func viewDidAppear(animated: Bool) {
super.viewDidAppear(animated)
if self.didAppearOnce {
return
}
self.didAppearOnce = true
let alert = UIAlertController(
title: "Fetch and Query Demo",
message: "This demo shows how to execute fetches and queries.\n\nEach menu item executes and displays a preconfigured fetch/query.",
preferredStyle: .Alert
)
alert.addAction(UIAlertAction(title: "OK", style: .Cancel, handler: nil))
self.presentViewController(alert, animated: true, completion: nil)
}
override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) {
super.prepareForSegue(segue, sender: sender)
if let indexPath = sender as? NSIndexPath {
switch segue.destinationViewController {
case let controller as FetchingResultsViewController:
let item = self.fetchingItems[indexPath.row]
controller.setTimeZones(item.fetch(), title: item.title)
case let controller as QueryingResultsViewController:
let item = self.queryingItems[indexPath.row]
controller.setValue(item.query(), title: item.title)
default:
break
}
}
}
// MARK: UITableViewDataSource
func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
switch self.segmentedControl?.selectedSegmentIndex {
case Section.Fetching.rawValue?:
return self.fetchingItems.count
case Section.Querying.rawValue?:
return self.queryingItems.count
default:
return 0
}
}
func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCellWithIdentifier("UITableViewCell")!
switch self.segmentedControl?.selectedSegmentIndex {
case Section.Fetching.rawValue?:
cell.textLabel?.text = self.fetchingItems[indexPath.row].title
case Section.Querying.rawValue?:
cell.textLabel?.text = self.queryingItems[indexPath.row].title
default:
cell.textLabel?.text = nil
}
return cell
}
// MARK: UITableViewDelegate
func tableView(tableView: UITableView, didSelectRowAtIndexPath indexPath: NSIndexPath) {
tableView.deselectRowAtIndexPath(indexPath, animated: true)
switch self.segmentedControl?.selectedSegmentIndex {
case Section.Fetching.rawValue?:
self.performSegueWithIdentifier("FetchingResultsViewController", sender: indexPath)
case Section.Querying.rawValue?:
self.performSegueWithIdentifier("QueryingResultsViewController", sender: indexPath)
default:
break
}
}
// MARK: Private
private enum Section: Int {
case Fetching
case Querying
}
private let fetchingItems = [
(
title: "All Time Zones",
fetch: { () -> [TimeZone] in
return Static.timeZonesStack.fetchAll(
From(TimeZone),
OrderBy(.Ascending("name"))
)!
}
),
(
title: "Time Zones in Asia",
fetch: { () -> [TimeZone] in
return Static.timeZonesStack.fetchAll(
From(TimeZone),
Where("%K BEGINSWITH[c] %@", "name", "Asia"),
OrderBy(.Ascending("secondsFromGMT"))
)!
}
),
(
title: "Time Zones in America and Europe",
fetch: { () -> [TimeZone] in
return Static.timeZonesStack.fetchAll(
From(TimeZone),
Where("%K BEGINSWITH[c] %@", "name", "America")
|| Where("%K BEGINSWITH[c] %@", "name", "Europe"),
OrderBy(.Ascending("secondsFromGMT"))
)!
}
),
(
title: "All Time Zones Except America",
fetch: { () -> [TimeZone] in
return Static.timeZonesStack.fetchAll(
From(TimeZone),
!Where("%K BEGINSWITH[c] %@", "name", "America"),
OrderBy(.Ascending("secondsFromGMT"))
)!
}
),
(
title: "Time Zones with Summer Time",
fetch: { () -> [TimeZone] in
return Static.timeZonesStack.fetchAll(
From(TimeZone),
Where("hasDaylightSavingTime", isEqualTo: true),
OrderBy(.Ascending("name"))
)!
}
)
]
private let queryingItems = [
(
title: "Number of Time Zones",
query: { () -> AnyObject in
return Static.timeZonesStack.queryValue(
From(TimeZone),
Select<NSNumber>(.Count("name"))
)!
}
),
(
title: "Abbreviation For Tokyo's Time Zone",
query: { () -> AnyObject in
return Static.timeZonesStack.queryValue(
From(TimeZone),
Select<String>("abbreviation"),
Where("%K ENDSWITH[c] %@", "name", "Tokyo")
)!
}
),
(
title: "All Abbreviations",
query: { () -> AnyObject in
return Static.timeZonesStack.queryAttributes(
From(TimeZone),
Select<NSDictionary>("name", "abbreviation"),
OrderBy(.Ascending("name"))
)!
}
),
(
title: "Number of Countries per Time Zone",
query: { () -> AnyObject in
return Static.timeZonesStack.queryAttributes(
From(TimeZone),
Select<NSDictionary>(.Count("abbreviation"), "abbreviation"),
GroupBy("abbreviation"),
OrderBy(.Ascending("secondsFromGMT"), .Ascending("name"))
)!
}
),
(
title: "Number of Countries with Summer Time",
query: { () -> AnyObject in
return Static.timeZonesStack.queryAttributes(
From(TimeZone),
Select<NSDictionary>(
.Count("hasDaylightSavingTime", As: "numberOfCountries"),
"hasDaylightSavingTime"
),
GroupBy("hasDaylightSavingTime"),
OrderBy(.Descending("hasDaylightSavingTime"))
)!
}
)
]
var didAppearOnce = false
@IBOutlet dynamic weak var segmentedControl: UISegmentedControl?
@IBOutlet dynamic weak var tableView: UITableView?
@IBAction dynamic func segmentedControlValueChanged(sender: AnyObject?) {
self.tableView?.reloadData()
}
}

View File

@@ -0,0 +1,68 @@
//
// FetchingResultsViewController.swift
// CoreStoreDemo
//
// Created by John Rommel Estropia on 2015/06/17.
// Copyright © 2015 John Rommel Estropia. All rights reserved.
//
import UIKit
// MARK: - FetchingResultsViewController
class FetchingResultsViewController: UITableViewController {
// MARK: Public
func setTimeZones(timeZones: [TimeZone]?, title: String) {
self.timeZones += timeZones ?? []
self.sectionTitle = title
self.tableView?.reloadData()
}
// MARK: UIViewController
override func viewDidLoad() {
super.viewDidLoad()
self.tableView.estimatedRowHeight = 60
self.tableView.rowHeight = UITableViewAutomaticDimension
}
// MARK: UITableViewDataSource
override func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return self.timeZones.count
}
override func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCellWithIdentifier("UITableViewCell", forIndexPath: indexPath)
let timeZone = self.timeZones[indexPath.row]
cell.textLabel?.text = timeZone.name
cell.detailTextLabel?.text = timeZone.abbreviation
return cell
}
// MARK: UITableViewDelegate
override func tableView(tableView: UITableView, titleForHeaderInSection section: Int) -> String? {
return self.sectionTitle
}
// MARK: Private
var timeZones = [TimeZone]()
var sectionTitle: String?
}

View File

@@ -0,0 +1,88 @@
//
// QueryingResultsViewController.swift
// CoreStoreDemo
//
// Created by John Rommel Estropia on 2015/06/17.
// Copyright © 2015 John Rommel Estropia. All rights reserved.
//
import UIKit
class QueryingResultsViewController: UITableViewController {
// MARK: Public
func setValue(value: AnyObject?, title: String) {
switch value {
case (let array as [AnyObject])?:
self.values = array.map { (item: AnyObject) -> (title: String, detail: String) in
(
title: item.description,
detail: String(reflecting: item.dynamicType)
)
}
case let item?:
self.values = [
(
title: item.description,
detail: String(reflecting: item.dynamicType)
)
]
default:
self.values = []
}
self.sectionTitle = title
self.tableView?.reloadData()
}
// MARK: UIViewController
override func viewDidLoad() {
super.viewDidLoad()
self.tableView.estimatedRowHeight = 60
self.tableView.rowHeight = UITableViewAutomaticDimension
}
// MARK: UITableViewDataSource
override func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return self.values.count
}
override func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCellWithIdentifier("UITableViewCell", forIndexPath: indexPath)
let value = self.values[indexPath.row]
cell.textLabel?.text = value.title
cell.detailTextLabel?.text = value.detail
return cell
}
// MARK: UITableViewDelegate
override func tableView(tableView: UITableView, titleForHeaderInSection section: Int) -> String? {
return self.sectionTitle
}
// MARK: Private
var values: [(title: String, detail: String)] = []
var sectionTitle: String?
}

View File

@@ -0,0 +1,20 @@
//
// TimeZone.swift
// CoreStoreDemo
//
// Created by John Rommel Estropia on 2015/06/15.
// Copyright © 2015 John Rommel Estropia. All rights reserved.
//
import Foundation
import CoreData
class TimeZone: NSManagedObject {
@NSManaged var secondsFromGMT: Int32
@NSManaged var abbreviation: String
@NSManaged var hasDaylightSavingTime: Bool
@NSManaged var daylightSavingTimeOffset: Double
@NSManaged var name: String
}

View File

@@ -0,0 +1,58 @@
{
"images" : [
{
"idiom" : "iphone",
"size" : "29x29",
"scale" : "2x"
},
{
"idiom" : "iphone",
"size" : "29x29",
"scale" : "3x"
},
{
"idiom" : "iphone",
"size" : "40x40",
"scale" : "2x"
},
{
"idiom" : "iphone",
"size" : "40x40",
"scale" : "3x"
},
{
"size" : "60x60",
"idiom" : "iphone",
"filename" : "Icon-60@2x.png",
"scale" : "2x"
},
{
"size" : "60x60",
"idiom" : "iphone",
"filename" : "Icon-60@3x-1.png",
"scale" : "3x"
},
{
"size" : "76x76",
"idiom" : "ipad",
"filename" : "Icon-76.png",
"scale" : "1x"
},
{
"size" : "76x76",
"idiom" : "ipad",
"filename" : "Icon-76@2x.png",
"scale" : "2x"
},
{
"size" : "60x60",
"idiom" : "car",
"filename" : "Icon-60@3x.png",
"scale" : "3x"
}
],
"info" : {
"version" : 1,
"author" : "xcode"
}
}

View File

Before

Width:  |  Height:  |  Size: 4.1 KiB

After

Width:  |  Height:  |  Size: 4.1 KiB

View File

@@ -0,0 +1,6 @@
{
"info" : {
"version" : 1,
"author" : "xcode"
}
}

View File

@@ -0,0 +1,21 @@
{
"images" : [
{
"idiom" : "universal",
"scale" : "1x"
},
{
"idiom" : "universal",
"filename" : "CoreStoreIcon@2x.png",
"scale" : "2x"
},
{
"idiom" : "universal",
"scale" : "3x"
}
],
"info" : {
"version" : 1,
"author" : "xcode"
}
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 28 KiB

View File

@@ -0,0 +1,12 @@
{
"images" : [
{
"idiom" : "universal",
"filename" : "first.pdf"
}
],
"info" : {
"version" : 1,
"author" : "xcode"
}
}

View File

@@ -0,0 +1,12 @@
{
"images" : [
{
"idiom" : "universal",
"filename" : "second.pdf"
}
],
"info" : {
"version" : 1,
"author" : "xcode"
}
}

View File

@@ -3,7 +3,9 @@
<plist version="1.0">
<dict>
<key>CFBundleDevelopmentRegion</key>
<string>$(DEVELOPMENT_LANGUAGE)</string>
<string>en</string>
<key>CFBundleDisplayName</key>
<string>CoreStore</string>
<key>CFBundleExecutable</key>
<string>$(EXECUTABLE_NAME)</string>
<key>CFBundleIdentifier</key>
@@ -13,36 +15,25 @@
<key>CFBundleName</key>
<string>$(PRODUCT_NAME)</string>
<key>CFBundlePackageType</key>
<string>$(PRODUCT_BUNDLE_PACKAGE_TYPE)</string>
<string>APPL</string>
<key>CFBundleShortVersionString</key>
<string>1.0</string>
<string>1.0.1</string>
<key>CFBundleSignature</key>
<string>????</string>
<key>CFBundleVersion</key>
<string>1</string>
<key>LSRequiresIPhoneOS</key>
<true/>
<key>UIApplicationSceneManifest</key>
<dict>
<key>UIApplicationSupportsMultipleScenes</key>
<false/>
<key>UISceneConfigurations</key>
<dict>
<key>UIWindowSceneSessionRoleApplication</key>
<array>
<dict>
<key>UISceneConfigurationName</key>
<string>Default Configuration</string>
<key>UISceneDelegateClassName</key>
<string>$(PRODUCT_MODULE_NAME).SceneDelegate</string>
</dict>
</array>
</dict>
</dict>
<key>UILaunchStoryboardName</key>
<string>LaunchScreen</string>
<key>UIMainStoryboardFile</key>
<string>Main</string>
<key>UIRequiredDeviceCapabilities</key>
<array>
<string>armv7</string>
</array>
<key>UIStatusBarStyle</key>
<string>UIStatusBarStyleLightContent</string>
<key>UIStatusBarTintParameters</key>
<dict>
<key>UINavigationBar</key>
@@ -56,15 +47,8 @@
<key>UISupportedInterfaceOrientations</key>
<array>
<string>UIInterfaceOrientationPortrait</string>
<string>UIInterfaceOrientationLandscapeLeft</string>
<string>UIInterfaceOrientationLandscapeRight</string>
</array>
<key>UISupportedInterfaceOrientations~ipad</key>
<array>
<string>UIInterfaceOrientationPortrait</string>
<string>UIInterfaceOrientationPortraitUpsideDown</string>
<string>UIInterfaceOrientationLandscapeLeft</string>
<string>UIInterfaceOrientationLandscapeRight</string>
</array>
<key>UIViewControllerBasedStatusBarAppearance</key>
<false/>
</dict>
</plist>

View File

@@ -0,0 +1,306 @@
//
// ListObserverDemoViewController.swift
// CoreStoreDemo
//
// Created by John Rommel Estropia on 2015/05/02.
// Copyright © 2015 John Rommel Estropia. All rights reserved.
//
import UIKit
import CoreStore
private struct Static {
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 {
switch self {
case .All: return Where(true)
case .Light: return Where("brightness >= 0.9")
case .Dark: return Where("brightness <= 0.4")
}
}
}
static var filter = Filter.All {
didSet {
self.palettes.refetch(self.filter.whereClause())
}
}
static let palettes: ListMonitor<Palette> = {
try! CoreStore.addStorageAndWait(
SQLiteStore(
fileName: "ColorsDemo.sqlite",
configuration: "ObservingDemo",
localStorageOptions: .RecreateStoreOnModelMismatch
)
)
return CoreStore.monitorSectionedList(
From(Palette),
SectionBy("colorName"),
OrderBy(.Ascending("hue"))
)
}()
}
// MARK: - ListObserverDemoViewController
class ListObserverDemoViewController: UITableViewController, ListSectionObserver {
// MARK: NSObject
deinit {
Static.palettes.removeObserver(self)
}
// 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: Static.filter.rawValue,
style: .Plain,
target: self,
action: #selector(self.filterBarButtonItemTouched(_:))
)
navigationItem.rightBarButtonItems = [
UIBarButtonItem(
barButtonSystemItem: .Add,
target: self,
action: #selector(self.addBarButtonItemTouched(_:))
),
filterBarButton
]
self.filterBarButton = filterBarButton
Static.palettes.addObserver(self)
self.setTableEnabled(!Static.palettes.isPendingRefetch)
}
override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) {
super.prepareForSegue(segue, sender: sender)
switch (segue.identifier, segue.destinationViewController, sender) {
case ("ObjectObserverDemoViewController"?, let destinationViewController as ObjectObserverDemoViewController, let palette as Palette):
destinationViewController.palette = palette
default:
break
}
}
// MARK: UITableViewDataSource
override func numberOfSectionsInTableView(tableView: UITableView) -> Int {
return Static.palettes.numberOfSections()
}
override func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return Static.palettes.numberOfObjectsInSection(section)
}
override func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCellWithIdentifier("PaletteTableViewCell") as! PaletteTableViewCell
let palette = Static.palettes[indexPath]
cell.colorView?.backgroundColor = palette.color
cell.label?.text = palette.colorText
return cell
}
// MARK: UITableViewDelegate
override func tableView(tableView: UITableView, didSelectRowAtIndexPath indexPath: NSIndexPath) {
tableView.deselectRowAtIndexPath(indexPath, animated: true)
self.performSegueWithIdentifier(
"ObjectObserverDemoViewController",
sender: Static.palettes[indexPath]
)
}
override func tableView(tableView: UITableView, commitEditingStyle editingStyle: UITableViewCellEditingStyle, forRowAtIndexPath indexPath: NSIndexPath) {
switch editingStyle {
case .Delete:
let palette = Static.palettes[indexPath]
CoreStore.beginAsynchronous{ (transaction) -> Void in
transaction.delete(palette)
transaction.commit { (result) -> Void in }
}
default:
break
}
}
override func tableView(tableView: UITableView, titleForHeaderInSection section: Int) -> String? {
return Static.palettes.sectionInfoAtIndex(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.setTableEnabled(false)
}
func listMonitorDidRefetch(monitor: ListMonitor<Palette>) {
self.filterBarButton?.title = Static.filter.rawValue
self.tableView.reloadData()
self.setTableEnabled(true)
}
// MARK: ListObjectObserver
func listMonitor(monitor: ListMonitor<Palette>, didInsertObject object: Palette, toIndexPath indexPath: NSIndexPath) {
self.tableView.insertRowsAtIndexPaths([indexPath], withRowAnimation: .Automatic)
}
func listMonitor(monitor: ListMonitor<Palette>, didDeleteObject object: Palette, fromIndexPath indexPath: NSIndexPath) {
self.tableView.deleteRowsAtIndexPaths([indexPath], withRowAnimation: .Automatic)
}
func listMonitor(monitor: ListMonitor<Palette>, didUpdateObject object: Palette, atIndexPath indexPath: NSIndexPath) {
if let cell = self.tableView.cellForRowAtIndexPath(indexPath) as? PaletteTableViewCell {
let palette = Static.palettes[indexPath]
cell.colorView?.backgroundColor = palette.color
cell.label?.text = palette.colorText
}
}
func listMonitor(monitor: ListMonitor<Palette>, didMoveObject object: Palette, fromIndexPath: NSIndexPath, toIndexPath: NSIndexPath) {
self.tableView.deleteRowsAtIndexPaths([fromIndexPath], withRowAnimation: .Automatic)
self.tableView.insertRowsAtIndexPaths([toIndexPath], withRowAnimation: .Automatic)
}
// MARK: ListSectionObserver
func listMonitor(monitor: ListMonitor<Palette>, didInsertSection sectionInfo: NSFetchedResultsSectionInfo, toSectionIndex sectionIndex: Int) {
self.tableView.insertSections(NSIndexSet(index: sectionIndex), withRowAnimation: .Automatic)
}
func listMonitor(monitor: ListMonitor<Palette>, didDeleteSection sectionInfo: NSFetchedResultsSectionInfo, fromSectionIndex sectionIndex: Int) {
self.tableView.deleteSections(NSIndexSet(index: sectionIndex), withRowAnimation: .Automatic)
}
// MARK: Private
private var filterBarButton: UIBarButtonItem?
@IBAction private dynamic func resetBarButtonItemTouched(sender: AnyObject?) {
CoreStore.beginAsynchronous { (transaction) -> Void in
transaction.deleteAll(From(Palette))
transaction.commit()
}
}
@IBAction private dynamic func filterBarButtonItemTouched(sender: AnyObject?) {
Static.filter = Static.filter.next()
}
@IBAction private dynamic func addBarButtonItemTouched(sender: AnyObject?) {
CoreStore.beginAsynchronous { (transaction) -> Void in
let palette = transaction.create(Into(Palette))
palette.setInitialValues()
transaction.commit()
}
}
private func setTableEnabled(enabled: Bool) {
UIView.animateWithDuration(
0.2,
delay: 0,
options: .BeginFromCurrentState,
animations: { () -> Void in
if let tableView = self.tableView {
tableView.alpha = enabled ? 1.0 : 0.5
tableView.userInteractionEnabled = enabled
}
},
completion: nil
)
}
}

View File

@@ -0,0 +1,192 @@
//
// ObjectObserverDemoViewController.swift
// CoreStoreDemo
//
// Created by John Rommel Estropia on 2015/05/06.
// Copyright © 2015 John Rommel Estropia. All rights reserved.
//
import UIKit
import CoreStore
// MARK: - ObjectObserverDemoViewController
class ObjectObserverDemoViewController: UIViewController, ObjectObserver {
var palette: Palette? {
get {
return self.monitor?.object
}
set {
guard self.monitor?.object != newValue else {
return
}
if let palette = newValue {
self.monitor = CoreStore.monitorObject(palette)
}
else {
self.monitor = nil
}
}
}
// MARK: NSObject
deinit {
self.monitor?.removeObserver(self)
}
// MARK: UIViewController
required init?(coder aDecoder: NSCoder) {
if let palette = CoreStore.fetchOne(From(Palette), OrderBy(.Ascending("hue"))) {
self.monitor = CoreStore.monitorObject(palette)
}
else {
CoreStore.beginSynchronous { (transaction) -> Void in
let palette = transaction.create(Into(Palette))
palette.setInitialValues()
transaction.commitAndWait()
}
let palette = CoreStore.fetchOne(From(Palette), OrderBy(.Ascending("hue")))!
self.monitor = CoreStore.monitorObject(palette)
}
super.init(coder: aDecoder)
}
override func viewDidLoad() {
super.viewDidLoad()
self.monitor?.addObserver(self)
if let palette = self.monitor?.object {
self.reloadPaletteInfo(palette, changedKeys: nil)
}
}
// MARK: ObjectObserver
func objectMonitor(monitor: ObjectMonitor<Palette>, didUpdateObject object: Palette, changedPersistentKeys: Set<KeyPath>) {
self.reloadPaletteInfo(object, changedKeys: changedPersistentKeys)
}
func objectMonitor(monitor: ObjectMonitor<Palette>, didDeleteObject object: Palette) {
self.navigationItem.rightBarButtonItem?.enabled = false
self.colorNameLabel?.alpha = 0.3
self.colorView?.alpha = 0.3
self.hsbLabel?.text = "Deleted"
self.hsbLabel?.textColor = UIColor.redColor()
self.hueSlider?.enabled = false
self.saturationSlider?.enabled = false
self.brightnessSlider?.enabled = false
}
// MARK: Private
var monitor: ObjectMonitor<Palette>?
@IBOutlet weak var colorNameLabel: UILabel?
@IBOutlet weak var colorView: UIView?
@IBOutlet weak var hsbLabel: UILabel?
@IBOutlet weak var dateLabel: UILabel?
@IBOutlet weak var hueSlider: UISlider?
@IBOutlet weak var saturationSlider: UISlider?
@IBOutlet weak var brightnessSlider: UISlider?
@IBAction dynamic func hueSliderValueDidChange(sender: AnyObject?) {
let hue = self.hueSlider?.value ?? 0
CoreStore.beginAsynchronous { [weak self] (transaction) -> Void in
if let palette = transaction.edit(self?.monitor?.object) {
palette.hue = Int32(hue)
transaction.commit()
}
}
}
@IBAction dynamic func saturationSliderValueDidChange(sender: AnyObject?) {
let saturation = self.saturationSlider?.value ?? 0
CoreStore.beginAsynchronous { [weak self] (transaction) -> Void in
if let palette = transaction.edit(self?.monitor?.object) {
palette.saturation = saturation
transaction.commit()
}
}
}
@IBAction dynamic func brightnessSliderValueDidChange(sender: AnyObject?) {
let brightness = self.brightnessSlider?.value ?? 0
CoreStore.beginAsynchronous { [weak self] (transaction) -> Void in
if let palette = transaction.edit(self?.monitor?.object) {
palette.brightness = brightness
transaction.commit()
}
}
}
@IBAction dynamic func deleteBarButtonTapped(sender: AnyObject?) {
CoreStore.beginAsynchronous { [weak self] (transaction) -> Void in
transaction.delete(self?.monitor?.object)
transaction.commit()
}
}
func reloadPaletteInfo(palette: Palette, changedKeys: Set<String>?) {
self.colorNameLabel?.text = palette.colorName
let color = palette.color
self.colorNameLabel?.textColor = color
self.colorView?.backgroundColor = color
self.hsbLabel?.text = palette.colorText
if changedKeys == nil || changedKeys?.contains("hue") == true {
self.hueSlider?.value = Float(palette.hue)
}
if changedKeys == nil || changedKeys?.contains("saturation") == true {
self.saturationSlider?.value = palette.saturation
}
if changedKeys == nil || changedKeys?.contains("brightness") == true {
self.brightnessSlider?.value = palette.brightness
}
}
}

View File

@@ -0,0 +1,30 @@
//
// ObserversViewController.swift
// CoreStoreDemo
//
// Created by John Rommel Estropia on 2015/05/24.
// Copyright © 2015 John Rommel Estropia. All rights reserved.
//
import UIKit
// MARK: - ObserversViewController
class ObserversViewController: UIViewController {
// MARK: UIViewController
override func viewDidAppear(animated: Bool) {
super.viewDidAppear(animated)
let alert = UIAlertController(
title: "Observers Demo",
message: "This demo shows how to observe changes to a list of objects. The top and bottom view controllers both observe a single shared \"ListMonitor\" instance.\n\nTap on a row to see how to observe changes made to a single object using a \"ObjectMonitor\".",
preferredStyle: .Alert
)
alert.addAction(UIAlertAction(title: "OK", style: .Cancel, handler: nil))
self.presentViewController(alert, animated: true, completion: nil)
}
}

View File

@@ -0,0 +1,77 @@
//
// Palette.swift
// CoreStoreDemo
//
// Created by John Rommel Estropia on 2015/05/05.
// Copyright © 2015 John Rommel Estropia. All rights reserved.
//
import Foundation
import UIKit
import CoreData
import CoreStore
// MARK: - Palette
class Palette: NSManagedObject {
@NSManaged var hue: Int32
@NSManaged var saturation: Float
@NSManaged var brightness: Float
@objc dynamic var colorName: String {
get {
let KVCKey = "colorName"
if let colorName = self.accessValueForKVCKey(KVCKey) as? String {
return colorName
}
let colorName: String
switch self.hue % 360 {
case 0 ..< 20: colorName = "Lower Reds"
case 20 ..< 57: colorName = "Oranges and Browns"
case 57 ..< 90: colorName = "Yellow-Greens"
case 90 ..< 159: colorName = "Greens"
case 159 ..< 197: colorName = "Blue-Greens"
case 197 ..< 241: colorName = "Blues"
case 241 ..< 297: colorName = "Violets"
case 297 ..< 331: colorName = "Magentas"
default: colorName = "Upper Reds"
}
self.setPrimitiveValue(colorName, forKey: KVCKey)
return colorName
}
set {
self.setValue(newValue, forKVCKey: "colorName")
}
}
var color: UIColor {
return UIColor(
hue: CGFloat(self.hue) / 360.0,
saturation: CGFloat(self.saturation),
brightness: CGFloat(self.brightness),
alpha: 1.0
)
}
var colorText: String {
return "H: \(self.hue)˚, S: \(round(self.saturation * 100.0))%, B: \(round(self.brightness * 100.0))%"
}
func setInitialValues() {
self.hue = Int32(arc4random_uniform(360))
self.saturation = 1.0
self.brightness = Float(arc4random_uniform(70) + 30) / 100.0
}
}

View File

@@ -0,0 +1,15 @@
//
// PaletteTableViewCell.swift
// CoreStoreDemo
//
// Created by John Rommel Estropia on 2015/05/05.
// Copyright © 2015 John Rommel Estropia. All rights reserved.
//
import UIKit
class PaletteTableViewCell: UITableViewCell {
@IBOutlet weak var colorView: UIView?
@IBOutlet weak var label: UILabel?
}

View File

@@ -0,0 +1,126 @@
//
// CustomLoggerViewController.swift
// CoreStoreDemo
//
// Created by John Rommel Estropia on 2015/06/05.
// Copyright © 2015 John Rommel Estropia. All rights reserved.
//
import UIKit
import CoreStore
import GCDKit
// MARK: - CustomLoggerViewController
class CustomLoggerViewController: UIViewController, CoreStoreLogger {
// MARK: NSObject
deinit {
CoreStore.logger = DefaultLogger()
}
let dataStack = DataStack()
// MARK: UIViewController
override func viewDidLoad() {
super.viewDidLoad()
try! self.dataStack.addStorageAndWait(SQLiteStore(fileName: "emptyStore.sqlite"))
CoreStore.logger = self
}
override func viewDidAppear(animated: Bool) {
super.viewDidAppear(animated)
let alert = UIAlertController(
title: "Logger Demo",
message: "This demo shows how to plug-in any logging framework to CoreStore.\n\nThe view controller implements CoreStoreLogger and appends all logs to the text view.",
preferredStyle: .Alert
)
alert.addAction(UIAlertAction(title: "OK", style: .Cancel, handler: nil))
self.presentViewController(alert, animated: true, completion: nil)
}
// MARK: CoreStoreLogger
func log(level level: LogLevel, message: String, fileName: StaticString, lineNumber: Int, functionName: StaticString) {
GCDQueue.Main.async { [weak self] in
let levelString: String
switch level {
case .Trace: levelString = "Trace"
case .Notice: levelString = "Notice"
case .Warning: levelString = "Warning"
case .Fatal: levelString = "Fatal"
}
self?.textView?.insertText("\((fileName.stringValue as NSString).lastPathComponent):\(lineNumber) \(functionName)\n ↪︎ [Log:\(levelString)] \(message)\n\n")
}
}
func log(error error: CoreStoreError, message: String, fileName: StaticString, lineNumber: Int, functionName: StaticString) {
GCDQueue.Main.async { [weak self] in
self?.textView?.insertText("\((fileName.stringValue as NSString).lastPathComponent):\(lineNumber) \(functionName)\n ↪︎ [Error] \(message): \(error)\n\n")
}
}
func assert(@autoclosure condition: () -> Bool, @autoclosure message: () -> String, fileName: StaticString, lineNumber: Int, functionName: StaticString) {
if condition() {
return
}
let messageString = message()
GCDQueue.Main.async { [weak self] in
self?.textView?.insertText("\((fileName.stringValue as NSString).lastPathComponent):\(lineNumber) \(functionName)\n ↪︎ [Assert] \(messageString)\n\n")
}
}
// MARK: Private
@IBOutlet dynamic weak var textView: UITextView?
@IBOutlet dynamic weak var segmentedControl: UISegmentedControl?
@IBAction dynamic func segmentedControlValueChanged(sender: AnyObject?) {
switch self.segmentedControl?.selectedSegmentIndex {
case 0?:
self.dataStack.beginAsynchronous { (transaction) -> Void in
transaction.create(Into(Palette))
}
case 1?:
_ = try? dataStack.addStorageAndWait(
SQLiteStore(
fileName: "emptyStore.sqlite",
configuration: "invalidStore"
)
)
case 2?:
self.dataStack.beginAsynchronous { (transaction) -> Void in
transaction.commit()
transaction.commit()
}
default:
return
}
}
}

View File

@@ -0,0 +1,397 @@
//
// MigrationsDemoViewController.swift
// CoreStoreDemo
//
// Created by John Rommel Estropia on 2015/06/21.
// Copyright © 2015 John Rommel Estropia. All rights reserved.
//
import UIKit
import CoreStore
// MARK: - MigrationsDemoViewController
class MigrationsDemoViewController: UIViewController {
// MARK: UIViewController
override func viewDidLoad() {
super.viewDidLoad()
if let segmentedControl = self.segmentedControl {
for (index, model) in self.models.enumerate() {
segmentedControl.setTitle(
model.label,
forSegmentAtIndex: index
)
}
}
self.setDataStack(nil, model: nil, scrollToSelection: false)
}
override func viewDidAppear(animated: Bool) {
super.viewDidAppear(animated)
let alert = UIAlertController(
title: "Migrations Demo",
message: "This demo shows how to run progressive migrations and how to support multiple model versions in a single project.\n\nThe persistent store contains 10000 organisms, which gain/lose properties when the migration evolves/devolves them.\n\nYou can use the \"mutate\" button to change an organism's properties then migrate to a different model to see how its value gets affected.",
preferredStyle: .Alert
)
alert.addAction(UIAlertAction(title: "OK", style: .Cancel, handler: nil))
self.presentViewController(alert, animated: true, completion: nil)
let modelMetadata = withExtendedLifetime(DataStack(modelName: "MigrationDemo")) {
(dataStack: DataStack) -> ModelMetadata in
let models = self.models
let migrations = try! dataStack.requiredMigrationsForStorage(
SQLiteStore(fileName: "MigrationDemo.sqlite")
)
guard let storeVersion = migrations.first?.sourceVersion else {
return models.first!
}
for model in models {
if model.version == storeVersion {
return model
}
}
return models.first!
}
self.selectModelVersion(modelMetadata)
}
// MARK: Private
private typealias ModelMetadata = (label: String, version: String, entityType: AnyClass, migrationChain: MigrationChain)
private let models: [ModelMetadata] = [
(
label: "Model V1",
version: "MigrationDemo",
entityType: OrganismV1.self,
migrationChain: ["MigrationDemoV3", "MigrationDemoV2", "MigrationDemo"]
),
(
label: "Model V2",
version: "MigrationDemoV2",
entityType: OrganismV2.self,
migrationChain: [
"MigrationDemo": "MigrationDemoV2",
"MigrationDemoV3": "MigrationDemoV2"
]
),
(
label: "Model V3",
version: "MigrationDemoV3",
entityType: OrganismV3.self,
migrationChain: ["MigrationDemo", "MigrationDemoV2", "MigrationDemoV3"]
)
]
private var _listMonitor: ListMonitor<NSManagedObject>?
private var listMonitor: ListMonitor<NSManagedObject>? {
return self._listMonitor
}
private var _dataStack: DataStack?
private var dataStack: DataStack? {
return self._dataStack
}
private var _lastSelectedIndexPath: NSIndexPath?
private var lastSelectedIndexPath: NSIndexPath? {
return self._lastSelectedIndexPath
}
private func setSelectedIndexPath(indexPath: NSIndexPath, scrollToSelection: Bool) {
self._lastSelectedIndexPath = indexPath
self.updateDisplay(reloadData: false, scrollToSelection: scrollToSelection, animated: true)
}
@IBOutlet private dynamic weak var headerContainer: UIView?
@IBOutlet private dynamic weak var titleLabel: UILabel?
@IBOutlet private dynamic weak var organismLabel: UILabel?
@IBOutlet private dynamic weak var segmentedControl: UISegmentedControl?
@IBOutlet private dynamic weak var progressView: UIProgressView?
@IBOutlet private dynamic weak var tableView: UITableView?
@IBAction private dynamic func segmentedControlValueChanged(sender: AnyObject?) {
guard let index = self.segmentedControl?.selectedSegmentIndex else {
return
}
self.selectModelVersion(self.models[index])
}
private func selectModelVersion(model: ModelMetadata) {
if self.dataStack?.modelVersion == model.version {
return
}
self.setDataStack(nil, model: nil, scrollToSelection: false) // explicitly trigger NSPersistentStore cleanup by deallocating the stack
let dataStack = DataStack(
modelName: "MigrationDemo",
migrationChain: model.migrationChain
)
self.setEnabled(false)
let progress = dataStack.addStorage(
SQLiteStore(fileName: "MigrationDemo.sqlite"),
completion: { [weak self] (result) -> Void in
guard let `self` = self else {
return
}
guard case .Success = result else {
self.setEnabled(true)
return
}
self.setDataStack(dataStack, model: model, scrollToSelection: true)
let count = dataStack.queryValue(
From(model.entityType),
Select<Int>(.Count("dna"))
)
if count > 0 {
self.setEnabled(true)
}
else {
for i: Int64 in 0 ..< 20 {
dataStack.beginAsynchronous { (transaction) -> Void in
for j: Int64 in 0 ..< 500 {
let organism = transaction.create(Into(model.entityType)) as! OrganismProtocol
organism.dna = (i * 500) + j + 1
organism.mutate()
}
transaction.commit()
}
}
dataStack.beginAsynchronous { [weak self] (transaction) -> Void in
transaction.commit { _ in
self?.setEnabled(true)
}
}
}
}
)
if let progress = progress {
progress.setProgressHandler { [weak self] (progress) -> Void in
self?.reloadTableHeaderWithProgress(progress)
}
}
}
private func setEnabled(enabled: Bool) {
UIView.animateWithDuration(
0.2,
delay: 0,
options: .BeginFromCurrentState,
animations: { () -> Void in
let navigationItem = self.navigationItem
navigationItem.leftBarButtonItem?.enabled = enabled
navigationItem.rightBarButtonItem?.enabled = enabled
navigationItem.hidesBackButton = !enabled
self.segmentedControl?.enabled = enabled
if let tableView = self.tableView {
tableView.alpha = enabled ? 1.0 : 0.5
tableView.userInteractionEnabled = enabled
}
},
completion: nil
)
}
private func setDataStack(dataStack: DataStack?, model: ModelMetadata?, scrollToSelection: Bool) {
if let dataStack = dataStack, let model = model {
self.segmentedControl?.selectedSegmentIndex = self.models.map { $0.version }.indexOf(model.version)!
self._dataStack = dataStack
let listMonitor = dataStack.monitorList(From(model.entityType), OrderBy(.Descending("dna")))
listMonitor.addObserver(self)
self._listMonitor = listMonitor
if self.lastSelectedIndexPath == nil {
if listMonitor.numberOfObjectsInSection(0) > 0 {
self.setSelectedIndexPath(NSIndexPath(forRow: 0, inSection: 0), scrollToSelection: true)
}
}
}
else {
self.segmentedControl?.selectedSegmentIndex = UISegmentedControlNoSegment
self._listMonitor = nil
self._dataStack = nil
}
self.updateDisplay(reloadData: true, scrollToSelection: scrollToSelection, animated: false)
}
private func reloadTableHeaderWithProgress(progress: NSProgress) {
self.progressView?.setProgress(Float(progress.fractionCompleted), animated: true)
self.titleLabel?.text = "Migrating: \(progress.localizedDescription)"
self.organismLabel?.text = "Progressive step \(progress.localizedAdditionalDescription)"
}
private func updateDisplay(reloadData reloadData: Bool, scrollToSelection: Bool, animated: Bool) {
var lines = [String]()
var organismType = ""
if let indexPath = self.lastSelectedIndexPath, let organism = self.listMonitor?[indexPath] {
for property in organism.entity.properties {
let value: AnyObject = organism.valueForKey(property.name) ?? NSNull()
lines.append("\(property.name): \(value)")
}
organismType = organism.entity.managedObjectClassName
}
self.titleLabel?.text = organismType
self.organismLabel?.text = lines.joinWithSeparator("\n")
self.progressView?.progress = 0
self.headerContainer?.setNeedsLayout()
guard let tableView = self.tableView else {
return
}
if reloadData {
tableView.reloadData()
}
tableView.layoutIfNeeded()
if let indexPath = self.lastSelectedIndexPath where indexPath.row < tableView.numberOfRowsInSection(0) {
tableView.selectRowAtIndexPath(indexPath,
animated: scrollToSelection && animated,
scrollPosition: scrollToSelection ? .Middle : .None
)
}
}
}
// MARK: - MigrationsDemoViewController: ListObserver
extension MigrationsDemoViewController: ListObserver {
// MARK: ListObserver
func listMonitorWillChange(monitor: ListMonitor<NSManagedObject>) { }
func listMonitorDidChange(monitor: ListMonitor<NSManagedObject>) {
if self.lastSelectedIndexPath == nil && self.listMonitor?.numberOfObjectsInSection(0) > 0 {
self.tableView?.reloadData()
self.setSelectedIndexPath(NSIndexPath(forRow: 0, inSection: 0), scrollToSelection: false)
}
else {
self.updateDisplay(reloadData: true, scrollToSelection: true, animated: true)
}
}
}
// MARK: - MigrationsDemoViewController: UITableViewDataSource, UITableViewDelegate
extension MigrationsDemoViewController: UITableViewDataSource, UITableViewDelegate {
// MARK: UITableViewDataSource
@objc dynamic func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return self.listMonitor?.numberOfObjectsInSection(0) ?? 0
}
@objc dynamic func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCellWithIdentifier("OrganismTableViewCell", forIndexPath: indexPath) as! OrganismTableViewCell
let dna = (self.listMonitor?[indexPath] as? OrganismProtocol)?.dna.description ?? ""
cell.dnaLabel?.text = "DNA: \(dna)"
cell.mutateButtonHandler = { [weak self] _ -> Void in
guard let `self` = self,
let dataStack = self.dataStack,
let organism = self.listMonitor?[indexPath] else {
return
}
self.setSelectedIndexPath(indexPath, scrollToSelection: false)
self.setEnabled(false)
dataStack.beginAsynchronous { [weak self] (transaction) -> Void in
let organism = transaction.edit(organism) as! OrganismProtocol
organism.mutate()
transaction.commit { _ -> Void in
self?.setEnabled(true)
}
}
}
return cell
}
// MARK: UITableViewDelegate
@objc dynamic func tableView(tableView: UITableView, didSelectRowAtIndexPath indexPath: NSIndexPath) {
self.setSelectedIndexPath(indexPath, scrollToSelection: false)
}
}

View File

@@ -0,0 +1,4 @@
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<model userDefinedModelVersionIdentifier="" type="com.apple.IDECoreDataModeler.DataModel" documentVersion="1.0" lastSavedToolsVersion="8166.2" systemVersion="14E46" minimumToolsVersion="Xcode 7.0">
<elements/>
</model>

View File

@@ -0,0 +1,16 @@
//
// OrganismProtocol.swift
// CoreStoreDemo
//
// Created by John Rommel Estropia on 2015/06/27.
// Copyright © 2015 John Rommel Estropia. All rights reserved.
//
import Foundation
protocol OrganismProtocol: class {
var dna: Int64 { get set }
func mutate()
}

View File

@@ -0,0 +1,22 @@
//
// OrganismTableViewCell.swift
// CoreStoreDemo
//
// Created by John Rommel Estropia on 2015/07/12.
// Copyright © 2015 John Rommel Estropia. All rights reserved.
//
import UIKit
class OrganismTableViewCell: UITableViewCell {
@IBOutlet weak dynamic var dnaLabel: UILabel?
@IBOutlet weak dynamic var mutateButton: UIButton?
var mutateButtonHandler: (() -> Void)?
@IBAction dynamic func mutateButtonTouchUpInside(sender: UIButton?) {
self.mutateButtonHandler?()
}
}

View File

@@ -0,0 +1,25 @@
//
// OrganismV1.swift
// CoreStoreDemo
//
// Created by John Rommel Estropia on 2015/06/21.
// Copyright © 2015 John Rommel Estropia. All rights reserved.
//
import Foundation
import CoreData
class OrganismV1: NSManagedObject, OrganismProtocol {
@NSManaged var dna: Int64
@NSManaged var hasHead: Bool
@NSManaged var hasTail: Bool
// MARK: OrganismProtocol
func mutate() {
self.hasHead = arc4random_uniform(2) == 1
self.hasTail = arc4random_uniform(2) == 1
}
}

View File

@@ -0,0 +1,27 @@
//
// OrganismV2.swift
// CoreStoreDemo
//
// Created by John Rommel Estropia on 2015/06/21.
// Copyright © 2015 John Rommel Estropia. All rights reserved.
//
import Foundation
import CoreData
class OrganismV2: NSManagedObject, OrganismProtocol {
@NSManaged var dna: Int64
@NSManaged var hasHead: Bool
@NSManaged var hasTail: Bool
@NSManaged var numberOfFlippers: Int32
// MARK: OrganismProtocol
func mutate() {
self.hasHead = arc4random_uniform(2) == 1
self.hasTail = arc4random_uniform(2) == 1
self.numberOfFlippers = Int32(arc4random_uniform(9) / 2 * 2)
}
}

File diff suppressed because one or more lines are too long

View File

@@ -0,0 +1,23 @@
//
// OrganismV2ToV3MigrationPolicy.swift
// CoreStoreDemo
//
// Created by John Rommel Estropia on 2015/06/27.
// Copyright © 2015 John Rommel Estropia. All rights reserved.
//
import CoreData
class OrganismV2ToV3MigrationPolicy: NSEntityMigrationPolicy {
override func createDestinationInstancesForSourceInstance(sInstance: NSManagedObject, entityMapping mapping: NSEntityMapping, manager: NSMigrationManager) throws {
try super.createDestinationInstancesForSourceInstance(sInstance, entityMapping: mapping, manager: manager)
for dInstance in manager.destinationInstancesForEntityMappingNamed(mapping.name, sourceInstances: [sInstance]) {
dInstance.setValue(false, forKey: "hasVertebrae")
dInstance.setValue(sInstance.valueForKey("numberOfFlippers"), forKey: "numberOfLimbs")
}
}
}

View File

@@ -0,0 +1,29 @@
//
// OrganismV3.swift
// CoreStoreDemo
//
// Created by John Rommel Estropia on 2015/06/27.
// Copyright © 2015 John Rommel Estropia. All rights reserved.
//
import Foundation
import CoreData
class OrganismV3: NSManagedObject, OrganismProtocol {
@NSManaged var dna: Int64
@NSManaged var hasHead: Bool
@NSManaged var hasTail: Bool
@NSManaged var numberOfLimbs: Int32
@NSManaged var hasVertebrae: Bool
// MARK: OrganismProtocol
func mutate() {
self.hasHead = arc4random_uniform(2) == 1
self.hasTail = arc4random_uniform(2) == 1
self.numberOfLimbs = Int32(arc4random_uniform(9) / 2 * 2)
self.hasVertebrae = arc4random_uniform(2) == 1
}
}

File diff suppressed because one or more lines are too long

View File

@@ -3,6 +3,6 @@
<plist version="1.0">
<dict>
<key>_XCCurrentVersionName</key>
<string>Advanced.EvolutionDemo.V1.xcdatamodel</string>
<string>MigrationDemoV3.xcdatamodel</string>
</dict>
</plist>

View File

@@ -0,0 +1,11 @@
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<model userDefinedModelVersionIdentifier="" type="com.apple.IDECoreDataModeler.DataModel" documentVersion="1.0" lastSavedToolsVersion="7701" systemVersion="14E46" minimumToolsVersion="Xcode 4.3">
<entity name="Organism" representedClassName="CoreStoreDemo.OrganismV1" syncable="YES">
<attribute name="dna" optional="YES" attributeType="Integer 64" syncable="YES"/>
<attribute name="hasHead" optional="YES" attributeType="Boolean" syncable="YES"/>
<attribute name="hasTail" optional="YES" attributeType="Boolean" syncable="YES"/>
</entity>
<elements>
<element name="Organism" positionX="-36" positionY="9" width="128" height="90"/>
</elements>
</model>

View File

@@ -0,0 +1,12 @@
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<model userDefinedModelVersionIdentifier="" type="com.apple.IDECoreDataModeler.DataModel" documentVersion="1.0" lastSavedToolsVersion="7701" systemVersion="14E46" minimumToolsVersion="Xcode 4.3">
<entity name="Organism" representedClassName="CoreStoreDemo.OrganismV2" syncable="YES">
<attribute name="dna" optional="YES" attributeType="Integer 64" syncable="YES"/>
<attribute name="hasHead" attributeType="Boolean" syncable="YES"/>
<attribute name="hasTail" attributeType="Boolean" syncable="YES"/>
<attribute name="numberOfFlippers" attributeType="Integer 32" defaultValueString="0" syncable="YES"/>
</entity>
<elements>
<element name="Organism" positionX="-36" positionY="9" width="128" height="105"/>
</elements>
</model>

View File

@@ -0,0 +1,13 @@
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<model userDefinedModelVersionIdentifier="" type="com.apple.IDECoreDataModeler.DataModel" documentVersion="1.0" lastSavedToolsVersion="7701" systemVersion="14E46" minimumToolsVersion="Xcode 4.3">
<entity name="Organism" representedClassName="CoreStoreDemo.OrganismV3" syncable="YES">
<attribute name="dna" optional="YES" attributeType="Integer 64" syncable="YES"/>
<attribute name="hasHead" attributeType="Boolean" syncable="YES"/>
<attribute name="hasTail" attributeType="Boolean" syncable="YES"/>
<attribute name="hasVertebrae" attributeType="Boolean" syncable="YES"/>
<attribute name="numberOfLimbs" attributeType="Integer 32" defaultValueString="0" syncable="YES"/>
</entity>
<elements>
<element name="Organism" positionX="-36" positionY="9" width="128" height="120"/>
</elements>
</model>

View File

@@ -0,0 +1,15 @@
//
// FemaleAccount.swift
// CoreStoreDemo
//
// Created by John Rommel Estropia on 2015/06/06.
// Copyright © 2015 John Rommel Estropia. All rights reserved.
//
import Foundation
import CoreData
class FemaleAccount: UserAccount {
}

View File

@@ -0,0 +1,15 @@
//
// MaleAccount.swift
// CoreStoreDemo
//
// Created by John Rommel Estropia on 2015/06/06.
// Copyright © 2015 John Rommel Estropia. All rights reserved.
//
import Foundation
import CoreData
class MaleAccount: UserAccount {
}

View File

@@ -0,0 +1,197 @@
//
// StackSetupDemoViewController.swift
// CoreStoreDemo
//
// Created by John Rommel Estropia on 2015/05/24.
// Copyright © 2015 John Rommel Estropia. All rights reserved.
//
import UIKit
import CoreStore
private struct Static {
static let maleConfiguration = "MaleAccounts"
static let femaleConfiguration = "FemaleAccounts"
static let facebookStack: DataStack = {
let dataStack = DataStack(modelName: "StackSetupDemo")
try! dataStack.addStorageAndWait(
SQLiteStore(
fileName: "AccountsDemo_FB_Male.sqlite",
configuration: maleConfiguration,
localStorageOptions: .RecreateStoreOnModelMismatch
)
)
try! dataStack.addStorageAndWait(
SQLiteStore(
fileName: "AccountsDemo_FB_Female.sqlite",
configuration: femaleConfiguration,
localStorageOptions: .RecreateStoreOnModelMismatch
)
)
dataStack.beginSynchronous { (transaction) -> Void in
transaction.deleteAll(From(UserAccount))
let account1 = transaction.create(Into<MaleAccount>(maleConfiguration))
account1.accountType = "Facebook"
account1.name = "John Smith HCD"
account1.friends = 42
let account2 = transaction.create(Into<FemaleAccount>(femaleConfiguration))
account2.accountType = "Facebook"
account2.name = "Jane Doe HCD"
account2.friends = 314
transaction.commitAndWait()
}
return dataStack
}()
static let twitterStack: DataStack = {
let dataStack = DataStack(modelName: "StackSetupDemo")
try! dataStack.addStorageAndWait(
SQLiteStore(
fileName: "AccountsDemo_TW_Male.sqlite",
configuration: maleConfiguration,
localStorageOptions: .RecreateStoreOnModelMismatch
)
)
try! dataStack.addStorageAndWait(
SQLiteStore(
fileName: "AccountsDemo_TW_Female.sqlite",
configuration: femaleConfiguration,
localStorageOptions: .RecreateStoreOnModelMismatch
)
)
dataStack.beginSynchronous { (transaction) -> Void in
transaction.deleteAll(From(UserAccount))
let account1 = transaction.create(Into<MaleAccount>(maleConfiguration))
account1.accountType = "Twitter"
account1.name = "#johnsmith_hcd"
account1.friends = 7
let account2 = transaction.create(Into<FemaleAccount>(femaleConfiguration))
account2.accountType = "Twitter"
account2.name = "#janedoe_hcd"
account2.friends = 100
transaction.commitAndWait()
}
return dataStack
}()
}
// MARK: - StackSetupDemoViewController
class StackSetupDemoViewController: UITableViewController {
let accounts = [
Static.facebookStack.fetchAll(From(UserAccount)) ?? [],
Static.twitterStack.fetchAll(From(UserAccount)) ?? []
]
// MARK: UIViewController
override func viewWillAppear(animated: Bool) {
super.viewWillAppear(animated)
self.tableView.reloadData()
let indexPath = NSIndexPath(forRow: 0, inSection: 0)
self.tableView.selectRowAtIndexPath(indexPath, animated: false, scrollPosition: .None)
self.updateDetailsWithAccount(self.accounts[indexPath.section][indexPath.row])
}
override func viewDidAppear(animated: Bool) {
super.viewDidAppear(animated)
let alert = UIAlertController(
title: "Setup Demo",
message: "This demo shows how to initialize 2 DataStacks with 2 configurations each, for a total of 4 SQLite files, each with 1 instance of a \"UserAccount\" entity.",
preferredStyle: .Alert
)
alert.addAction(UIAlertAction(title: "OK", style: .Cancel, handler: nil))
self.presentViewController(alert, animated: true, completion: nil)
}
// MARK: UITableViewDataSource
override func numberOfSectionsInTableView(tableView: UITableView) -> Int {
return self.accounts.count
}
override func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return self.accounts[section].count
}
override func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCellWithIdentifier("UITableViewCell")!
let account = self.accounts[indexPath.section][indexPath.row]
cell.textLabel?.text = account.name
cell.detailTextLabel?.text = "\(account.friends) friends"
return cell
}
// MARK: UITableViewDelegate
override func tableView(tableView: UITableView, didSelectRowAtIndexPath indexPath: NSIndexPath) {
let account = self.accounts[indexPath.section][indexPath.row]
self.updateDetailsWithAccount(account)
}
override func tableView(tableView: UITableView, titleForHeaderInSection section: Int) -> String? {
switch section {
case 0:
let count = self.accounts[section].count
return "Facebook Accounts (\(count) users)"
case 1:
let count = self.accounts[section].count
return "Twitter Accounts (\(count) users)"
default:
return nil
}
}
// MARK: Private
@IBOutlet private dynamic weak var accountTypeLabel: UILabel?
@IBOutlet private dynamic weak var nameLabel: UILabel?
@IBOutlet private dynamic weak var friendsLabel: UILabel?
private func updateDetailsWithAccount(account: UserAccount) {
self.accountTypeLabel?.text = account.accountType
self.nameLabel?.text = account.name
self.friendsLabel?.text = "\(account.friends) friends"
}
}

View File

@@ -0,0 +1,20 @@
//
// UserAccount.swift
// CoreStoreDemo
//
// Created by John Rommel Estropia on 2015/05/24.
// Copyright © 2015 John Rommel Estropia. All rights reserved.
//
import Foundation
import CoreData
// MARK: - UserAccount
class UserAccount: NSManagedObject {
@NSManaged var accountType: String?
@NSManaged var name: String?
@NSManaged var friends: Int32
}

View File

@@ -0,0 +1,23 @@
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<model userDefinedModelVersionIdentifier="" type="com.apple.IDECoreDataModeler.DataModel" documentVersion="1.0" lastSavedToolsVersion="7701" systemVersion="14D136" minimumToolsVersion="Xcode 4.3" macOSVersion="Automatic" iOSVersion="Automatic">
<entity name="FemaleAccount" representedClassName="CoreStoreDemo.FemaleAccount" parentEntity="UserAccount" syncable="YES"/>
<entity name="MaleAccount" representedClassName="CoreStoreDemo.MaleAccount" parentEntity="UserAccount" syncable="YES"/>
<entity name="UserAccount" representedClassName="CoreStoreDemo.UserAccount" isAbstract="YES" syncable="YES">
<attribute name="accountType" optional="YES" attributeType="String" syncable="YES"/>
<attribute name="friends" optional="YES" attributeType="Integer 32" defaultValueString="0" syncable="YES"/>
<attribute name="name" optional="YES" attributeType="String" syncable="YES"/>
</entity>
<configuration name="FemaleAccounts">
<memberEntity name="FemaleAccount"/>
<memberEntity name="UserAccount"/>
</configuration>
<configuration name="MaleAccounts">
<memberEntity name="MaleAccount"/>
<memberEntity name="UserAccount"/>
</configuration>
<elements>
<element name="UserAccount" positionX="-63" positionY="-18" width="128" height="90"/>
<element name="MaleAccount" positionX="-54" positionY="18" width="128" height="45"/>
<element name="FemaleAccount" positionX="-36" positionY="27" width="128" height="45"/>
</elements>
</model>

View File

@@ -0,0 +1,50 @@
//
// Place.swift
// CoreStoreDemo
//
// Created by John Rommel Estropia on 2015/05/24.
// Copyright © 2015 John Rommel Estropia. All rights reserved.
//
import Foundation
import CoreData
import MapKit
// MARK: - Place
class Place: NSManagedObject, MKAnnotation {
@NSManaged var latitude: Double
@NSManaged var longitude: Double
@NSManaged var title: String?
@NSManaged var subtitle: String?
func setInitialValues() {
self.latitude = Double(arc4random_uniform(180)) - 90
self.longitude = Double(arc4random_uniform(360)) - 180
self.title = "\(self.latitude), \(self.longitude)"
self.subtitle = nil
}
// MARK: MKAnnotation
var coordinate: CLLocationCoordinate2D {
get {
return CLLocationCoordinate2DMake(
self.latitude,
self.longitude
)
}
set {
self.latitude = newValue.latitude
self.longitude = newValue.longitude
self.title = "\(self.latitude), \(self.longitude)"
self.subtitle = nil
}
}
}

View File

@@ -0,0 +1,214 @@
//
// TransactionsDemoViewController.swift
// CoreStoreDemo
//
// Created by John Rommel Estropia on 2015/05/24.
// Copyright © 2015 John Rommel Estropia. All rights reserved.
//
import UIKit
import CoreLocation
import MapKit
import AddressBookUI
import CoreStore
import GCDKit
private struct Static {
static let placeController: ObjectMonitor<Place> = {
try! CoreStore.addStorageAndWait(
SQLiteStore(
fileName: "PlaceDemo.sqlite",
configuration: "TransactionsDemo",
localStorageOptions: .RecreateStoreOnModelMismatch
)
)
var place = CoreStore.fetchOne(From(Place))
if place == nil {
CoreStore.beginSynchronous { (transaction) -> Void in
let place = transaction.create(Into(Place))
place.setInitialValues()
transaction.commitAndWait()
}
place = CoreStore.fetchOne(From(Place))
}
return CoreStore.monitorObject(place!)
}()
}
// MARK: - TransactionsDemoViewController
class TransactionsDemoViewController: UIViewController, MKMapViewDelegate, ObjectObserver {
// MARK: NSObject
deinit {
Static.placeController.removeObserver(self)
}
// MARK: UIViewController
override func viewDidLoad() {
super.viewDidLoad()
let longPressGesture = UILongPressGestureRecognizer(
target: self,
action: #selector(self.longPressGestureRecognized(_:))
)
self.mapView?.addGestureRecognizer(longPressGesture)
Static.placeController.addObserver(self)
self.navigationItem.rightBarButtonItem = UIBarButtonItem(
barButtonSystemItem: .Refresh,
target: self,
action: #selector(self.refreshButtonTapped(_:))
)
}
override func viewDidAppear(animated: Bool) {
super.viewDidAppear(animated)
let alert = UIAlertController(
title: "Transactions Demo",
message: "This demo shows how to use the 3 types of transactions to save updates: synchronous, asynchronous, and unsafe.\n\nTap and hold on the map to change the pin location.",
preferredStyle: .Alert
)
alert.addAction(UIAlertAction(title: "OK", style: .Cancel, handler: nil))
self.presentViewController(alert, animated: true, completion: nil)
}
override func viewWillAppear(animated: Bool) {
super.viewWillAppear(animated)
if let mapView = self.mapView, let place = Static.placeController.object {
mapView.addAnnotation(place)
mapView.setCenterCoordinate(place.coordinate, animated: false)
mapView.selectAnnotation(place, animated: false)
}
}
// MARK: MKMapViewDelegate
func mapView(mapView: MKMapView, viewForAnnotation annotation: MKAnnotation) -> MKAnnotationView? {
let identifier = "MKAnnotationView"
var annotationView: MKPinAnnotationView! = mapView.dequeueReusableAnnotationViewWithIdentifier(identifier) as? MKPinAnnotationView
if annotationView == nil {
annotationView = MKPinAnnotationView(annotation: annotation, reuseIdentifier: identifier)
annotationView.enabled = true
annotationView.canShowCallout = true
annotationView.animatesDrop = true
}
else {
annotationView.annotation = annotation
}
return annotationView
}
// MARK: ObjectObserver
func objectMonitor(monitor: ObjectMonitor<Place>, willUpdateObject object: Place) {
// none
}
func objectMonitor(monitor: ObjectMonitor<Place>, didUpdateObject object: Place, changedPersistentKeys: Set<KeyPath>) {
if let mapView = self.mapView {
mapView.removeAnnotations(mapView.annotations ?? [])
mapView.addAnnotation(object)
mapView.setCenterCoordinate(object.coordinate, animated: true)
mapView.selectAnnotation(object, animated: true)
if changedPersistentKeys.contains("latitude") || changedPersistentKeys.contains("longitude") {
self.geocodePlace(object)
}
}
}
func objectMonitor(monitor: ObjectMonitor<Place>, didDeleteObject object: Place) {
// none
}
// MARK: Private
var geocoder: CLGeocoder?
@IBOutlet weak var mapView: MKMapView?
@IBAction dynamic func longPressGestureRecognized(sender: AnyObject?) {
if let mapView = self.mapView, let gesture = sender as? UILongPressGestureRecognizer where gesture.state == .Began {
let coordinate = mapView.convertPoint(
gesture.locationInView(mapView),
toCoordinateFromView: mapView
)
CoreStore.beginAsynchronous { (transaction) -> Void in
let place = transaction.edit(Static.placeController.object)
place?.coordinate = coordinate
transaction.commit { (_) -> Void in }
}
}
}
@IBAction dynamic func refreshButtonTapped(sender: AnyObject?) {
CoreStore.beginSynchronous { (transaction) -> Void in
let place = transaction.edit(Static.placeController.object)
place?.setInitialValues()
transaction.commitAndWait()
}
}
func geocodePlace(place: Place) {
let transaction = CoreStore.beginUnsafe()
self.geocoder?.cancelGeocode()
let geocoder = CLGeocoder()
self.geocoder = geocoder
geocoder.reverseGeocodeLocation(
CLLocation(latitude: place.latitude, longitude: place.longitude),
completionHandler: { [weak self] (placemarks, error) -> Void in
if let placemark = placemarks?.first, let addressDictionary = placemark.addressDictionary {
let place = transaction.edit(Static.placeController.object)
place?.title = placemark.name
place?.subtitle = ABCreateStringWithAddressDictionary(addressDictionary, true)
transaction.commit { (_) -> Void in }
}
self?.geocoder = nil
}
)
}
}

Binary file not shown.

View File

@@ -1,94 +0,0 @@
//
// BaseTestDataTestCase.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
@testable
import CoreStore
// MARK: - BaseTestDataTestCase
class BaseTestDataTestCase: BaseTestCase {
@nonobjc
let dateFormatter: DateFormatter = Internals.with {
let formatter = DateFormatter()
formatter.locale = Locale(identifier: "en_US_POSIX")
formatter.timeZone = TimeZone(identifier: "UTC")
formatter.calendar = Calendar(identifier: Calendar.Identifier.gregorian)
formatter.dateFormat = "yyyy'-'MM'-'dd'T'HH':'mm':'ssZ"
return formatter
}
@nonobjc
func prepareTestDataForStack(_ stack: DataStack, configurations: [ModelConfiguration] = [nil]) {
try! stack.perform(
synchronous: { (transaction) in
for (configurationIndex, configuration) in configurations.enumerated() {
let configurationOrdinal = configurationIndex + 1
if configuration == nil || configuration == "Config1" {
for idIndex in 1 ... 5 {
let object = transaction.create(Into<TestEntity1>(configuration))
object.testEntityID = NSNumber(value: (configurationOrdinal * 100) + idIndex)
object.testNumber = NSNumber(value: idIndex)
object.testDate = self.dateFormatter.date(from: "2000-\(configurationOrdinal)-\(idIndex)T00:00:00Z")
object.testBoolean = NSNumber(value: (idIndex % 2) == 1)
object.testDecimal = NSDecimalNumber(string: "\(idIndex)")
let string = "\(configuration ?? "nil"):TestEntity1:\(idIndex)"
object.testString = string
object.testData = (string as NSString).data(using: String.Encoding.utf8.rawValue)
}
}
if configuration == nil || configuration == "Config2" {
for idIndex in 1 ... 5 {
let object = transaction.create(Into<TestEntity2>(configuration))
object.testEntityID = NSNumber(value: (configurationOrdinal * 200) + idIndex)
object.testNumber = NSNumber(value: idIndex)
object.testDate = self.dateFormatter.date(from: "2000-\(configurationOrdinal)-\(idIndex)T00:00:00Z")
object.testBoolean = NSNumber(value: (idIndex % 2) == 1)
object.testDecimal = NSDecimalNumber(string: "\(idIndex)")
let string = "\(configuration ?? "nil"):TestEntity2:\(idIndex)"
object.testString = string
object.testData = (string as NSString).data(using: String.Encoding.utf8.rawValue)
}
}
}
}
)
}
}

View File

@@ -2,7 +2,7 @@
// BaseTestCase.swift
// CoreStore
//
// Copyright © 2018 John Rommel Estropia
// Copyright © 2016 John Rommel Estropia
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
@@ -28,17 +28,6 @@ import XCTest
@testable
import CoreStore
#if !SWIFT_PACKAGE
extension Bundle {
static var module: Bundle {
return Bundle(for: BaseTestCase.self)
}
}
#endif
// MARK: - BaseTestCase
@@ -47,11 +36,11 @@ class BaseTestCase: XCTestCase {
// MARK: Internal
@nonobjc
func prepareStack(configurations: [ModelConfiguration] = [nil], _ closure: (_ dataStack: DataStack) throws -> Void) {
func prepareStack<T>(configurations configurations: [String?] = [nil], @noescape _ closure: (dataStack: DataStack) -> T) -> T {
let stack = DataStack(
xcodeModelName: "Model",
bundle: Bundle.module
modelName: "Model",
bundle: NSBundle(forClass: self.dynamicType)
)
do {
@@ -60,76 +49,46 @@ class BaseTestCase: XCTestCase {
try stack.addStorageAndWait(
SQLiteStore(
fileURL: SQLiteStore.defaultRootDirectory
.appendingPathComponent(UUID().uuidString)
.appendingPathComponent("\(Self.self)_\(($0 ?? "-null-")).sqlite"),
.URLByAppendingPathComponent(NSUUID().UUIDString)
.URLByAppendingPathComponent("\(self.dynamicType)_\(($0 ?? "-null-")).sqlite"),
configuration: $0,
localStorageOptions: .recreateStoreOnModelMismatch
localStorageOptions: .RecreateStoreOnModelMismatch
)
)
}
try closure(stack)
}
catch let error as NSError {
XCTFail(error.coreStoreDumpString)
}
self.addTeardownBlock {
stack.unsafeRemoveAllPersistentStoresAndWait()
}
return closure(dataStack: stack)
}
@nonobjc
func expectLogger<T>(_ expectations: [TestLogger.Expectation], closure: () throws -> T) rethrows -> T {
func expectLogger<T>(expectations: [TestLogger.Expectation], @noescape closure: () -> T) -> T {
CoreStoreDefaults.logger = TestLogger(self.prepareLoggerExpectations(expectations))
CoreStore.logger = TestLogger(self.prepareLoggerExpectations(expectations))
defer {
self.checkExpectationsImmediately()
CoreStoreDefaults.logger = TestLogger([:])
CoreStore.logger = TestLogger([:])
}
return try closure()
return closure()
}
@nonobjc
func expectLogger(_ expectations: [TestLogger.Expectation: XCTestExpectation]) {
func expectLogger(expectations: [TestLogger.Expectation: XCTestExpectation]) {
CoreStoreDefaults.logger = TestLogger(expectations)
}
@nonobjc
func expectError<T>(code: CoreStoreErrorCode, closure: () throws -> T) {
CoreStoreDefaults.logger = TestLogger(self.prepareLoggerExpectations([.logError]))
defer {
self.checkExpectationsImmediately()
CoreStoreDefaults.logger = TestLogger([:])
}
do {
_ = try closure()
}
catch let error as CoreStoreError {
if error.errorCode == code.rawValue {
return
}
XCTFail("Expected error code \(code) different from actual error: \((error as NSError).coreStoreDumpString)")
}
catch {
XCTFail("Error not wrapped as \(Internals.typeName(CoreStoreError.self)): \((error as NSError).coreStoreDumpString)")
}
CoreStore.logger = TestLogger(expectations)
}
@nonobjc
func prepareLoggerExpectations(_ expectations: [TestLogger.Expectation]) -> [TestLogger.Expectation: XCTestExpectation] {
func prepareLoggerExpectations(expectations: [TestLogger.Expectation]) -> [TestLogger.Expectation: XCTestExpectation] {
var testExpectations: [TestLogger.Expectation: XCTestExpectation] = [:]
for expectation in expectations {
testExpectations[expectation] = self.expectation(description: "Logger Expectation: \(expectation)")
testExpectations[expectation] = self.expectationWithDescription("Logger Expectation: \(expectation)")
}
return testExpectations
}
@@ -137,13 +96,13 @@ class BaseTestCase: XCTestCase {
@nonobjc
func checkExpectationsImmediately() {
self.waitForExpectations(timeout: 0, handler: { _ in })
self.waitForExpectationsWithTimeout(0, handler: nil)
}
@nonobjc
func waitAndCheckExpectations() {
self.waitForExpectations(timeout: 10, handler: {_ in })
self.waitForExpectationsWithTimeout(10, handler: nil)
}
// MARK: XCTestCase
@@ -152,12 +111,12 @@ class BaseTestCase: XCTestCase {
super.setUp()
self.deleteStores()
CoreStoreDefaults.logger = TestLogger([:])
CoreStore.logger = TestLogger([:])
}
override func tearDown() {
CoreStoreDefaults.logger = DefaultLogger()
CoreStore.logger = DefaultLogger()
self.deleteStores()
super.tearDown()
}
@@ -167,7 +126,7 @@ class BaseTestCase: XCTestCase {
private func deleteStores() {
_ = try? FileManager.default.removeItem(at: SQLiteStore.defaultRootDirectory)
_ = try? NSFileManager.defaultManager().removeItemAtURL(SQLiteStore.defaultRootDirectory)
}
}
@@ -178,11 +137,11 @@ class TestLogger: CoreStoreLogger {
enum Expectation {
case logWarning
case logFatal
case logError
case assertionFailure
case fatalError
case LogWarning
case LogFatal
case LogError
case AssertionFailure
case FatalError
}
init(_ expectations: [Expectation: XCTestExpectation]) {
@@ -193,35 +152,33 @@ class TestLogger: CoreStoreLogger {
// MARK: CoreStoreLogger
var enableObjectConcurrencyDebugging: Bool = true
func log(level: LogLevel, message: String, fileName: StaticString, lineNumber: Int, functionName: StaticString) {
func log(level level: LogLevel, message: String, fileName: StaticString, lineNumber: Int, functionName: StaticString) {
switch level {
case .warning: self.fulfill(.logWarning)
case .fatal: self.fulfill(.logFatal)
case .Warning: self.fulfill(.LogWarning)
case .Fatal: self.fulfill(.LogFatal)
default: break
}
}
func log(error: CoreStoreError, message: String, fileName: StaticString, lineNumber: Int, functionName: StaticString) {
func log(error error: CoreStoreError, message: String, fileName: StaticString, lineNumber: Int, functionName: StaticString) {
self.fulfill(.logError)
self.fulfill(.LogError)
}
func assert(_ condition: @autoclosure () -> Bool, message: @autoclosure () -> String, fileName: StaticString, lineNumber: Int, functionName: StaticString) {
func assert(@autoclosure condition: () -> Bool, @autoclosure message: () -> String, fileName: StaticString, lineNumber: Int, functionName: StaticString) {
if condition() {
return
}
self.fulfill(.assertionFailure)
self.fulfill(.AssertionFailure)
}
func abort(_ message: String, fileName: StaticString, lineNumber: Int, functionName: StaticString) {
func abort(message: String, fileName: StaticString, lineNumber: Int, functionName: StaticString) {
self.fulfill(.fatalError)
self.fulfill(.FatalError)
}
@@ -229,7 +186,7 @@ class TestLogger: CoreStoreLogger {
private var expectations: [Expectation: XCTestExpectation]
private func fulfill(_ expectation: Expectation) {
private func fulfill(expectation: Expectation) {
if let instance = self.expectations[expectation] {

View File

@@ -0,0 +1,76 @@
//
// BaseTestDataTestCase.swift
// CoreStore
//
// Created by John Rommel Estropia on 2016/06/11.
// Copyright © 2016 John Rommel Estropia. All rights reserved.
//
import Foundation
@testable
import CoreStore
// MARK: - BaseTestDataTestCase
class BaseTestDataTestCase: BaseTestCase {
@nonobjc
let dateFormatter: NSDateFormatter = {
let formatter = NSDateFormatter()
formatter.locale = NSLocale(localeIdentifier: "en_US_POSIX")
formatter.timeZone = NSTimeZone(name: "UTC")
formatter.calendar = NSCalendar(identifier: NSCalendarIdentifierGregorian)
formatter.dateFormat = "yyyy'-'MM'-'dd'T'HH':'mm':'ssZ"
return formatter
}()
@nonobjc
func prepareTestDataForStack(stack: DataStack, configurations: [String?] = [nil]) {
stack.beginSynchronous { (transaction) in
for (configurationIndex, configuration) in configurations.enumerate() {
let configurationOrdinal = configurationIndex + 1
if configuration == nil || configuration == "Config1" {
for idIndex in 1 ... 5 {
let object = transaction.create(Into<TestEntity1>(configuration))
object.testEntityID = NSNumber(integer: (configurationOrdinal * 100) + idIndex)
object.testNumber = idIndex
object.testDate = self.dateFormatter.dateFromString("2000-\(configurationOrdinal)-\(idIndex)T00:00:00Z")
object.testBoolean = (idIndex % 2) == 1
object.testDecimal = NSDecimalNumber(string: "\(idIndex)")
let string = "\(configuration ?? "nil"):TestEntity1:\(idIndex)"
object.testString = string
object.testData = (string as NSString).dataUsingEncoding(NSUTF8StringEncoding)
}
}
if configuration == nil || configuration == "Config2" {
for idIndex in 1 ... 5 {
let object = transaction.create(Into<TestEntity2>(configuration))
object.testEntityID = NSNumber(integer: (configurationOrdinal * 200) + idIndex)
object.testNumber = idIndex
object.testDate = self.dateFormatter.dateFromString("2000-\(configurationOrdinal)-\(idIndex)T00:00:00Z")
object.testBoolean = (idIndex % 2) == 1
object.testDecimal = NSDecimalNumber(string: "\(idIndex)")
let string = "\(configuration ?? "nil"):TestEntity2:\(idIndex)"
object.testString = string
object.testData = (string as NSString).dataUsingEncoding(NSUTF8StringEncoding)
}
}
}
transaction.commitAndWait()
}
}
}

View File

@@ -1,8 +1,8 @@
//
// Module.swift
// BridgingTests.h
// CoreStore
//
// Copyright © 2018 John Rommel Estropia
// Copyright © 2016 John Rommel Estropia
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
@@ -23,4 +23,8 @@
// SOFTWARE.
//
@_exported import CoreData
#import <XCTest/XCTest.h>
@interface BridgingTests : XCTestCase
@end

View File

@@ -0,0 +1,237 @@
//
// BridgingTests.m
// CoreStore
//
// Copyright © 2016 John Rommel Estropia
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in all
// copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
// SOFTWARE.
//
#import "BridgingTests.h"
#import <CoreStore/CoreStore.h>
#import <CoreStore/CoreStore-Swift.h>
#import "CoreStoreTests-Swift.h"
@import CoreData;
// MARK: - BridgingTests
@implementation BridgingTests
- (void)test_ThatFlags_HaveCorrectValues {
XCTAssertEqual(CSLocalStorageOptionsNone, 0);
XCTAssertEqual(CSLocalStorageOptionsRecreateStoreOnModelMismatch, 1);
XCTAssertEqual(CSLocalStorageOptionsPreventProgressiveMigration, 2);
XCTAssertEqual(CSLocalStorageOptionsAllowSynchronousLightweightMigration, 4);
}
- (void)test_ThatKeyPaths_AreCorrect {
XCTAssertEqualObjects(CSKeyPath(TestEntity1, testNumber), @"testNumber");
XCTAssertEqualObjects(CSKeyPath(TestEntity1, testString), @"testString");
XCTAssertEqualObjects(CSKeyPathOperator(count, TestEntity1, testString), @"@count.testString");
XCTAssertEqualObjects(CSKeyPathOperator(max, TestEntity1, testNumber), @"@max.testNumber");
}
- (void)test_ThatFromClauses_BridgeCorrectly {
{
CSFrom *from = CSFromClass([TestEntity1 class]);
XCTAssertEqualObjects(from.entityClass, [TestEntity1 class]);
XCTAssertNil(from.configurations);
}
{
CSFrom *from = CSFromClass([TestEntity1 class], [NSNull null]);
XCTAssertEqualObjects(from.entityClass, [TestEntity1 class]);
NSArray *configurations = @[[NSNull null]];
XCTAssertEqualObjects(from.configurations, configurations);
}
{
CSFrom *from = CSFromClass([TestEntity1 class], @"Config1");
XCTAssertEqualObjects(from.entityClass, [TestEntity1 class]);
NSArray *configurations = @[@"Config1"];
XCTAssertEqualObjects(from.configurations, configurations);
}
{
CSFrom *from = CSFromClass([TestEntity1 class], @[[NSNull null], @"Config2"]);
XCTAssertEqualObjects(from.entityClass, [TestEntity1 class]);
NSArray *configurations = @[[NSNull null], @"Config2"];
XCTAssertEqualObjects(from.configurations, configurations);
}
}
- (void)test_ThatWhereClauses_BridgeCorrectly {
{
CSWhere *where = CSWhereFormat(@"%K == %@", @"key", @"value");
NSPredicate *predicate = [NSPredicate predicateWithFormat:@"%K == %@", @"key", @"value"];
XCTAssertEqualObjects(where.predicate, predicate);
}
{
CSWhere *where = CSWhereValue(YES);
NSPredicate *predicate = [NSPredicate predicateWithValue:YES];
XCTAssertEqualObjects(where.predicate, predicate);
}
{
CSWhere *where = CSWherePredicate([NSPredicate predicateWithFormat:@"%K == %@", @"key", @"value"]);
NSPredicate *predicate = [NSPredicate predicateWithFormat:@"%K == %@", @"key", @"value"];
XCTAssertEqualObjects(where.predicate, predicate);
}
}
- (void)test_ThatOrderByClauses_BridgeCorrectly {
{
CSOrderBy *orderBy = CSOrderByKey(CSSortAscending(@"key"));
XCTAssertEqualObjects(orderBy.sortDescriptors, @[[NSSortDescriptor sortDescriptorWithKey:@"key" ascending:YES]]);
}
{
CSOrderBy *orderBy = CSOrderByKey(CSSortDescending(@"key"));
XCTAssertEqualObjects(orderBy.sortDescriptors, @[[NSSortDescriptor sortDescriptorWithKey:@"key" ascending:NO]]);
}
{
CSOrderBy *orderBy = CSOrderByKeys(CSSortAscending(@"key1"), CSSortDescending(@"key2"), nil);
NSArray *sortDescriptors = @[[NSSortDescriptor sortDescriptorWithKey:@"key1" ascending:YES],
[NSSortDescriptor sortDescriptorWithKey:@"key2" ascending:NO]];
XCTAssertEqualObjects(orderBy.sortDescriptors, sortDescriptors);
}
}
- (void)test_ThatGroupByClauses_BridgeCorrectly {
{
CSGroupBy *groupBy = CSGroupByKeyPath(@"key");
XCTAssertEqualObjects(groupBy.keyPaths, @[@"key"]);
}
{
CSGroupBy *groupBy = CSGroupByKeyPaths(@[@"key1", @"key2"]);
NSArray *keyPaths = @[@"key1", @"key2"];
XCTAssertEqualObjects(groupBy.keyPaths, keyPaths);
}
}
- (void)test_ThatTweakClauses_BridgeCorrectly {
CSTweak *tweak = CSTweakRequest(^(NSFetchRequest * _Nonnull fetchRequest) {
fetchRequest.fetchLimit = 100;
});
NSFetchRequest *request = [NSFetchRequest new];
tweak.block(request);
XCTAssertEqual(request.fetchLimit, 100);
}
- (void)test_ThatIntoClauses_BridgeCorrectly {
{
CSInto *into = CSIntoClass([TestEntity1 class]);
XCTAssertEqualObjects(into.entityClass, [TestEntity1 class]);
}
{
CSInto *into = CSIntoClass([TestEntity1 class], [NSNull null]);
XCTAssertEqualObjects(into.entityClass, [TestEntity1 class]);
XCTAssertNil(into.configuration);
}
{
CSInto *into = CSIntoClass([TestEntity1 class], @"Config1");
XCTAssertEqualObjects(into.entityClass, [TestEntity1 class]);
XCTAssertEqualObjects(into.configuration, @"Config1");
}
}
- (void)test_ThatDataStacks_BridgeCorrectly {
CSDataStack *dataStack = [[CSDataStack alloc]
initWithModelName:@"Model"
bundle:[NSBundle bundleForClass:[self class]]
versionChain:nil];
XCTAssertNotNil(dataStack);
[CSCoreStore setDefaultStack:dataStack];
XCTAssertTrue([dataStack isEqual:[CSCoreStore defaultStack]]);
}
- (void)test_ThatStorages_BridgeCorrectly {
NSError *memoryError;
CSInMemoryStore *memoryStorage = [CSCoreStore
addInMemoryStorageAndWait:[CSInMemoryStore new]
error:&memoryError];
XCTAssertNotNil(memoryStorage);
XCTAssertEqualObjects([[memoryStorage class] storeType], [CSInMemoryStore storeType]);
XCTAssertEqualObjects([[memoryStorage class] storeType], NSInMemoryStoreType);
XCTAssertNil(memoryStorage.configuration);
XCTAssertNil(memoryStorage.storeOptions);
XCTAssertNil(memoryError);
NSError *sqliteError;
CSSQLiteStore *sqliteStorage = [CSCoreStore
addSQLiteStorageAndWait:[CSSQLiteStore new]
error:&sqliteError];
XCTAssertNotNil(sqliteStorage);
XCTAssertEqualObjects([[sqliteStorage class] storeType], [CSSQLiteStore storeType]);
XCTAssertEqualObjects([[sqliteStorage class] storeType], NSSQLiteStoreType);
XCTAssertNil(sqliteStorage.configuration);
XCTAssertEqualObjects(sqliteStorage.storeOptions, @{ NSSQLitePragmasOption: @{ @"journal_mode": @"WAL" } });
XCTAssertNil(sqliteError);
}
- (void)test_ThatTransactions_BridgeCorrectly {
[CSCoreStore
setDefaultStack:[[CSDataStack alloc]
initWithModelName:@"Model"
bundle:[NSBundle bundleForClass:[self class]]
versionChain:nil]];
[CSCoreStore
addInMemoryStorageAndWait:[CSInMemoryStore new]
error:nil];
{
CSUnsafeDataTransaction *transaction = [CSCoreStore beginUnsafe];
XCTAssertNotNil(transaction);
XCTAssert([transaction isKindOfClass:[CSUnsafeDataTransaction class]]);
}
{
XCTestExpectation *expectation = [self expectationWithDescription:@"sync"];
[CSCoreStore beginSynchronous:^(CSSynchronousDataTransaction * _Nonnull transaction) {
XCTAssertNotNil(transaction);
XCTAssert([transaction isKindOfClass:[CSSynchronousDataTransaction class]]);
[expectation fulfill];
}];
}
{
XCTestExpectation *expectation = [self expectationWithDescription:@"async"];
[CSCoreStore beginAsynchronous:^(CSAsynchronousDataTransaction * _Nonnull transaction) {
XCTAssertNotNil(transaction);
XCTAssert([transaction isKindOfClass:[CSAsynchronousDataTransaction class]]);
[expectation fulfill];
}];
}
[self waitForExpectationsWithTimeout:10 handler:nil];
}
@end

View File

@@ -1,93 +0,0 @@
//
// ConvenienceTests.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 CoreData
import XCTest
@testable
import CoreStore
// MARK: - ConvenienceTests
class ConvenienceTests: BaseTestCase {
@objc
dynamic func test_ThatDataStacks_CanCreateFetchedResultsControllers() {
self.prepareStack { (stack) in
let controller = stack.createFetchedResultsController(
From<TestEntity1>(),
SectionBy(#keyPath(TestEntity1.testString)),
Where<TestEntity1>("%@ > %d", #keyPath(TestEntity1.testEntityID), 100),
OrderBy<TestEntity1>(.ascending(#keyPath(TestEntity1.testString))),
Tweak { $0.fetchLimit = 10 }
)
XCTAssertEqual(controller.managedObjectContext, stack.mainContext)
XCTAssertEqual(controller.fetchRequest.entity?.managedObjectClassName, NSStringFromClass(TestEntity1.self))
XCTAssertEqual(controller.sectionNameKeyPath, #keyPath(TestEntity1.testString))
XCTAssertEqual(
controller.fetchRequest.sortDescriptors!,
OrderBy<TestEntity1>(.ascending(#keyPath(TestEntity1.testString))).sortDescriptors
)
XCTAssertEqual(
controller.fetchRequest.predicate,
Where<TestEntity1>("%@ > %d", #keyPath(TestEntity1.testEntityID), 100).predicate
)
XCTAssertEqual(controller.fetchRequest.fetchLimit, 10)
}
}
@objc
dynamic func test_ThatUnsafeDataTransactions_CanCreateFetchedResultsControllers() {
self.prepareStack { (stack) in
withExtendedLifetime(stack.beginUnsafe()) { (transaction: UnsafeDataTransaction) in
let controller = transaction.createFetchedResultsController(
From<TestEntity1>(),
SectionBy(#keyPath(TestEntity1.testString)),
Where<TestEntity1>("%@ > %d", #keyPath(TestEntity1.testEntityID), 100),
OrderBy<TestEntity1>(.ascending(#keyPath(TestEntity1.testString))),
Tweak { $0.fetchLimit = 10 }
)
XCTAssertEqual(controller.managedObjectContext, transaction.context)
XCTAssertEqual(controller.fetchRequest.entity?.managedObjectClassName, NSStringFromClass(TestEntity1.self))
XCTAssertEqual(controller.sectionNameKeyPath, #keyPath(TestEntity1.testString))
XCTAssertEqual(
controller.fetchRequest.sortDescriptors!,
OrderBy<TestEntity1>(.ascending(#keyPath(TestEntity1.testString))).sortDescriptors
)
XCTAssertEqual(
controller.fetchRequest.predicate,
Where<TestEntity1>("%@ > %d", #keyPath(TestEntity1.testEntityID), 100).predicate
)
XCTAssertEqual(controller.fetchRequest.fetchLimit, 10)
}
}
}
}

View File

@@ -0,0 +1,5 @@
//
// Use this file to import your target's public headers that you would like to expose to Swift.
//
#import "BridgingTests.h"

View File

@@ -1,535 +0,0 @@
//
// DynamicModelTests.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
#if os(macOS)
typealias Color = NSColor
#else
typealias Color = UIColor
#endif
class Animal: CoreStoreObject {
@Field.Stored("species")
var species: String = "Swift"
@Field.Coded("color", coder: FieldCoders.NSCoding.self)
var color: Color? = .blue
@Field.Relationship("master")
var master: Person?
}
class Dog: Animal {
static let commonNicknames = ["Spot", "Benjie", "Max", "Milo"]
@Field.Stored(
"nickname",
dynamicInitialValue: {
commonNicknames.randomElement()!
}
)
var nickname: String
@Field.Stored("age")
var age: Int = 1
@Field.Relationship("friends")
var friends: [Dog]
@Field.Relationship("friendedBy", inverse: \.$friends)
var friendedBy: Set<Dog>
}
struct CustomType {
var string = "customString"
}
enum Job: String, CaseIterable {
case unemployed
case engineer
case doctor
case lawyer
init?(data: Data) {
guard
let rawValue = String(data: data, encoding: .utf8),
let value = Self.init(rawValue: rawValue)
else {
return nil
}
self = value
}
func toData() -> Data {
return Data(self.rawValue.utf8)
}
}
class Person: CoreStoreObject {
@Field.Stored(
"title",
customSetter: { (object, field, newValue) in
field.primitiveValue = newValue
object.$displayName.primitiveValue = nil
}
)
var title: String = "Mr."
@Field.Stored(
"name",
customSetter: { (object, field, newValue) in
field.primitiveValue = newValue
object.$displayName.primitiveValue = nil
}
)
var name: String = ""
@Field.Virtual(
"displayName",
customGetter: Person.getDisplayName(_:_:),
affectedByKeyPaths: Person.keyPathsAffectingDisplayName()
)
var displayName: String?
@Field.Virtual(
"customType",
customGetter: { (object, field) in
if let value = field.primitiveValue {
return value
}
let value = CustomType()
field.primitiveValue = value
return value
}
)
var customField: CustomType
@Field.Coded(
"job",
coder: (
encode: { $0.toData() },
decode: { $0.flatMap(Job.init(data:)) ?? .unemployed }
),
dynamicInitialValue: {
Job.allCases.randomElement()!
}
)
var job: Job
@Field.Relationship("spouse")
var spouse: Person?
@Field.Relationship("pets", inverse: \.$master)
var pets: Set<Animal>
@Field.Relationship("_spouseInverse", inverse: \.$spouse)
private var spouseInverse: Person?
private static func getDisplayName(_ object: ObjectProxy<Person>, _ field: ObjectProxy<Person>.FieldProxy<String?>) -> String? {
if let value = field.primitiveValue {
return value
}
let title = object.$title.value
let name = object.$name.value
let value = "\(title) \(name)"
field.primitiveValue = value
return value
}
private static func keyPathsAffectingDisplayName() -> Set<String> {
return [
String(keyPath: \Person.$title),
String(keyPath: \Person.$name)
]
}
}
// MARK: - DynamicModelTests
class DynamicModelTests: BaseTestDataTestCase {
@objc
dynamic func test_ThatDynamicModels_CanBeDeclaredCorrectly() {
let dataStack = DataStack(
CoreStoreSchema(
modelVersion: "V1",
entities: [
Entity<Animal>("Animal"),
Entity<Dog>("Dog", indexes: [[\Dog.$nickname, \Dog.$age]]),
Entity<Person>("Person")
],
versionLock: [
"Animal": [0x1b59d511019695cf, 0xdeb97e86c5eff179, 0x1cfd80745646cb3, 0x4ff99416175b5b9a],
"Dog": [0xad6de93adc5565d, 0x7897e51253eba5a3, 0xd12b9ce0b13600f3, 0x5a4827cd794cd15e],
"Person": [0xf3e6ba6016bbedc6, 0x50dedf64f0eba490, 0xa32088a0ee83468d, 0xb72d1d0b37bd0992]
]
)
)
self.prepareStack(dataStack, configurations: [nil]) { (stack) in
let k1 = String(keyPath: \Animal.$species)
XCTAssertEqual(k1, "species")
let k2 = String(keyPath: \Dog.$species)
XCTAssertEqual(k2, "species")
let k3 = String(keyPath: \Dog.$nickname)
XCTAssertEqual(k3, "nickname")
let updateDone = self.expectation(description: "update-done")
let fetchDone = self.expectation(description: "fetch-done")
let willSetPriorObserverDone = self.expectation(description: "willSet-observe-prior-done")
let willSetNotPriorObserverDone = self.expectation(description: "willSet-observe-notPrior-done")
let didSetObserverDone = self.expectation(description: "didSet-observe-done")
stack.perform(
asynchronous: { (transaction) in
let animal = transaction.create(Into<Animal>())
XCTAssertEqual(animal.species, "Swift")
XCTAssertTrue(type(of: animal.species) == String.self)
XCTAssertEqual(animal.color, Color.blue)
animal.species = "Sparrow"
XCTAssertEqual(animal.species, "Sparrow")
animal.color = .yellow
XCTAssertEqual(animal.color, Color.yellow)
for property in Animal.metaProperties(includeSuperclasses: true) {
switch property.keyPath {
case String(keyPath: \Animal.$species):
XCTAssertTrue(property is FieldContainer<Animal>.Stored<String>)
case String(keyPath: \Animal.$master):
XCTAssertTrue(property is FieldContainer<Animal>.Relationship<Person?>)
case String(keyPath: \Animal.$color):
XCTAssertTrue(property is FieldContainer<Animal>.Coded<Color?>)
default:
XCTFail("Unknown KeyPath: \"\(property.keyPath)\"")
}
}
let dog = transaction.create(Into<Dog>())
XCTAssertEqual(dog.species, "Swift")
XCTAssertEqual(dog.age, 1)
XCTAssertTrue(Dog.commonNicknames.contains(dog.nickname))
for property in Dog.metaProperties(includeSuperclasses: true) {
switch property.keyPath {
case String(keyPath: \Dog.$species):
XCTAssertTrue(property is FieldContainer<Animal>.Stored<String>)
case String(keyPath: \Dog.$master):
XCTAssertTrue(property is FieldContainer<Animal>.Relationship<Person?>)
case String(keyPath: \Dog.$color):
XCTAssertTrue(property is FieldContainer<Animal>.Coded<Color?>)
case String(keyPath: \Dog.$nickname):
XCTAssertTrue(property is FieldContainer<Dog>.Stored<String>)
case String(keyPath: \Dog.$age):
XCTAssertTrue(property is FieldContainer<Dog>.Stored<Int>)
case String(keyPath: \Dog.$friends):
XCTAssertTrue(property is FieldContainer<Dog>.Relationship<[Dog]>)
case String(keyPath: \Dog.$friendedBy):
XCTAssertTrue(property is FieldContainer<Dog>.Relationship<Set<Dog>>)
default:
XCTFail("Unknown KeyPath: \"\(property.keyPath)\"")
}
}
let didSetObserver = dog.observe(\.$species, options: [.new, .old]) { (object, change) in
XCTAssertEqual(object, dog)
XCTAssertEqual(change.kind, .setting)
XCTAssertEqual(change.newValue, "Dog")
XCTAssertEqual(change.oldValue, "Swift")
XCTAssertFalse(change.isPrior)
XCTAssertEqual(object.species, "Dog")
didSetObserverDone.fulfill()
}
let willSetObserver = dog.observe(\.$species, options: [.new, .old, .prior]) { (object, change) in
XCTAssertEqual(object, dog)
XCTAssertEqual(change.kind, .setting)
XCTAssertEqual(change.oldValue, "Swift")
if change.isPrior {
XCTAssertNil(change.newValue)
XCTAssertEqual(object.species, "Swift")
willSetPriorObserverDone.fulfill()
}
else {
XCTAssertEqual(change.newValue, "Dog")
XCTAssertEqual(object.species, "Dog")
willSetNotPriorObserverDone.fulfill()
}
}
dog.species = "Dog"
XCTAssertEqual(dog.species, "Dog")
didSetObserver.invalidate()
willSetObserver.invalidate()
dog.nickname = "Spot"
XCTAssertEqual(dog.nickname, "Spot")
let person = transaction.create(Into<Person>())
XCTAssertTrue(person.pets.isEmpty)
XCTAssertEqual(person.customField.string, "customString")
let initialJob = person.job
XCTAssertTrue(Job.allCases.contains(initialJob))
XCTAssertEqual(
person.rawObject!
.runtimeType()
.keyPathsForValuesAffectingValue(forKey: "displayName"),
["title", "name"]
)
person.name = "Joe"
XCTAssertEqual(person.rawObject!.value(forKey: "name") as! String?, "Joe")
XCTAssertEqual(person.rawObject!.value(forKey: "displayName") as! String?, "Mr. Joe")
person.rawObject!.setValue("AAAA", forKey: "displayName")
XCTAssertEqual(person.rawObject!.value(forKey: "displayName") as! String?, "AAAA")
person.name = "John"
XCTAssertEqual(person.name, "John")
XCTAssertEqual(person.displayName, "Mr. John") // Custom getter
let personSnapshot1 = person.asSnapshot(in: transaction)!
XCTAssertEqual(person.name, personSnapshot1.$name)
XCTAssertEqual(person.title, personSnapshot1.$title)
XCTAssertEqual(person.displayName, personSnapshot1.$displayName)
XCTAssertEqual(person.job, personSnapshot1.$job)
person.title = "Sir"
XCTAssertEqual(person.displayName, "Sir John")
XCTAssertEqual(personSnapshot1.$name, "John")
XCTAssertEqual(personSnapshot1.$title, "Mr.")
XCTAssertEqual(personSnapshot1.$displayName, "Mr. John")
person.customField.string = "newCustomString"
XCTAssertEqual(person.customField.string, "newCustomString")
person.job = .engineer
XCTAssertEqual(person.job, .engineer)
let personSnapshot2 = person.asSnapshot(in: transaction)!
XCTAssertEqual(person.name, personSnapshot2.$name)
XCTAssertEqual(person.title, personSnapshot2.$title)
XCTAssertEqual(person.displayName, personSnapshot2.$displayName)
XCTAssertEqual(person.job, personSnapshot2.$job)
var personSnapshot3 = personSnapshot2
personSnapshot3.$name = "James"
XCTAssertEqual(personSnapshot1.$name, "John")
XCTAssertEqual(personSnapshot1.$displayName, "Mr. John")
XCTAssertEqual(personSnapshot1.$job, initialJob)
XCTAssertEqual(personSnapshot2.$name, "John")
XCTAssertEqual(personSnapshot2.$displayName, "Sir John")
XCTAssertEqual(personSnapshot2.$job, .engineer)
XCTAssertEqual(personSnapshot3.$name, "James")
XCTAssertEqual(personSnapshot3.$displayName, "Sir John")
XCTAssertEqual(personSnapshot3.$job, .engineer)
person.pets.insert(dog)
XCTAssertEqual(person.pets.count, 1)
XCTAssertEqual(person.pets.first, dog)
XCTAssertEqual(person.pets.first?.master, person)
XCTAssertEqual(dog.master, person)
XCTAssertEqual(dog.master?.pets.first, dog)
},
success: { _ in
let person = try! stack.fetchOne(From<Person>())
XCTAssertNotNil(person)
let personPublisher = person!.asPublisher(in: stack)
XCTAssertEqual(personPublisher.$name, "John")
XCTAssertEqual(personPublisher.$displayName, "Sir John")
XCTAssertEqual(personPublisher.$job, .engineer)
updateDone.fulfill()
},
failure: { _ in
XCTFail()
}
)
stack.perform(
asynchronous: { (transaction) in
let p1 = Where<Animal>({ $0.$species == "Sparrow" })
XCTAssertEqual(p1.predicate, NSPredicate(format: "%K == %@", "species", "Sparrow"))
let bird = try transaction.fetchOne(From<Animal>(), p1)
XCTAssertNotNil(bird)
XCTAssertEqual(bird!.species, "Sparrow")
XCTAssertEqual(bird!.color, Color.yellow)
let p2 = Where<Dog>({ $0.$nickname == "Spot" })
XCTAssertEqual(p2.predicate, NSPredicate(format: "%K == %@", "nickname", "Spot"))
let dog = try transaction.fetchOne(From<Dog>().where(\.$nickname == "Spot"))
XCTAssertNotNil(dog)
XCTAssertEqual(dog!.nickname, "Spot")
XCTAssertEqual(dog!.species, "Dog")
let person = try transaction.fetchOne(From<Person>())
XCTAssertNotNil(person)
XCTAssertEqual(person!.name, "John")
XCTAssertEqual(person!.title, "Sir")
XCTAssertEqual(person!.displayName, "Sir John")
XCTAssertEqual(person!.customField.string, "customString")
XCTAssertEqual(person!.job, .engineer)
XCTAssertEqual(person!.pets.first, dog)
let p3 = Where<Dog>({ $0.$age == 10 })
XCTAssertEqual(p3.predicate, NSPredicate(format: "%K == %d", "age", 10))
let totalAge = try transaction.queryValue(
From<Dog>().select(Int.self, .sum(\.$age))
)
XCTAssertEqual(totalAge, 1)
_ = try transaction.fetchAll(
From<Dog>()
.where(\Animal.$species == "Dog" && \Dog.$age == 10)
)
_ = try transaction.fetchAll(
From<Dog>()
.where(\Dog.$age == 10 && \Animal.$species == "Dog")
.orderBy(.ascending({ $0.$species }))
)
_ = try transaction.fetchAll(
From<Dog>(),
Where<Dog>({ $0.$age > 10 && $0.$age <= 15 })
)
_ = try transaction.fetchAll(
From<Dog>(),
Where<Dog>({ $0.$species == "Dog" && $0.$age == 10 })
)
_ = try transaction.fetchAll(
From<Dog>(),
Where<Dog>({ $0.$age == 10 && $0.$species == "Dog" })
)
_ = try transaction.fetchAll(
From<Dog>(),
Where<Dog>({ $0.$age > 10 && $0.$age <= 15 })
)
_ = try transaction.fetchAll(
From<Dog>(),
(\Dog.$age > 10 && \Dog.$age <= 15)
)
},
success: { _ in
fetchDone.fulfill()
},
failure: { _ in
XCTFail()
}
)
}
self.waitForExpectations(timeout: 10, handler: { _ in })
self.addTeardownBlock {
dataStack.unsafeRemoveAllPersistentStoresAndWait()
}
}
@objc
dynamic func test_ThatDynamicModelKeyPaths_CanBeCreated() {
XCTAssertEqual(String(keyPath: \Animal.$species), "species")
XCTAssertEqual(String(keyPath: \Dog.$species), "species")
}
@nonobjc
func prepareStack(_ dataStack: DataStack, configurations: [ModelConfiguration] = [nil], _ closure: (_ dataStack: DataStack) -> Void) {
do {
try configurations.forEach { (configuration) in
try dataStack.addStorageAndWait(
SQLiteStore(
fileURL: SQLiteStore.defaultRootDirectory
.appendingPathComponent(UUID().uuidString)
.appendingPathComponent("\(Self.self)_\((configuration ?? "-null-")).sqlite"),
configuration: configuration,
localStorageOptions: .recreateStoreOnModelMismatch
)
)
}
}
catch let error as NSError {
XCTFail(error.coreStoreDumpString)
}
closure(dataStack)
}
}

View File

@@ -2,7 +2,7 @@
// ErrorTests.swift
// CoreStore
//
// Copyright © 2018 John Rommel Estropia
// Copyright © 2016 John Rommel Estropia
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
@@ -36,100 +36,103 @@ final class ErrorTests: XCTestCase {
@objc
dynamic func test_ThatUnknownErrors_BridgeCorrectly() {
let error = CoreStoreError.unknown
let error = CoreStoreError.Unknown
XCTAssertEqual((error as NSError).domain, CoreStoreErrorDomain)
XCTAssertEqual((error as NSError).code, CoreStoreErrorCode.unknownError.rawValue)
XCTAssertEqual((error as NSError).code, CoreStoreErrorCode.UnknownError.rawValue)
let userInfo: NSDictionary = [:]
let objcError = error as NSError
let objcError = error.bridgeToObjectiveC
XCTAssertEqual(error, objcError.bridgeToSwift)
XCTAssertEqual(objcError.domain, CoreStoreErrorDomain)
XCTAssertEqual(objcError.code, CoreStoreErrorCode.unknownError.rawValue)
XCTAssertEqual(objcError.userInfo as NSDictionary, userInfo)
XCTAssertEqual(objcError.code, CoreStoreErrorCode.UnknownError.rawValue)
XCTAssertEqual(objcError.userInfo, userInfo)
let objcError2 = CoreStoreError(objcError) as NSError
let objcError2 = objcError.bridgeToSwift.bridgeToObjectiveC
XCTAssertEqual(error, objcError2.bridgeToSwift)
XCTAssertEqual(objcError2.domain, CoreStoreErrorDomain)
XCTAssertEqual(objcError2.code, CoreStoreErrorCode.unknownError.rawValue)
XCTAssertEqual(objcError2.userInfo as NSDictionary, userInfo)
XCTAssertEqual(objcError2.code, CoreStoreErrorCode.UnknownError.rawValue)
XCTAssertEqual(objcError2.userInfo, userInfo)
}
@objc
dynamic func test_ThatDifferentStorageExistsAtURLErrors_BridgeCorrectly() {
let dummyURL = URL(string: "file:///test1/test2.sqlite")!
let dummyURL = NSURL(string: "file:///test1/test2.sqlite")!
let error = CoreStoreError.differentStorageExistsAtURL(existingPersistentStoreURL: dummyURL)
let error = CoreStoreError.DifferentStorageExistsAtURL(existingPersistentStoreURL: dummyURL)
XCTAssertEqual((error as NSError).domain, CoreStoreErrorDomain)
XCTAssertEqual((error as NSError).code, CoreStoreErrorCode.differentStorageExistsAtURL.rawValue)
XCTAssertEqual((error as NSError).code, CoreStoreErrorCode.DifferentPersistentStoreExistsAtURL.rawValue)
let userInfo: NSDictionary = [
"existingPersistentStoreURL": dummyURL
]
let objcError = error as NSError
let objcError = error.bridgeToObjectiveC
XCTAssertEqual(error, objcError.bridgeToSwift)
XCTAssertEqual(objcError.domain, CoreStoreErrorDomain)
XCTAssertEqual(objcError.code, CoreStoreErrorCode.differentStorageExistsAtURL.rawValue)
XCTAssertEqual(objcError.userInfo as NSDictionary, userInfo)
let objcError2 = CoreStoreError(objcError) as NSError
XCTAssertEqual(objcError.code, CoreStoreErrorCode.DifferentPersistentStoreExistsAtURL.rawValue)
XCTAssertEqual(objcError.userInfo, userInfo)
let objcError2 = objcError.bridgeToSwift.bridgeToObjectiveC
XCTAssertEqual(error, objcError2.bridgeToSwift)
XCTAssertEqual(objcError2.domain, CoreStoreErrorDomain)
XCTAssertEqual(objcError2.code, CoreStoreErrorCode.differentStorageExistsAtURL.rawValue)
XCTAssertEqual(objcError2.userInfo as NSDictionary, userInfo)
XCTAssertEqual(objcError2.code, CoreStoreErrorCode.DifferentPersistentStoreExistsAtURL.rawValue)
XCTAssertEqual(objcError2.userInfo, userInfo)
}
@objc
dynamic func test_ThatMappingModelNotFoundErrors_BridgeCorrectly() {
let dummyURL = URL(string: "file:///test1/test2.sqlite")!
let dummyURL = NSURL(string: "file:///test1/test2.sqlite")!
let schemaHistory = SchemaHistory(
XcodeDataModelSchema.from(
modelName: "Model",
bundle: Bundle.module
)
)
let model = NSManagedObjectModel.fromBundle(NSBundle(forClass: self.dynamicType), modelName: "Model")
let version = "1.0.0"
let error = CoreStoreError.mappingModelNotFound(localStoreURL: dummyURL, targetModel: schemaHistory.rawModel, targetModelVersion: version)
let error = CoreStoreError.MappingModelNotFound(localStoreURL: dummyURL, targetModel: model, targetModelVersion: version)
XCTAssertEqual((error as NSError).domain, CoreStoreErrorDomain)
XCTAssertEqual((error as NSError).code, CoreStoreErrorCode.mappingModelNotFound.rawValue)
XCTAssertEqual((error as NSError).code, CoreStoreErrorCode.MappingModelNotFound.rawValue)
let userInfo: NSDictionary = [
"localStoreURL": dummyURL,
"targetModel": schemaHistory.rawModel,
"targetModel": model,
"targetModelVersion": version
]
let objcError = error as NSError
let objcError = error.bridgeToObjectiveC
XCTAssertEqual(error, objcError.bridgeToSwift)
XCTAssertEqual(objcError.domain, CoreStoreErrorDomain)
XCTAssertEqual(objcError.code, CoreStoreErrorCode.mappingModelNotFound.rawValue)
XCTAssertEqual(objcError.userInfo as NSDictionary, userInfo)
let objcError2 = CoreStoreError(objcError) as NSError
XCTAssertEqual(objcError.code, CoreStoreErrorCode.MappingModelNotFound.rawValue)
XCTAssertEqual(objcError.userInfo, userInfo)
let objcError2 = objcError.bridgeToSwift.bridgeToObjectiveC
XCTAssertEqual(error, objcError2.bridgeToSwift)
XCTAssertEqual(objcError2.domain, CoreStoreErrorDomain)
XCTAssertEqual(objcError2.code, CoreStoreErrorCode.mappingModelNotFound.rawValue)
XCTAssertEqual(objcError2.userInfo as NSDictionary, userInfo)
XCTAssertEqual(objcError2.code, CoreStoreErrorCode.MappingModelNotFound.rawValue)
XCTAssertEqual(objcError2.userInfo, userInfo)
}
@objc
dynamic func test_ThatProgressiveMigrationRequiredErrors_BridgeCorrectly() {
let dummyURL = URL(string: "file:///test1/test2.sqlite")!
let dummyURL = NSURL(string: "file:///test1/test2.sqlite")!
let error = CoreStoreError.progressiveMigrationRequired(localStoreURL: dummyURL)
let error = CoreStoreError.ProgressiveMigrationRequired(localStoreURL: dummyURL)
XCTAssertEqual((error as NSError).domain, CoreStoreErrorDomain)
XCTAssertEqual((error as NSError).code, CoreStoreErrorCode.progressiveMigrationRequired.rawValue)
XCTAssertEqual((error as NSError).code, CoreStoreErrorCode.ProgressiveMigrationRequired.rawValue)
let userInfo: NSDictionary = [
"localStoreURL": dummyURL
]
let objcError = error as NSError
let objcError = error.bridgeToObjectiveC
XCTAssertEqual(error, objcError.bridgeToSwift)
XCTAssertEqual(objcError.domain, CoreStoreErrorDomain)
XCTAssertEqual(objcError.code, CoreStoreErrorCode.progressiveMigrationRequired.rawValue)
XCTAssertEqual(objcError.userInfo as NSDictionary, userInfo)
let objcError2 = CoreStoreError(objcError) as NSError
XCTAssertEqual(objcError.code, CoreStoreErrorCode.ProgressiveMigrationRequired.rawValue)
XCTAssertEqual(objcError.userInfo, userInfo)
let objcError2 = objcError.bridgeToSwift.bridgeToObjectiveC
XCTAssertEqual(error, objcError2.bridgeToSwift)
XCTAssertEqual(objcError2.domain, CoreStoreErrorDomain)
XCTAssertEqual(objcError2.code, CoreStoreErrorCode.progressiveMigrationRequired.rawValue)
XCTAssertEqual(objcError2.userInfo as NSDictionary, userInfo)
XCTAssertEqual(objcError2.code, CoreStoreErrorCode.ProgressiveMigrationRequired.rawValue)
XCTAssertEqual(objcError2.userInfo, userInfo)
}
@objc
@@ -141,24 +144,26 @@ final class ErrorTests: XCTestCase {
userInfo: [
"key1": "value1",
"key2": 2,
"key3": Date()
"key3": NSDate()
]
)
let error = CoreStoreError(internalError)
XCTAssertEqual((error as NSError).domain, CoreStoreErrorDomain)
XCTAssertEqual((error as NSError).code, CoreStoreErrorCode.internalError.rawValue)
XCTAssertEqual((error as NSError).code, CoreStoreErrorCode.InternalError.rawValue)
let userInfo: NSDictionary = [
"NSError": internalError
]
let objcError = error as NSError
let objcError = error.bridgeToObjectiveC
XCTAssertEqual(error, objcError.bridgeToSwift)
XCTAssertEqual(objcError.domain, CoreStoreErrorDomain)
XCTAssertEqual(objcError.code, CoreStoreErrorCode.internalError.rawValue)
XCTAssertEqual(objcError.userInfo as NSDictionary, userInfo)
let objcError2 = CoreStoreError(objcError) as NSError
XCTAssertEqual(objcError.code, CoreStoreErrorCode.InternalError.rawValue)
XCTAssertEqual(objcError.userInfo, userInfo)
let objcError2 = objcError.bridgeToSwift.bridgeToObjectiveC
XCTAssertEqual(error, objcError2.bridgeToSwift)
XCTAssertEqual(objcError2.domain, CoreStoreErrorDomain)
XCTAssertEqual(objcError2.code, CoreStoreErrorCode.internalError.rawValue)
XCTAssertEqual(objcError2.userInfo as NSDictionary, userInfo)
XCTAssertEqual(objcError2.code, CoreStoreErrorCode.InternalError.rawValue)
XCTAssertEqual(objcError2.userInfo, userInfo)
}
}

File diff suppressed because it is too large Load Diff

View File

@@ -2,7 +2,7 @@
// FromTests.swift
// CoreStore
//
// Copyright © 2018 John Rommel Estropia
// Copyright © 2016 John Rommel Estropia
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
@@ -23,7 +23,6 @@
// SOFTWARE.
//
import CoreData
import XCTest
@testable
@@ -39,7 +38,7 @@ final class FromTests: BaseTestCase {
do {
let from = From<NSManagedObject>()
let from = From()
XCTAssert(from.entityClass === NSManagedObject.self)
XCTAssertNil(from.configurations)
}
@@ -75,31 +74,33 @@ final class FromTests: BaseTestCase {
let from = From<TestEntity1>()
let request = Internals.CoreStoreFetchRequest<NSFetchRequestResult>()
try from.applyToFetchRequest(request, context: dataStack.mainContext)
let request = NSFetchRequest()
let storesFound = from.applyToFetchRequest(request, context: dataStack.mainContext)
XCTAssertTrue(storesFound)
XCTAssertNotNil(request.entity)
XCTAssertNotNil(request.safeAffectedStores())
XCTAssertNotNil(request.affectedStores)
XCTAssert(from.entityClass == NSClassFromString(request.entity!.managedObjectClassName))
let affectedConfigurations = request.safeAffectedStores()?.map { $0.configurationName } ?? []
let affectedConfigurations = request.affectedStores!.map { $0.configurationName }
XCTAssertEqual(affectedConfigurations, ["PF_DEFAULT_CONFIGURATION_NAME"])
}
do {
let from = From<TestEntity1>("Config1")
let request = Internals.CoreStoreFetchRequest<NSFetchRequestResult>()
self.expectError(code: .persistentStoreNotFound) {
let request = NSFetchRequest()
let storesFound = self.expectLogger([.LogWarning]) {
try from.applyToFetchRequest(request, context: dataStack.mainContext)
from.applyToFetchRequest(request, context: dataStack.mainContext)
}
XCTAssertFalse(storesFound)
XCTAssertNotNil(request.entity)
XCTAssertNotNil(request.safeAffectedStores())
XCTAssertNotNil(request.affectedStores)
XCTAssert(from.entityClass == NSClassFromString(request.entity!.managedObjectClassName))
let affectedConfigurations = request.safeAffectedStores()?.map { $0.configurationName } ?? []
let affectedConfigurations = request.affectedStores!.map { $0.configurationName }
XCTAssertTrue(affectedConfigurations.isEmpty)
}
}
@@ -114,98 +115,102 @@ final class FromTests: BaseTestCase {
let from = From<TestEntity1>()
let request = Internals.CoreStoreFetchRequest<NSFetchRequestResult>()
let storesFound: Void? = try? from.applyToFetchRequest(request, context: dataStack.mainContext)
XCTAssertNotNil(storesFound)
let request = NSFetchRequest()
let storesFound = from.applyToFetchRequest(request, context: dataStack.mainContext)
XCTAssertTrue(storesFound)
XCTAssertNotNil(request.entity)
XCTAssertNotNil(request.safeAffectedStores())
XCTAssertNotNil(request.affectedStores)
XCTAssert(from.entityClass == NSClassFromString(request.entity!.managedObjectClassName))
let affectedConfigurations = request.safeAffectedStores()?.map { $0.configurationName } ?? []
let affectedConfigurations = request.affectedStores!.map { $0.configurationName }
XCTAssertEqual(affectedConfigurations, ["Config1"])
}
do {
let from = From<TestEntity1>("Config1")
let request = Internals.CoreStoreFetchRequest<NSFetchRequestResult>()
let storesFound: Void? = try? from.applyToFetchRequest(request, context: dataStack.mainContext)
XCTAssertNotNil(storesFound)
let request = NSFetchRequest()
let storesFound = from.applyToFetchRequest(request, context: dataStack.mainContext)
XCTAssertTrue(storesFound)
XCTAssertNotNil(request.entity)
XCTAssertNotNil(request.safeAffectedStores())
XCTAssertNotNil(request.affectedStores)
XCTAssert(from.entityClass == NSClassFromString(request.entity!.managedObjectClassName))
let affectedConfigurations = request.safeAffectedStores()?.map { $0.configurationName } ?? []
let affectedConfigurations = request.affectedStores!.map { $0.configurationName }
XCTAssertEqual(affectedConfigurations, ["Config1"])
}
do {
let from = From<TestEntity1>("Config2")
let request = Internals.CoreStoreFetchRequest<NSFetchRequestResult>()
self.expectError(code: .persistentStoreNotFound) {
let request = NSFetchRequest()
let storesFound = self.expectLogger([.LogWarning]) {
try from.applyToFetchRequest(request, context: dataStack.mainContext)
from.applyToFetchRequest(request, context: dataStack.mainContext)
}
XCTAssertFalse(storesFound)
XCTAssertNotNil(request.entity)
XCTAssertNotNil(request.safeAffectedStores())
XCTAssertNotNil(request.affectedStores)
XCTAssert(from.entityClass == NSClassFromString(request.entity!.managedObjectClassName))
let affectedConfigurations = request.safeAffectedStores()?.map { $0.configurationName } ?? []
let affectedConfigurations = request.affectedStores!.map { $0.configurationName }
XCTAssertTrue(affectedConfigurations.isEmpty)
}
do {
let from = From<TestEntity2>()
let request = Internals.CoreStoreFetchRequest<NSFetchRequestResult>()
self.expectError(code: .persistentStoreNotFound) {
let request = NSFetchRequest()
let storesFound = self.expectLogger([.LogWarning]) {
try from.applyToFetchRequest(request, context: dataStack.mainContext)
from.applyToFetchRequest(request, context: dataStack.mainContext)
}
XCTAssertFalse(storesFound)
XCTAssertNotNil(request.entity)
XCTAssertNotNil(request.safeAffectedStores())
XCTAssertNotNil(request.affectedStores)
XCTAssert(from.entityClass == NSClassFromString(request.entity!.managedObjectClassName))
let affectedConfigurations = request.safeAffectedStores()?.map { $0.configurationName } ?? []
let affectedConfigurations = request.affectedStores!.map { $0.configurationName }
XCTAssertTrue(affectedConfigurations.isEmpty)
}
do {
let from = From<TestEntity2>("Config1")
let request = Internals.CoreStoreFetchRequest<NSFetchRequestResult>()
self.expectError(code: .persistentStoreNotFound) {
let request = NSFetchRequest()
let storesFound = self.expectLogger([.LogWarning]) {
try from.applyToFetchRequest(request, context: dataStack.mainContext)
from.applyToFetchRequest(request, context: dataStack.mainContext)
}
XCTAssertFalse(storesFound)
XCTAssertNotNil(request.entity)
XCTAssertNotNil(request.safeAffectedStores())
XCTAssertNotNil(request.affectedStores)
XCTAssert(from.entityClass == NSClassFromString(request.entity!.managedObjectClassName))
let affectedConfigurations = request.safeAffectedStores()?.map { $0.configurationName } ?? []
let affectedConfigurations = request.affectedStores!.map { $0.configurationName }
XCTAssertTrue(affectedConfigurations.isEmpty)
}
do {
let from = From<TestEntity2>("Config2")
let request = Internals.CoreStoreFetchRequest<NSFetchRequestResult>()
self.expectError(code: .persistentStoreNotFound) {
let request = NSFetchRequest()
let storesFound = self.expectLogger([.LogWarning]) {
try from.applyToFetchRequest(request, context: dataStack.mainContext)
from.applyToFetchRequest(request, context: dataStack.mainContext)
}
XCTAssertFalse(storesFound)
XCTAssertNotNil(request.entity)
XCTAssertNotNil(request.safeAffectedStores())
XCTAssertNotNil(request.affectedStores)
XCTAssert(from.entityClass == NSClassFromString(request.entity!.managedObjectClassName))
let affectedConfigurations = request.safeAffectedStores()?.map { $0.configurationName } ?? []
let affectedConfigurations = request.affectedStores!.map { $0.configurationName }
XCTAssertTrue(affectedConfigurations.isEmpty)
}
}
@@ -220,96 +225,99 @@ final class FromTests: BaseTestCase {
let from = From<TestEntity1>()
let request = Internals.CoreStoreFetchRequest<NSFetchRequestResult>()
let storesFound: Void? = try? from.applyToFetchRequest(request, context: dataStack.mainContext)
XCTAssertNotNil(storesFound)
let request = NSFetchRequest()
let storesFound = from.applyToFetchRequest(request, context: dataStack.mainContext)
XCTAssertTrue(storesFound)
XCTAssertNotNil(request.entity)
XCTAssertNotNil(request.safeAffectedStores())
XCTAssertNotNil(request.affectedStores)
XCTAssert(from.entityClass == NSClassFromString(request.entity!.managedObjectClassName))
let affectedConfigurations = request.safeAffectedStores()?.map { $0.configurationName } ?? []
let affectedConfigurations = request.affectedStores!.map { $0.configurationName }
XCTAssertEqual(Set(affectedConfigurations), ["PF_DEFAULT_CONFIGURATION_NAME", "Config1"] as Set)
}
do {
let from = From<TestEntity1>("Config1")
let request = Internals.CoreStoreFetchRequest<NSFetchRequestResult>()
let storesFound: Void? = try? from.applyToFetchRequest(request, context: dataStack.mainContext)
XCTAssertNotNil(storesFound)
let request = NSFetchRequest()
let storesFound = from.applyToFetchRequest(request, context: dataStack.mainContext)
XCTAssertTrue(storesFound)
XCTAssertNotNil(request.entity)
XCTAssertNotNil(request.safeAffectedStores())
XCTAssertNotNil(request.affectedStores)
XCTAssert(from.entityClass == NSClassFromString(request.entity!.managedObjectClassName))
let affectedConfigurations = request.safeAffectedStores()?.map { $0.configurationName } ?? []
let affectedConfigurations = request.affectedStores!.map { $0.configurationName }
XCTAssertEqual(affectedConfigurations, ["Config1"])
}
do {
let from = From<TestEntity1>("Config2")
let request = Internals.CoreStoreFetchRequest<NSFetchRequestResult>()
self.expectError(code: .persistentStoreNotFound) {
let request = NSFetchRequest()
let storesFound = self.expectLogger([.LogWarning]) {
try from.applyToFetchRequest(request, context: dataStack.mainContext)
from.applyToFetchRequest(request, context: dataStack.mainContext)
}
XCTAssertFalse(storesFound)
XCTAssertNotNil(request.entity)
XCTAssertNotNil(request.safeAffectedStores())
XCTAssertNotNil(request.affectedStores)
XCTAssert(from.entityClass == NSClassFromString(request.entity!.managedObjectClassName))
let affectedConfigurations = request.safeAffectedStores()?.map { $0.configurationName } ?? []
let affectedConfigurations = request.affectedStores!.map { $0.configurationName }
XCTAssertTrue(affectedConfigurations.isEmpty)
}
do {
let from = From<TestEntity2>()
let request = Internals.CoreStoreFetchRequest<NSFetchRequestResult>()
let storesFound: Void? = try? from.applyToFetchRequest(request, context: dataStack.mainContext)
XCTAssertNotNil(storesFound)
let request = NSFetchRequest()
let storesFound = from.applyToFetchRequest(request, context: dataStack.mainContext)
XCTAssertTrue(storesFound)
XCTAssertNotNil(request.entity)
XCTAssertNotNil(request.safeAffectedStores())
XCTAssertNotNil(request.affectedStores)
XCTAssert(from.entityClass == NSClassFromString(request.entity!.managedObjectClassName))
let affectedConfigurations = request.safeAffectedStores()?.map { $0.configurationName } ?? []
let affectedConfigurations = request.affectedStores!.map { $0.configurationName }
XCTAssertEqual(affectedConfigurations, ["PF_DEFAULT_CONFIGURATION_NAME"])
}
do {
let from = From<TestEntity2>("Config1")
let request = Internals.CoreStoreFetchRequest<NSFetchRequestResult>()
self.expectError(code: .persistentStoreNotFound) {
let request = NSFetchRequest()
let storesFound = self.expectLogger([.LogWarning]) {
try from.applyToFetchRequest(request, context: dataStack.mainContext)
from.applyToFetchRequest(request, context: dataStack.mainContext)
}
XCTAssertFalse(storesFound)
XCTAssertNotNil(request.entity)
XCTAssertNotNil(request.safeAffectedStores())
XCTAssertNotNil(request.affectedStores)
XCTAssert(from.entityClass == NSClassFromString(request.entity!.managedObjectClassName))
let affectedConfigurations = request.safeAffectedStores()?.map { $0.configurationName } ?? []
let affectedConfigurations = request.affectedStores!.map { $0.configurationName }
XCTAssertTrue(affectedConfigurations.isEmpty)
}
do {
let from = From<TestEntity2>("Config2")
let request = Internals.CoreStoreFetchRequest<NSFetchRequestResult>()
self.expectError(code: .persistentStoreNotFound) {
let request = NSFetchRequest()
let storesFound = self.expectLogger([.LogWarning]) {
try from.applyToFetchRequest(request, context: dataStack.mainContext)
from.applyToFetchRequest(request, context: dataStack.mainContext)
}
XCTAssertFalse(storesFound)
XCTAssertNotNil(request.entity)
XCTAssertNotNil(request.safeAffectedStores())
XCTAssertNotNil(request.affectedStores)
XCTAssert(from.entityClass == NSClassFromString(request.entity!.managedObjectClassName))
let affectedConfigurations = request.safeAffectedStores()?.map { $0.configurationName } ?? []
let affectedConfigurations = request.affectedStores!.map { $0.configurationName }
XCTAssertTrue(affectedConfigurations.isEmpty)
}
}
@@ -324,94 +332,96 @@ final class FromTests: BaseTestCase {
let from = From<TestEntity1>()
let request = Internals.CoreStoreFetchRequest<NSFetchRequestResult>()
let storesFound: Void? = try? from.applyToFetchRequest(request, context: dataStack.mainContext)
XCTAssertNotNil(storesFound)
let request = NSFetchRequest()
let storesFound = from.applyToFetchRequest(request, context: dataStack.mainContext)
XCTAssertTrue(storesFound)
XCTAssertNotNil(request.entity)
XCTAssertNotNil(request.safeAffectedStores())
XCTAssertNotNil(request.affectedStores)
XCTAssert(from.entityClass == NSClassFromString(request.entity!.managedObjectClassName))
let affectedConfigurations = request.safeAffectedStores()?.map { $0.configurationName } ?? []
let affectedConfigurations = request.affectedStores!.map { $0.configurationName }
XCTAssertEqual(affectedConfigurations, ["Config1"])
}
do {
let from = From<TestEntity1>("Config1")
let request = Internals.CoreStoreFetchRequest<NSFetchRequestResult>()
let storesFound: Void? = try? from.applyToFetchRequest(request, context: dataStack.mainContext)
XCTAssertNotNil(storesFound)
let request = NSFetchRequest()
let storesFound = from.applyToFetchRequest(request, context: dataStack.mainContext)
XCTAssertTrue(storesFound)
XCTAssertNotNil(request.entity)
XCTAssertNotNil(request.safeAffectedStores())
XCTAssertNotNil(request.affectedStores)
XCTAssert(from.entityClass == NSClassFromString(request.entity!.managedObjectClassName))
let affectedConfigurations = request.safeAffectedStores()?.map { $0.configurationName } ?? []
let affectedConfigurations = request.affectedStores!.map { $0.configurationName }
XCTAssertEqual(affectedConfigurations, ["Config1"])
}
do {
let from = From<TestEntity1>("Config2")
let request = Internals.CoreStoreFetchRequest<NSFetchRequestResult>()
self.expectError(code: .persistentStoreNotFound) {
let request = NSFetchRequest()
let storesFound = self.expectLogger([.LogWarning]) {
try from.applyToFetchRequest(request, context: dataStack.mainContext)
from.applyToFetchRequest(request, context: dataStack.mainContext)
}
XCTAssertFalse(storesFound)
XCTAssertNotNil(request.entity)
XCTAssertNotNil(request.safeAffectedStores())
XCTAssertNotNil(request.affectedStores)
XCTAssert(from.entityClass == NSClassFromString(request.entity!.managedObjectClassName))
let affectedConfigurations = request.safeAffectedStores()?.map { $0.configurationName } ?? []
let affectedConfigurations = request.affectedStores!.map { $0.configurationName }
XCTAssertTrue(affectedConfigurations.isEmpty)
}
do {
let from = From<TestEntity2>()
let request = Internals.CoreStoreFetchRequest<NSFetchRequestResult>()
let storesFound: Void? = try? from.applyToFetchRequest(request, context: dataStack.mainContext)
XCTAssertNotNil(storesFound)
let request = NSFetchRequest()
let storesFound = from.applyToFetchRequest(request, context: dataStack.mainContext)
XCTAssertTrue(storesFound)
XCTAssertNotNil(request.entity)
XCTAssertNotNil(request.safeAffectedStores())
XCTAssertNotNil(request.affectedStores)
XCTAssert(from.entityClass == NSClassFromString(request.entity!.managedObjectClassName))
let affectedConfigurations = request.safeAffectedStores()?.map { $0.configurationName } ?? []
let affectedConfigurations = request.affectedStores!.map { $0.configurationName }
XCTAssertEqual(affectedConfigurations, ["Config2"])
}
do {
let from = From<TestEntity2>("Config1")
let request = Internals.CoreStoreFetchRequest<NSFetchRequestResult>()
self.expectError(code: .persistentStoreNotFound) {
let request = NSFetchRequest()
let storesFound = self.expectLogger([.LogWarning]) {
try from.applyToFetchRequest(request, context: dataStack.mainContext)
from.applyToFetchRequest(request, context: dataStack.mainContext)
}
XCTAssertFalse(storesFound)
XCTAssertNotNil(request.entity)
XCTAssertNotNil(request.safeAffectedStores())
XCTAssertNotNil(request.affectedStores)
XCTAssert(from.entityClass == NSClassFromString(request.entity!.managedObjectClassName))
let affectedConfigurations = request.safeAffectedStores()?.map { $0.configurationName } ?? []
let affectedConfigurations = request.affectedStores!.map { $0.configurationName }
XCTAssertTrue(affectedConfigurations.isEmpty)
}
do {
let from = From<TestEntity2>("Config2")
let request = Internals.CoreStoreFetchRequest<NSFetchRequestResult>()
let storesFound: Void? = try? from.applyToFetchRequest(request, context: dataStack.mainContext)
XCTAssertNotNil(storesFound)
let request = NSFetchRequest()
let storesFound = from.applyToFetchRequest(request, context: dataStack.mainContext)
XCTAssertTrue(storesFound)
XCTAssertNotNil(request.entity)
XCTAssertNotNil(request.safeAffectedStores())
XCTAssertNotNil(request.affectedStores)
XCTAssert(from.entityClass == NSClassFromString(request.entity!.managedObjectClassName))
let affectedConfigurations = request.safeAffectedStores()?.map { $0.configurationName } ?? []
let affectedConfigurations = request.affectedStores!.map { $0.configurationName }
XCTAssertEqual(affectedConfigurations, ["Config2"])
}
}

View File

@@ -2,7 +2,7 @@
// GroupByTests.swift
// CoreStore
//
// Copyright © 2018 John Rommel Estropia
// Copyright © 2016 John Rommel Estropia
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
@@ -23,7 +23,6 @@
// SOFTWARE.
//
import CoreData
import XCTest
@testable
@@ -39,14 +38,14 @@ final class GroupByTests: BaseTestCase {
do {
let groupBy = GroupBy<NSManagedObject>()
let groupBy = GroupBy()
XCTAssertEqual(groupBy, GroupBy([] as [String]))
XCTAssertNotEqual(groupBy, GroupBy("key"))
XCTAssertTrue(groupBy.keyPaths.isEmpty)
}
do {
let groupBy = GroupBy<NSManagedObject>("key1")
let groupBy = GroupBy("key1")
XCTAssertEqual(groupBy, GroupBy("key1"))
XCTAssertEqual(groupBy, GroupBy(["key1"]))
XCTAssertNotEqual(groupBy, GroupBy("key2"))
@@ -54,7 +53,7 @@ final class GroupByTests: BaseTestCase {
}
do {
let groupBy = GroupBy<NSManagedObject>("key1", "key2")
let groupBy = GroupBy("key1", "key2")
XCTAssertEqual(groupBy, GroupBy("key1", "key2"))
XCTAssertEqual(groupBy, GroupBy(["key1", "key2"]))
XCTAssertNotEqual(groupBy, GroupBy("key2", "key1"))
@@ -67,10 +66,10 @@ final class GroupByTests: BaseTestCase {
self.prepareStack { (dataStack) in
let groupBy = GroupBy<NSManagedObject>(#keyPath(TestEntity1.testString))
let groupBy = GroupBy("testString")
let request = Internals.CoreStoreFetchRequest<NSFetchRequestResult>()
try From<TestEntity1>().applyToFetchRequest(request, context: dataStack.mainContext)
let request = NSFetchRequest()
_ = From(TestEntity1).applyToFetchRequest(request, context: dataStack.mainContext)
groupBy.applyToFetchRequest(request)
XCTAssertNotNil(request.propertiesToGroupBy)

File diff suppressed because it is too large Load Diff

View File

@@ -15,7 +15,7 @@
<key>CFBundlePackageType</key>
<string>BNDL</string>
<key>CFBundleShortVersionString</key>
<string>9.1.0</string>
<string>1.0</string>
<key>CFBundleSignature</key>
<string>????</string>
<key>CFBundleVersion</key>

View File

@@ -2,7 +2,7 @@
// IntoTests.swift
// CoreStore
//
// Copyright © 2018 John Rommel Estropia
// Copyright © 2016 John Rommel Estropia
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
@@ -23,7 +23,6 @@
// SOFTWARE.
//
import CoreData
import XCTest
@testable
@@ -37,7 +36,7 @@ final class IntoTests: XCTestCase {
@objc
dynamic func test_ThatIntoClauseConstants_AreCorrect() {
XCTAssertEqual(DataStack.defaultConfigurationName, "PF_DEFAULT_CONFIGURATION_NAME")
XCTAssertEqual(Into<NSManagedObject>.defaultConfigurationName, "PF_DEFAULT_CONFIGURATION_NAME")
}
@objc
@@ -45,7 +44,7 @@ final class IntoTests: XCTestCase {
do {
let into = Into<NSManagedObject>()
let into = Into()
XCTAssert(into.entityClass === NSManagedObject.self)
XCTAssertNil(into.configuration)
XCTAssertTrue(into.inferStoreIfPossible)
@@ -59,7 +58,14 @@ final class IntoTests: XCTestCase {
}
do {
let into = Into(TestEntity1.self)
let into = Into(TestEntity1)
XCTAssert(into.entityClass === TestEntity1.self)
XCTAssertNil(into.configuration)
XCTAssertTrue(into.inferStoreIfPossible)
}
do {
let into = Into(TestEntity1.self as AnyClass)
XCTAssert(into.entityClass === TestEntity1.self)
XCTAssertNil(into.configuration)
XCTAssertTrue(into.inferStoreIfPossible)
@@ -78,6 +84,13 @@ final class IntoTests: XCTestCase {
XCTAssertEqual(into.configuration, "Config1")
XCTAssertFalse(into.inferStoreIfPossible)
}
do {
let into = Into(TestEntity1.self as AnyClass, "Config1")
XCTAssert(into.entityClass === TestEntity1.self)
XCTAssertEqual(into.configuration, "Config1")
XCTAssertFalse(into.inferStoreIfPossible)
}
}
@objc
@@ -85,30 +98,43 @@ final class IntoTests: XCTestCase {
do {
let into = Into<NSManagedObject>()
let into = Into()
XCTAssertEqual(into, Into())
XCTAssertEqual(into, Into<NSManagedObject>())
XCTAssertEqual(into, Into(NSManagedObject.self))
XCTAssertNotEqual(into, Into<NSManagedObject>(TestEntity1.self))
XCTAssertEqual(into, Into(NSManagedObject.self as AnyClass))
XCTAssertFalse(into == Into<TestEntity1>())
XCTAssertNotEqual(into, Into<NSManagedObject>("Config1"))
}
do {
let into = Into<TestEntity1>()
XCTAssertEqual(into, Into<TestEntity1>())
XCTAssertEqual(into, Into(TestEntity1.self))
XCTAssertEqual(into, Into(TestEntity1))
XCTAssertEqual(into, Into(TestEntity1.self as AnyClass))
XCTAssertFalse(into == Into<TestEntity2>())
XCTAssertNotEqual(into, Into<TestEntity1>("Config1"))
}
do {
let into = Into(TestEntity1.self)
let into = Into(TestEntity1)
XCTAssertEqual(into, Into<TestEntity1>())
XCTAssertEqual(into, Into(TestEntity1.self as AnyClass))
XCTAssertFalse(into == Into<TestEntity2>())
XCTAssertNotEqual(into, Into<TestEntity1>("Config1"))
}
do {
let into = Into(TestEntity1.self as AnyClass)
XCTAssert(into == Into<TestEntity1>())
XCTAssertEqual(into, Into(TestEntity1.self))
XCTAssertEqual(into, Into(TestEntity1))
XCTAssertFalse(into == Into<TestEntity2>())
XCTAssertFalse(into == Into<TestEntity1>("Config1"))
}
do {
let into = Into<TestEntity1>("Config1")
XCTAssertEqual(into, Into(TestEntity1.self, "Config1"))
XCTAssertEqual(into, Into(TestEntity1.self as AnyClass, "Config1"))
XCTAssertFalse(into == Into<TestEntity2>("Config1"))
XCTAssertNotEqual(into, Into<TestEntity1>("Config2"))
}
do {
@@ -116,14 +142,63 @@ final class IntoTests: XCTestCase {
let into = Into(TestEntity1.self, "Config1")
XCTAssertEqual(into, Into(TestEntity1.self, "Config1"))
XCTAssertEqual(into, Into<TestEntity1>("Config1"))
XCTAssertFalse(into == Into<TestEntity2>("Config1"))
XCTAssertNotEqual(into, Into<TestEntity1>("Config2"))
}
do {
let into = Into(TestEntity1.self, "Config1")
XCTAssertEqual(into, Into<TestEntity1>("Config1"))
let into = Into(TestEntity1.self as AnyClass, "Config1")
XCTAssert(into == Into<TestEntity1>("Config1"))
XCTAssertEqual(into, Into(TestEntity1.self, "Config1"))
XCTAssertNotEqual(into, Into<TestEntity1>("Config2"))
XCTAssertFalse(into == Into<TestEntity2>("Config1"))
XCTAssertFalse(into == Into<TestEntity1>("Config2"))
}
}
@objc
dynamic func test_ThatIntoClauses_BridgeCorrectly() {
do {
let into = Into()
let objcInto = into.bridgeToObjectiveC
XCTAssertEqual(into, objcInto.bridgeToSwift)
}
do {
let into = Into<TestEntity1>()
let objcInto = into.bridgeToObjectiveC
XCTAssertTrue(into == objcInto.bridgeToSwift)
}
do {
let into = Into(TestEntity1.self as AnyClass)
let objcInto = into.bridgeToObjectiveC
XCTAssertEqual(into, objcInto.bridgeToSwift)
}
do {
let into = Into(TestEntity1.self as AnyClass)
let objcInto = into.bridgeToObjectiveC
XCTAssertEqual(into, objcInto.bridgeToSwift)
}
do {
let into = Into<TestEntity1>("Config1")
let objcInto = into.bridgeToObjectiveC
XCTAssertTrue(into == objcInto.bridgeToSwift)
}
do {
let into = Into(TestEntity1.self, "Config1")
let objcInto = into.bridgeToObjectiveC
XCTAssertTrue(into == objcInto.bridgeToSwift)
}
do {
let into = Into(TestEntity1.self as AnyClass, "Config1")
let objcInto = into.bridgeToObjectiveC
XCTAssertTrue(into == objcInto.bridgeToSwift)
}
}
}

View File

@@ -2,7 +2,7 @@
// ListObserverTests.swift
// CoreStore
//
// Copyright © 2018 John Rommel Estropia
// Copyright © 2016 John Rommel Estropia
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
@@ -23,13 +23,14 @@
// SOFTWARE.
//
import CoreData
import XCTest
@testable
import CoreStore
#if os(iOS) || os(watchOS) || os(tvOS)
// MARK: - ListObserverTests
class ListObserverTests: BaseTestDataTestCase {
@@ -41,9 +42,9 @@ class ListObserverTests: BaseTestDataTestCase {
let observer = TestListObserver()
let monitor = stack.monitorSectionedList(
From<TestEntity1>(),
SectionBy(#keyPath(TestEntity1.testBoolean)),
OrderBy<TestEntity1>(.ascending(#keyPath(TestEntity1.testBoolean)), .ascending(#keyPath(TestEntity1.testEntityID)))
From(TestEntity1),
SectionBy("testBoolean"),
OrderBy(.Ascending("testBoolean"), .Ascending("testEntityID"))
)
monitor.addObserver(observer)
@@ -53,13 +54,13 @@ class ListObserverTests: BaseTestDataTestCase {
var events = 0
_ = self.expectation(
forNotification: NSNotification.Name(rawValue: "listMonitorWillChange:"),
let willChangeExpectation = self.expectationForNotification(
"listMonitorWillChange:",
object: observer,
handler: { (note) -> Bool in
XCTAssertEqual(events, 0)
XCTAssertEqual((note.userInfo as NSDictionary?) ?? [:], NSDictionary())
XCTAssertEqual((note.userInfo ?? [:]), NSDictionary())
defer {
events += 1
@@ -67,16 +68,16 @@ class ListObserverTests: BaseTestDataTestCase {
return events == 0
}
)
_ = self.expectation(
forNotification: NSNotification.Name(rawValue: "listMonitor:didInsertSection:toSectionIndex:"),
let didInsertSectionExpectation = self.expectationForNotification(
"listMonitor:didInsertSection:toSectionIndex:",
object: observer,
handler: { (note) -> Bool in
XCTAssertEqual(events, 1)
XCTAssertEqual(
((note.userInfo as NSDictionary?) ?? [:]),
(note.userInfo ?? [:]),
[
"sectionInfo": monitor.sectionInfo(at: 0),
"sectionInfo": monitor.sectionInfoAtIndex(0),
"sectionIndex": 0
] as NSDictionary
)
@@ -87,8 +88,8 @@ class ListObserverTests: BaseTestDataTestCase {
return events == 1
}
)
_ = self.expectation(
forNotification: NSNotification.Name(rawValue: "listMonitor:didInsertObject:toIndexPath:"),
let didInsertObjectExpectation = self.expectationForNotification(
"listMonitor:didInsertObject:toIndexPath:",
object: observer,
handler: { (note) -> Bool in
@@ -97,21 +98,21 @@ class ListObserverTests: BaseTestDataTestCase {
let userInfo = note.userInfo
XCTAssertNotNil(userInfo)
XCTAssertEqual(
Set(userInfo?.keys.map({ $0 as! String }) ?? []),
Set(((userInfo as? [String: AnyObject]) ?? [:]).keys),
["indexPath", "object"]
)
let indexPath = userInfo?["indexPath"] as? IndexPath
let indexPath = userInfo?["indexPath"] as? NSIndexPath
XCTAssertEqual(indexPath?.section, 0)
XCTAssertEqual(indexPath?.item, 0)
XCTAssertEqual(indexPath?.row, 0)
let object = userInfo?["object"] as? TestEntity1
XCTAssertEqual(object?.testBoolean, NSNumber(value: true))
XCTAssertEqual(object?.testNumber, NSNumber(value: 1))
XCTAssertEqual(object?.testBoolean, NSNumber(bool: true))
XCTAssertEqual(object?.testNumber, NSNumber(integer: 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")!)
XCTAssertEqual(object?.testData, ("nil:TestEntity1:1" as NSString).dataUsingEncoding(NSUTF8StringEncoding)!)
XCTAssertEqual(object?.testDate, self.dateFormatter.dateFromString("2000-01-01T00:00:00Z")!)
defer {
events += 1
@@ -119,12 +120,12 @@ class ListObserverTests: BaseTestDataTestCase {
return events == 2
}
)
_ = self.expectation(
forNotification: NSNotification.Name(rawValue: "listMonitorDidChange:"),
let didChangeExpectation = self.expectationForNotification(
"listMonitorDidChange:",
object: observer,
handler: { (note) -> Bool in
XCTAssertEqual((note.userInfo as NSDictionary?) ?? [:], NSDictionary())
XCTAssertEqual((note.userInfo ?? [:]), NSDictionary())
defer {
events += 1
@@ -132,30 +133,30 @@ class ListObserverTests: BaseTestDataTestCase {
return events == 3
}
)
let saveExpectation = self.expectation(description: "save")
stack.perform(
asynchronous: { (transaction) -> Bool in
let saveExpectation = self.expectationWithDescription("save")
stack.beginAsynchronous { (transaction) in
let object = transaction.create(Into(TestEntity1))
object.testBoolean = NSNumber(bool: true)
object.testNumber = NSNumber(integer: 1)
object.testDecimal = NSDecimalNumber(string: "1")
object.testString = "nil:TestEntity1:1"
object.testData = ("nil:TestEntity1:1" as NSString).dataUsingEncoding(NSUTF8StringEncoding)!
object.testDate = self.dateFormatter.dateFromString("2000-01-01T00:00:00Z")!
transaction.commit { (result) 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()
switch result {
case .Success(let hasChanges):
XCTAssertTrue(hasChanges)
saveExpectation.fulfill()
case .Failure:
XCTFail()
}
}
)
}
self.waitAndCheckExpectations()
}
}
@@ -169,28 +170,28 @@ class ListObserverTests: BaseTestDataTestCase {
let observer = TestListObserver()
let monitor = stack.monitorSectionedList(
From<TestEntity1>(),
SectionBy(#keyPath(TestEntity1.testBoolean)),
OrderBy<TestEntity1>(.ascending(#keyPath(TestEntity1.testBoolean)), .ascending(#keyPath(TestEntity1.testEntityID)))
From(TestEntity1),
SectionBy("testBoolean"),
OrderBy(.Ascending("testBoolean"), .Ascending("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)
XCTAssertTrue(monitor.hasObjectsInSection(0))
XCTAssertEqual(monitor.numberOfObjectsInSection(0), 2)
XCTAssertEqual(monitor.numberOfObjectsInSection(1), 3)
var events = 0
_ = self.expectation(
forNotification: NSNotification.Name(rawValue: "listMonitorWillChange:"),
let willChangeExpectation = self.expectationForNotification(
"listMonitorWillChange:",
object: observer,
handler: { (note) -> Bool in
XCTAssertEqual(events, 0)
XCTAssertEqual((note.userInfo as NSDictionary?) ?? [:], NSDictionary())
XCTAssertEqual((note.userInfo ?? [:]), NSDictionary())
defer {
events += 1
@@ -198,65 +199,67 @@ class ListObserverTests: BaseTestDataTestCase {
return events == 0
}
)
_ = 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? IndexPath
let object = userInfo?["object"] as? TestEntity1
switch object?.testEntityID {
for _ in 1 ... 2 {
let didUpdateObjectExpectation = self.expectationForNotification(
"listMonitor:didUpdateObject:atIndexPath:",
object: observer,
handler: { (note) -> Bool in
case NSNumber(value: 101)?:
XCTAssertEqual(indexPath?.section, 1)
XCTAssertEqual(indexPath?.item, 0)
XCTAssert(events == 1 || events == 2)
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")!)
let userInfo = note.userInfo
XCTAssertNotNil(userInfo)
XCTAssertEqual(
Set(((userInfo as? [String: AnyObject]) ?? [:]).keys),
["indexPath", "object"]
)
case NSNumber(value: 102)?:
XCTAssertEqual(indexPath?.section, 0)
XCTAssertEqual(indexPath?.item, 0)
let indexPath = userInfo?["indexPath"] as? NSIndexPath
let object = userInfo?["object"] as? TestEntity1
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()
switch object?.testEntityID {
case NSNumber(integer: 101)?:
XCTAssertEqual(indexPath?.section, 1)
XCTAssertEqual(indexPath?.row, 0)
XCTAssertEqual(object?.testBoolean, NSNumber(bool: true))
XCTAssertEqual(object?.testNumber, NSNumber(integer: 11))
XCTAssertEqual(object?.testDecimal, NSDecimalNumber(string: "11"))
XCTAssertEqual(object?.testString, "nil:TestEntity1:11")
XCTAssertEqual(object?.testData, ("nil:TestEntity1:11" as NSString).dataUsingEncoding(NSUTF8StringEncoding)!)
XCTAssertEqual(object?.testDate, self.dateFormatter.dateFromString("2000-01-11T00:00:00Z")!)
case NSNumber(integer: 102)?:
XCTAssertEqual(indexPath?.section, 0)
XCTAssertEqual(indexPath?.row, 0)
XCTAssertEqual(object?.testBoolean, NSNumber(bool: false))
XCTAssertEqual(object?.testNumber, NSNumber(integer: 22))
XCTAssertEqual(object?.testDecimal, NSDecimalNumber(string: "22"))
XCTAssertEqual(object?.testString, "nil:TestEntity1:22")
XCTAssertEqual(object?.testData, ("nil:TestEntity1:22" as NSString).dataUsingEncoding(NSUTF8StringEncoding)!)
XCTAssertEqual(object?.testDate, self.dateFormatter.dateFromString("2000-01-22T00:00:00Z")!)
default:
XCTFail()
}
defer {
events += 1
}
return events == 1 || events == 2
}
defer {
events += 1
}
return events == 1 || events == 2
}
)
_ = self.expectation(
forNotification: NSNotification.Name(rawValue: "listMonitorDidChange:"),
)
}
let didChangeExpectation = self.expectationForNotification(
"listMonitorDidChange:",
object: observer,
handler: { (note) -> Bool in
XCTAssertEqual(events, 3)
XCTAssertEqual((note.userInfo as NSDictionary?) ?? [:], NSDictionary())
XCTAssertEqual((note.userInfo ?? [:]), NSDictionary())
defer {
events += 1
@@ -264,50 +267,50 @@ class ListObserverTests: BaseTestDataTestCase {
return events == 3
}
)
let saveExpectation = self.expectation(description: "save")
stack.perform(
asynchronous: { (transaction) -> Bool in
let saveExpectation = self.expectationWithDescription("save")
stack.beginAsynchronous { (transaction) in
if let object = transaction.fetchOne(
From(TestEntity1),
Where("testEntityID", isEqualTo: 101)) {
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
object.testNumber = NSNumber(integer: 11)
object.testDecimal = NSDecimalNumber(string: "11")
object.testString = "nil:TestEntity1:11"
object.testData = ("nil:TestEntity1:11" as NSString).dataUsingEncoding(NSUTF8StringEncoding)!
object.testDate = self.dateFormatter.dateFromString("2000-01-11T00:00:00Z")!
}
else {
XCTFail()
}
)
if let object = transaction.fetchOne(
From(TestEntity1),
Where("testEntityID", isEqualTo: 102)) {
object.testNumber = NSNumber(integer: 22)
object.testDecimal = NSDecimalNumber(string: "22")
object.testString = "nil:TestEntity1:22"
object.testData = ("nil:TestEntity1:22" as NSString).dataUsingEncoding(NSUTF8StringEncoding)!
object.testDate = self.dateFormatter.dateFromString("2000-01-22T00:00:00Z")!
}
else {
XCTFail()
}
transaction.commit { (result) in
switch result {
case .Success(let hasChanges):
XCTAssertTrue(hasChanges)
saveExpectation.fulfill()
case .Failure:
XCTFail()
}
}
}
self.waitAndCheckExpectations()
}
}
@@ -321,21 +324,21 @@ class ListObserverTests: BaseTestDataTestCase {
let observer = TestListObserver()
let monitor = stack.monitorSectionedList(
From<TestEntity1>(),
SectionBy(#keyPath(TestEntity1.testBoolean)),
OrderBy<TestEntity1>(.ascending(#keyPath(TestEntity1.testBoolean)), .ascending(#keyPath(TestEntity1.testEntityID)))
From(TestEntity1),
SectionBy("testBoolean"),
OrderBy(.Ascending("testBoolean"), .Ascending("testEntityID"))
)
monitor.addObserver(observer)
var events = 0
_ = self.expectation(
forNotification: NSNotification.Name(rawValue: "listMonitorWillChange:"),
let willChangeExpectation = self.expectationForNotification(
"listMonitorWillChange:",
object: observer,
handler: { (note) -> Bool in
XCTAssertEqual(events, 0)
XCTAssertEqual((note.userInfo as NSDictionary?) ?? [:], NSDictionary())
XCTAssertEqual((note.userInfo ?? [:]), NSDictionary())
defer {
events += 1
@@ -343,8 +346,8 @@ class ListObserverTests: BaseTestDataTestCase {
return events == 0
}
)
_ = self.expectation(
forNotification: NSNotification.Name(rawValue: "listMonitor:didMoveObject:fromIndexPath:toIndexPath:"),
let didMoveObjectExpectation = self.expectationForNotification(
"listMonitor:didMoveObject:fromIndexPath:toIndexPath:",
object: observer,
handler: { (note) -> Bool in
@@ -353,21 +356,21 @@ class ListObserverTests: BaseTestDataTestCase {
let userInfo = note.userInfo
XCTAssertNotNil(userInfo)
XCTAssertEqual(
Set(userInfo?.keys.map({ $0 as! String }) ?? []),
Set(((userInfo as? [String: AnyObject]) ?? [:]).keys),
["fromIndexPath", "toIndexPath", "object"]
)
let fromIndexPath = userInfo?["fromIndexPath"] as? IndexPath
let fromIndexPath = userInfo?["fromIndexPath"] as? NSIndexPath
XCTAssertEqual(fromIndexPath?.section, 0)
XCTAssertEqual(fromIndexPath?.item, 0)
XCTAssertEqual(fromIndexPath?.row, 0)
let toIndexPath = userInfo?["toIndexPath"] as? IndexPath
let toIndexPath = userInfo?["toIndexPath"] as? NSIndexPath
XCTAssertEqual(toIndexPath?.section, 1)
XCTAssertEqual(toIndexPath?.item, 1)
XCTAssertEqual(toIndexPath?.row, 1)
let object = userInfo?["object"] as? TestEntity1
XCTAssertEqual(object?.testEntityID, NSNumber(value: 102))
XCTAssertEqual(object?.testBoolean, NSNumber(value: true))
XCTAssertEqual(object?.testEntityID, NSNumber(integer: 102))
XCTAssertEqual(object?.testBoolean, NSNumber(bool: true))
defer {
@@ -376,13 +379,13 @@ class ListObserverTests: BaseTestDataTestCase {
return events == 1
}
)
_ = self.expectation(
forNotification: NSNotification.Name(rawValue: "listMonitorDidChange:"),
let didChangeExpectation = self.expectationForNotification(
"listMonitorDidChange:",
object: observer,
handler: { (note) -> Bool in
XCTAssertEqual(events, 2)
XCTAssertEqual((note.userInfo as NSDictionary?) ?? [:], NSDictionary())
XCTAssertEqual((note.userInfo ?? [:]), NSDictionary())
defer {
events += 1
@@ -390,32 +393,32 @@ class ListObserverTests: BaseTestDataTestCase {
return events == 2
}
)
let saveExpectation = self.expectation(description: "save")
stack.perform(
asynchronous: { (transaction) -> Bool in
let saveExpectation = self.expectationWithDescription("save")
stack.beginAsynchronous { (transaction) in
if let object = transaction.fetchOne(
From(TestEntity1),
Where("testEntityID", isEqualTo: 102)) {
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
object.testBoolean = NSNumber(bool: true)
}
else {
XCTFail()
}
)
transaction.commit { (result) in
switch result {
case .Success(let hasChanges):
XCTAssertTrue(hasChanges)
saveExpectation.fulfill()
case .Failure:
XCTFail()
}
}
}
self.waitAndCheckExpectations()
}
}
@@ -429,21 +432,21 @@ class ListObserverTests: BaseTestDataTestCase {
let observer = TestListObserver()
let monitor = stack.monitorSectionedList(
From<TestEntity1>(),
SectionBy(#keyPath(TestEntity1.testBoolean)),
OrderBy<TestEntity1>(.ascending(#keyPath(TestEntity1.testBoolean)), .ascending(#keyPath(TestEntity1.testEntityID)))
From(TestEntity1),
SectionBy("testBoolean"),
OrderBy(.Ascending("testBoolean"), .Ascending("testEntityID"))
)
monitor.addObserver(observer)
var events = 0
_ = self.expectation(
forNotification: NSNotification.Name(rawValue: "listMonitorWillChange:"),
let willChangeExpectation = self.expectationForNotification(
"listMonitorWillChange:",
object: observer,
handler: { (note) -> Bool in
XCTAssertEqual(events, 0)
XCTAssertEqual((note.userInfo as NSDictionary?) ?? [:], NSDictionary())
XCTAssertEqual((note.userInfo ?? [:]), NSDictionary())
defer {
events += 1
@@ -451,37 +454,40 @@ class ListObserverTests: BaseTestDataTestCase {
return events == 0
}
)
_ = 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? IndexPath
XCTAssertEqual(indexPath?.section, 0)
XCTAssert(indexPath?.item == 0 || indexPath?.item == 1)
let object = userInfo?["object"] as? TestEntity1
XCTAssertEqual(object?.isDeleted, true)
defer {
for _ in 1 ... 2 {
let didUpdateObjectExpectation = self.expectationForNotification(
"listMonitor:didDeleteObject:fromIndexPath:",
object: observer,
handler: { (note) -> Bool in
events += 1
XCTAssert(events == 1 || events == 2)
let userInfo = note.userInfo
XCTAssertNotNil(userInfo)
XCTAssertEqual(
Set(((userInfo as? [String: AnyObject]) ?? [:]).keys),
["indexPath", "object"]
)
let indexPath = userInfo?["indexPath"] as? NSIndexPath
XCTAssertEqual(indexPath?.section, 0)
XCTAssert(indexPath?.row == 0 || indexPath?.row == 1)
let object = userInfo?["object"] as? TestEntity1
XCTAssertEqual(object?.deleted, true)
defer {
events += 1
}
return events == 1 || events == 2
}
return events == 1 || events == 2
}
)
_ = self.expectation(
forNotification: NSNotification.Name(rawValue: "listMonitor:didDeleteSection:fromSectionIndex:"),
)
}
let didDeleteSectionExpectation = self.expectationForNotification(
"listMonitor:didDeleteSection:fromSectionIndex:",
object: observer,
handler: { (note) -> Bool in
@@ -490,16 +496,16 @@ class ListObserverTests: BaseTestDataTestCase {
let userInfo = note.userInfo
XCTAssertNotNil(userInfo)
XCTAssertEqual(
Set(userInfo?.keys.map({ $0 as! String }) ?? []),
Set(((userInfo as? [String: AnyObject]) ?? [:]).keys),
["sectionInfo", "sectionIndex"]
)
let sectionInfo = userInfo?["sectionInfo"] as? NSFetchedResultsSectionInfo
let sectionInfo = userInfo?["sectionInfo"]
XCTAssertNotNil(sectionInfo)
XCTAssertEqual(sectionInfo?.name, "0")
let sectionIndex = userInfo?["sectionIndex"]
XCTAssertEqual(sectionIndex as? NSNumber, NSNumber(value: 0))
XCTAssertEqual(sectionIndex as? NSNumber, NSNumber(integer: 0))
defer {
@@ -508,13 +514,13 @@ class ListObserverTests: BaseTestDataTestCase {
return events == 3
}
)
_ = self.expectation(
forNotification: NSNotification.Name(rawValue: "listMonitorDidChange:"),
let didChangeExpectation = self.expectationForNotification(
"listMonitorDidChange:",
object: observer,
handler: { (note) -> Bool in
XCTAssertEqual(events, 4)
XCTAssertEqual((note.userInfo as NSDictionary?) ?? [:], NSDictionary())
XCTAssertEqual((note.userInfo ?? [:]), NSDictionary())
defer {
events += 1
@@ -522,27 +528,26 @@ class ListObserverTests: BaseTestDataTestCase {
return events == 4
}
)
let saveExpectation = self.expectation(description: "save")
stack.perform(
asynchronous: { (transaction) -> Bool in
let saveExpectation = self.expectationWithDescription("save")
stack.beginAsynchronous { (transaction) in
transaction.deleteAll(
From(TestEntity1),
Where("testBoolean", isEqualTo: false)
)
transaction.commit { (result) 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()
switch result {
case .Success(let hasChanges):
XCTAssertTrue(hasChanges)
saveExpectation.fulfill()
case .Failure:
XCTFail()
}
}
)
}
self.waitAndCheckExpectations()
}
}
@@ -557,37 +562,37 @@ class TestListObserver: ListSectionObserver {
typealias ListEntityType = TestEntity1
func listMonitorWillChange(_ monitor: ListMonitor<TestEntity1>) {
func listMonitorWillChange(monitor: ListMonitor<TestEntity1>) {
NotificationCenter.default.post(
name: Notification.Name(rawValue: "listMonitorWillChange:"),
NSNotificationCenter.defaultCenter().postNotificationName(
"listMonitorWillChange:",
object: self,
userInfo: [:]
)
}
func listMonitorDidChange(_ monitor: ListMonitor<TestEntity1>) {
func listMonitorDidChange(monitor: ListMonitor<TestEntity1>) {
NotificationCenter.default.post(
name: Notification.Name(rawValue: "listMonitorDidChange:"),
NSNotificationCenter.defaultCenter().postNotificationName(
"listMonitorDidChange:",
object: self,
userInfo: [:]
)
}
func listMonitorWillRefetch(_ monitor: ListMonitor<TestEntity1>) {
func listMonitorWillRefetch(monitor: ListMonitor<TestEntity1>) {
NotificationCenter.default.post(
name: Notification.Name(rawValue: "listMonitorWillRefetch:"),
NSNotificationCenter.defaultCenter().postNotificationName(
"listMonitorWillRefetch:",
object: self,
userInfo: [:]
)
}
func listMonitorDidRefetch(_ monitor: ListMonitor<TestEntity1>) {
func listMonitorDidRefetch(monitor: ListMonitor<TestEntity1>) {
NotificationCenter.default.post(
name: Notification.Name(rawValue: "listMonitorDidRefetch:"),
NSNotificationCenter.defaultCenter().postNotificationName(
"listMonitorDidRefetch:",
object: self,
userInfo: [:]
)
@@ -596,10 +601,10 @@ class TestListObserver: ListSectionObserver {
// MARK: ListObjectObserver
func listMonitor(_ monitor: ListMonitor<TestEntity1>, didInsertObject object: TestEntity1, toIndexPath indexPath: IndexPath) {
func listMonitor(monitor: ListMonitor<TestEntity1>, didInsertObject object: TestEntity1, toIndexPath indexPath: NSIndexPath) {
NotificationCenter.default.post(
name: Notification.Name(rawValue: "listMonitor:didInsertObject:toIndexPath:"),
NSNotificationCenter.defaultCenter().postNotificationName(
"listMonitor:didInsertObject:toIndexPath:",
object: self,
userInfo: [
"object": object,
@@ -608,10 +613,10 @@ class TestListObserver: ListSectionObserver {
)
}
func listMonitor(_ monitor: ListMonitor<TestEntity1>, didDeleteObject object: TestEntity1, fromIndexPath indexPath: IndexPath) {
func listMonitor(monitor: ListMonitor<TestEntity1>, didDeleteObject object: TestEntity1, fromIndexPath indexPath: NSIndexPath) {
NotificationCenter.default.post(
name: Notification.Name(rawValue: "listMonitor:didDeleteObject:fromIndexPath:"),
NSNotificationCenter.defaultCenter().postNotificationName(
"listMonitor:didDeleteObject:fromIndexPath:",
object: self,
userInfo: [
"object": object,
@@ -620,10 +625,10 @@ class TestListObserver: ListSectionObserver {
)
}
func listMonitor(_ monitor: ListMonitor<TestEntity1>, didUpdateObject object: TestEntity1, atIndexPath indexPath: IndexPath) {
func listMonitor(monitor: ListMonitor<TestEntity1>, didUpdateObject object: TestEntity1, atIndexPath indexPath: NSIndexPath) {
NotificationCenter.default.post(
name: Notification.Name(rawValue: "listMonitor:didUpdateObject:atIndexPath:"),
NSNotificationCenter.defaultCenter().postNotificationName(
"listMonitor:didUpdateObject:atIndexPath:",
object: self,
userInfo: [
"object": object,
@@ -633,10 +638,10 @@ class TestListObserver: ListSectionObserver {
}
func listMonitor(_ monitor: ListMonitor<TestEntity1>, didMoveObject object: TestEntity1, fromIndexPath: IndexPath, toIndexPath: IndexPath) {
func listMonitor(monitor: ListMonitor<TestEntity1>, didMoveObject object: TestEntity1, fromIndexPath: NSIndexPath, toIndexPath: NSIndexPath) {
NotificationCenter.default.post(
name: Notification.Name(rawValue: "listMonitor:didMoveObject:fromIndexPath:toIndexPath:"),
NSNotificationCenter.defaultCenter().postNotificationName(
"listMonitor:didMoveObject:fromIndexPath:toIndexPath:",
object: self,
userInfo: [
"object": object,
@@ -649,10 +654,10 @@ class TestListObserver: ListSectionObserver {
// MARK: ListSectionObserver
func listMonitor(_ monitor: ListMonitor<TestEntity1>, didInsertSection sectionInfo: NSFetchedResultsSectionInfo, toSectionIndex sectionIndex: Int) {
func listMonitor(monitor: ListMonitor<TestEntity1>, didInsertSection sectionInfo: NSFetchedResultsSectionInfo, toSectionIndex sectionIndex: Int) {
NotificationCenter.default.post(
name: Notification.Name(rawValue: "listMonitor:didInsertSection:toSectionIndex:"),
NSNotificationCenter.defaultCenter().postNotificationName(
"listMonitor:didInsertSection:toSectionIndex:",
object: self,
userInfo: [
"sectionInfo": sectionInfo,
@@ -661,10 +666,10 @@ class TestListObserver: ListSectionObserver {
)
}
func listMonitor(_ monitor: ListMonitor<TestEntity1>, didDeleteSection sectionInfo: NSFetchedResultsSectionInfo, fromSectionIndex sectionIndex: Int) {
func listMonitor(monitor: ListMonitor<TestEntity1>, didDeleteSection sectionInfo: NSFetchedResultsSectionInfo, fromSectionIndex sectionIndex: Int) {
NotificationCenter.default.post(
name: Notification.Name(rawValue: "listMonitor:didDeleteSection:fromSectionIndex:"),
NSNotificationCenter.defaultCenter().postNotificationName(
"listMonitor:didDeleteSection:fromSectionIndex:",
object: self,
userInfo: [
"sectionInfo": sectionInfo,
@@ -673,3 +678,5 @@ class TestListObserver: ListSectionObserver {
)
}
}
#endif

View File

@@ -1,303 +0,0 @@
//
// 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
class ListPublisherTests: BaseTestDataTestCase {
@objc
dynamic func test_ThatListPublishers_CanReceiveInsertNotifications() {
self.prepareStack { (stack) in
let observer = NSObject()
let listPublisher = stack.publishList(
From<TestEntity1>(),
SectionBy(#keyPath(TestEntity1.testBoolean)),
OrderBy<TestEntity1>(.ascending(#keyPath(TestEntity1.testBoolean)), .ascending(#keyPath(TestEntity1.testEntityID)))
)
XCTAssertFalse(listPublisher.snapshot.hasSections())
XCTAssertFalse(listPublisher.snapshot.hasItems())
XCTAssertTrue(listPublisher.snapshot.itemIDs.isEmpty)
let didChangeExpectation = self.expectation(description: "didChange")
listPublisher.addObserver(observer) { listPublisher in
XCTAssertTrue(listPublisher.snapshot.hasSections())
XCTAssertTrue(listPublisher.snapshot.hasItems())
XCTAssertEqual(listPublisher.snapshot.numberOfItems(inSectionIndex: 0), 1)
didChangeExpectation.fulfill()
}
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, {})
withExtendedLifetime(observer, {})
}
}
@objc
dynamic func test_ThatListPublishers_CanReceiveUpdateNotifications() {
self.prepareStack { (stack) in
self.prepareTestDataForStack(stack)
let observer = NSObject()
let listPublisher = stack.publishList(
From<TestEntity1>(),
SectionBy(#keyPath(TestEntity1.testBoolean)),
OrderBy<TestEntity1>(.ascending(#keyPath(TestEntity1.testBoolean)), .ascending(#keyPath(TestEntity1.testEntityID)))
)
XCTAssertTrue(listPublisher.snapshot.hasSections())
XCTAssertEqual(listPublisher.snapshot.numberOfSections, 2)
XCTAssertTrue(listPublisher.snapshot.hasItems())
XCTAssertTrue(listPublisher.snapshot.hasItems(inSectionIndex: 0))
XCTAssertEqual(listPublisher.snapshot.numberOfItems(inSectionIndex: 0), 2)
XCTAssertEqual(listPublisher.snapshot.numberOfItems(inSectionIndex: 1), 3)
let didChangeExpectation = self.expectation(description: "didChange")
listPublisher.addObserver(observer) { listPublisher in
XCTAssertTrue(listPublisher.snapshot.hasSections())
XCTAssertEqual(listPublisher.snapshot.numberOfSections, 2)
XCTAssertTrue(listPublisher.snapshot.hasItems())
XCTAssertTrue(listPublisher.snapshot.hasItems(inSectionIndex: 0))
XCTAssertEqual(listPublisher.snapshot.numberOfItems(inSectionIndex: 0), 2)
XCTAssertEqual(listPublisher.snapshot.numberOfItems(inSectionIndex: 1), 3)
didChangeExpectation.fulfill()
}
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()
withExtendedLifetime(listPublisher, {})
withExtendedLifetime(observer, {})
}
}
@objc
dynamic func test_ThatListPublishers_CanReceiveMoveNotifications() {
self.prepareStack { (stack) in
self.prepareTestDataForStack(stack)
let observer = NSObject()
let listPublisher = stack.publishList(
From<TestEntity1>(),
SectionBy(#keyPath(TestEntity1.testBoolean)),
OrderBy<TestEntity1>(.ascending(#keyPath(TestEntity1.testBoolean)), .ascending(#keyPath(TestEntity1.testEntityID)))
)
XCTAssertTrue(listPublisher.snapshot.hasSections())
XCTAssertEqual(listPublisher.snapshot.numberOfSections, 2)
XCTAssertTrue(listPublisher.snapshot.hasItems())
XCTAssertTrue(listPublisher.snapshot.hasItems(inSectionIndex: 0))
XCTAssertEqual(listPublisher.snapshot.numberOfItems(inSectionIndex: 0), 2)
XCTAssertEqual(listPublisher.snapshot.numberOfItems(inSectionIndex: 1), 3)
let didChangeExpectation = self.expectation(description: "didChange")
listPublisher.addObserver(observer) { listPublisher in
XCTAssertTrue(listPublisher.snapshot.hasSections())
XCTAssertEqual(listPublisher.snapshot.numberOfSections, 2)
XCTAssertTrue(listPublisher.snapshot.hasItems())
XCTAssertTrue(listPublisher.snapshot.hasItems(inSectionIndex: 0))
XCTAssertEqual(listPublisher.snapshot.numberOfItems(inSectionIndex: 0), 1)
XCTAssertEqual(listPublisher.snapshot.numberOfItems(inSectionIndex: 1), 4)
didChangeExpectation.fulfill()
}
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()
withExtendedLifetime(listPublisher, {})
withExtendedLifetime(observer, {})
}
}
@objc
dynamic func test_ThatListPublishers_CanReceiveDeleteNotifications() {
self.prepareStack { (stack) in
self.prepareTestDataForStack(stack)
let observer = NSObject()
let listPublisher = stack.publishList(
From<TestEntity1>(),
SectionBy(#keyPath(TestEntity1.testBoolean)),
OrderBy<TestEntity1>(.ascending(#keyPath(TestEntity1.testBoolean)), .ascending(#keyPath(TestEntity1.testEntityID)))
)
XCTAssertTrue(listPublisher.snapshot.hasSections())
XCTAssertEqual(listPublisher.snapshot.numberOfSections, 2)
XCTAssertTrue(listPublisher.snapshot.hasItems())
XCTAssertTrue(listPublisher.snapshot.hasItems(inSectionIndex: 0))
XCTAssertEqual(listPublisher.snapshot.numberOfItems(inSectionIndex: 0), 2)
XCTAssertEqual(listPublisher.snapshot.numberOfItems(inSectionIndex: 1), 3)
let didChangeExpectation = self.expectation(description: "didChange")
listPublisher.addObserver(observer) { listPublisher in
XCTAssertTrue(listPublisher.snapshot.hasSections())
XCTAssertEqual(listPublisher.snapshot.numberOfSections, 1)
XCTAssertTrue(listPublisher.snapshot.hasItems())
XCTAssertTrue(listPublisher.snapshot.hasItems(inSectionIndex: 0))
XCTAssertEqual(listPublisher.snapshot.numberOfItems(inSectionIndex: 0), 3)
didChangeExpectation.fulfill()
}
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()
}
}
}
#endif

View File

@@ -2,7 +2,7 @@
// MigrationChainTests.swift
// CoreStore
//
// Copyright © 2018 John Rommel Estropia
// Copyright © 2016 John Rommel Estropia
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
@@ -37,8 +37,8 @@ final class MigrationChainTests: XCTestCase {
dynamic func test_ThatNilMigrationChains_HaveNoVersions() {
let chain: MigrationChain = nil
XCTAssertTrue(chain.isValid)
XCTAssertTrue(chain.isEmpty)
XCTAssertTrue(chain.valid)
XCTAssertTrue(chain.empty)
XCTAssertFalse(chain.contains("version1"))
XCTAssertNil(chain.nextVersionFrom("version1"))
@@ -48,8 +48,8 @@ final class MigrationChainTests: XCTestCase {
dynamic func test_ThatStringMigrationChains_HaveOneVersion() {
let chain: MigrationChain = "version1"
XCTAssertTrue(chain.isValid)
XCTAssertTrue(chain.isEmpty)
XCTAssertTrue(chain.valid)
XCTAssertTrue(chain.empty)
XCTAssertTrue(chain.contains("version1"))
XCTAssertFalse(chain.contains("version2"))
@@ -62,8 +62,8 @@ final class MigrationChainTests: XCTestCase {
dynamic func test_ThatArrayMigrationChains_HaveLinearVersions() {
let chain: MigrationChain = ["version1", "version2", "version3", "version4"]
XCTAssertTrue(chain.isValid)
XCTAssertFalse(chain.isEmpty)
XCTAssertTrue(chain.valid)
XCTAssertFalse(chain.empty)
XCTAssertTrue(chain.contains("version1"))
XCTAssertTrue(chain.contains("version2"))
@@ -86,8 +86,8 @@ final class MigrationChainTests: XCTestCase {
"version2": "version3",
"version3": "version4"
]
XCTAssertTrue(chain.isValid)
XCTAssertFalse(chain.isEmpty)
XCTAssertTrue(chain.valid)
XCTAssertFalse(chain.empty)
XCTAssertTrue(chain.contains("version1"))
XCTAssertTrue(chain.contains("version2"))

Some files were not shown because too many files have changed in this diff Show More