Compare commits

...

439 Commits

Author SHA1 Message Date
John Estropia
84f3740ea1 fix unit test warnings 2019-01-18 17:30:54 +09:00
John Estropia
6dc48b6af7 Add docs for new throwing methods 2019-01-17 18:43:10 +09:00
John Estropia
09ce2816bf Merge branch 'develop' into throwables 2019-01-16 17:03:49 +09:00
John Estropia
62e962eebe Merge pull request #301 from ianbytchek/develop
Resolve source entity and managed object attributes by name
2019-01-16 17:01:48 +09:00
John Estropia
682472c1bd fetches, queries, and deletes are now throwable methods 2019-01-15 20:40:15 +09:00
Ian Bytchek
46ab70b839 Update TravisCI base image to Xcode 10
Replace deprecated build matrix configurations with newer alternatives.
2019-01-13 06:24:04 +00:00
Ian Bytchek
ac8304f977 Resolve source entity and managed object attributes by name
Addresses #300 – see it for details. Also improves the use of whitespace consistency across the `CustomSchemaMappingProvider.swift` and uses method names for `cs_resolve…` over `cs_resolved…` for better alignment with [Swift API Design Guidelines](https://swift.org/documentation/api-design-guidelines).
2019-01-13 05:41:34 +00:00
John Estropia
5777831565 WIP: make fetching methods throwable 2019-01-11 19:52:12 +09:00
John Estropia
42d1f41939 Provide more context when failing to search for mapping models #299 2019-01-11 19:48:35 +09:00
John Estropia
8c30ec3a3d minor fixes on Playgrounds and Demo app 2019-01-09 11:59:06 +09:00
John Estropia
237a1b648e Assert on reserved property names 2019-01-09 11:58:37 +09:00
John Estropia
614f1572c2 print PartialObjects 2018-12-26 22:35:28 +08:00
John Estropia
a48f16aa8c add Jazzy docs 2018-12-19 16:27:05 +09:00
John Estropia
cdbadae002 added comments to playground 2018-12-18 18:44:47 +09:00
John Estropia
4a28a39df6 removed long-standing workaround for NSFetchedResultsController bugs since they seem to be fixed 2018-12-18 18:43:36 +09:00
John Estropia
5febf2542d added playgrounds just to show off 2018-12-14 19:28:55 +09:00
John Estropia
c21ab11a41 format header comment 2018-12-14 18:21:41 +09:00
John Estropia
10cd18dbf0 prototype for CoreStoreObject property observers (a.k.a. KVO) 2018-12-14 18:20:42 +09:00
John Estropia
8409a13289 Merge pull request #288 from ruslanskorb/list-monitor-number-of-objects-performance
[ListMonitor] Fix performance of `numberOfObjects()`.
2018-12-06 18:53:06 +09:00
Ruslan Skorb
a9a73fa5c4 [ListMonitor] [numberOfObjects()] Return count of fetchedObjects.
Casting `fetchedObjects` to `NSArray?` has better performance.
https://github.com/JohnEstropia/CoreStore/pull/288
2018-12-06 10:56:30 +02:00
John Estropia
82cae2e11e Merge pull request #292 from eliseo-juan/patch-1
Fix documentation
2018-12-06 10:54:50 +09:00
John Estropia
42caee2418 Merge pull request #287 from ruslanskorb/list-monitor-subscript-performance
[ListMonitor] Fix performance of `subscript(safeSectionIndex:safeItemIndex:)`.
2018-12-06 10:54:12 +09:00
Eliseo Juan Quintanilla
1dea1d0d06 Fix documentation
Changed attribtue to attribute
2018-12-05 10:09:05 +01:00
John Estropia
d344b9d878 minimum deployment version bumped to iOS 10, macOS 10.12, tvOS 10, watchOS 3. Deprecated iCloud Storage 2018-12-05 17:31:16 +09:00
John Estropia
95c1ce52cc Merge branch 'develop' of github.com:JohnEstropia/CoreStore into develop 2018-12-05 16:17:03 +09:00
John Estropia
cc346816d6 Added new error for cases when addStorageAndWait() is used with .allowSynchronousLightweightMigration but migrations are only allowed asynchronously (related to #277) 2018-12-05 16:15:20 +09:00
John Estropia
f14b561c33 Merge pull request #275 from DmitrijMaz/fix_queueing
Fix queue validation for UnsafeDataTransaction
2018-12-05 11:02:47 +09:00
Ruslan Skorb
6f655951aa [ListMonitor] [numberOfObjects()] Calculate the number of objects in all sections by summing the number of objects stored in NSFetchedResultsSectionInfo.
There is a performance problem in Swift when calling `count` method on an array with a large number of fetched objects. It requires casting the array between Objective-C and Swift, that is pretty slow.
2018-11-24 16:24:14 +02:00
Ruslan Skorb
ff8fbae568 [ListMonitor] [subscript(safeSectionIndex:safeItemIndex:)] Use subscript(indexPath:) after the validation of sectionIndex and itemIndex to get an object.
There is a performance problem in Swift when getting an object from the Objective-C array with a large number of objects using subscript. It requires casting the array between Objective-C and Swift, that is pretty slow.
2018-11-24 16:23:36 +02:00
Dmitry Mazurenko
4d4b02d076 Fix queue validation for UnsafeDataTransaction 2018-10-10 16:48:04 +03:00
John Estropia
06c0981ded debug string for CoreStoreObject 2018-09-24 00:49:53 +09:00
John Estropia
20d581d536 version bump 2018-09-19 18:48:45 +09:00
John Estropia
45e110755d deleted unnecessary Equatable and Hashable custom implementations 2018-09-19 11:06:19 +09:00
John Estropia
ab40532801 fix issue with early-deallocated CoreStoreObjects 2018-09-18 23:50:14 +09:00
John Estropia
40f458a09c Merge branch 'develop' of github.com:JohnEstropia/CoreStore into develop 2018-09-15 12:56:21 +09:00
John Estropia
1ad233ca9d Swift 4.2 support 2018-09-15 12:56:08 +09:00
John Estropia
3a8e394272 Merge pull request #269 from congbach/develop
Fixed bug where ListObjectObserver didUpdateObject was not called on …
2018-09-10 19:30:06 +09:00
Ken Bach
1f54daa528 Fixed bug where ListObjectObserver.didUpdateObject was not called on watchos. 2018-08-21 22:47:54 +01:00
John Estropia
f25879b6fe fix compile error on tvOS and watchOS 2018-08-09 21:04:09 +09:00
John Estropia
8fa3109e91 version bump 2018-08-09 20:45:46 +09:00
John Estropia
808e8ff97a stabilize NSProgress when lightweight migration falls back to InferredMappingModel 2018-08-09 18:18:21 +09:00
John Estropia
30685d4355 Use InferredMappingModel in case lightweight migration fails for some reason 2018-08-09 02:09:54 +09:00
John Estropia
7152962026 revert 2018-08-09 01:39:16 +09:00
John Estropia
91735e38d1 Fix issue where CoreStoreObjects nested in a type is mismatching classnames before migration 2018-08-08 23:52:47 +09:00
John Estropia
333a50ad9e Merge pull request #256 from vGubriienko/demo-fix
Fixed issue with brightness observing in the Demo
2018-08-03 17:44:40 +09:00
John Rommel Estropia
b7a602fc67 iOS 11 Core Data changes 2018-07-29 23:33:51 +09:00
Viktor Gubriienko
2ff7ecef96 Fixed issue with brightness observing in the Demo 2018-06-12 17:53:00 +03:00
John Rommel Estropia
e3f9139304 version bump 2018-06-10 11:52:47 +09:00
John Rommel Estropia
4aa461872f specify swift version in podspec 2018-06-10 11:47:03 +09:00
John Rommel Estropia
3d43314076 update readme 2018-04-14 09:05:13 +09:00
John Rommel Estropia
7b1075b759 support compound indexes and unique constraints on CoreStore properties 2018-03-17 23:56:42 +09:00
John Rommel Estropia
0c29e07ddb support allowsExternalBinaryDataStorage option on Transformable CoreStoreObject properties 2018-03-17 23:56:01 +09:00
John Rommel Estropia
ce91cf22f9 Swift 4.1 support 2018-03-17 23:53:24 +09:00
John Rommel Estropia
2dd033c002 Merge branch 'develop' into prototype/Swift_4_1 2018-03-10 21:09:29 +09:00
John Rommel Estropia
c7fcba112e Fix bug where ListMonitor sectionIndexTitles are not updated on refetch (fixes #218) 2018-03-10 21:09:18 +09:00
John Rommel Estropia
c8b1c4358f Fix bug where ListMonitor sectionIndexTitles are not updated on refetch (fixes #218) 2018-03-10 21:08:40 +09:00
John Rommel Estropia
5431e2e974 Swift 4.1 support 2018-03-10 21:07:53 +09:00
John Rommel Estropia
83e6082c56 Merge branch 'develop' of github.com:JohnEstropia/CoreStore into develop 2018-01-07 23:25:11 +09:00
John Rommel Estropia
c7bdbbde57 convert value to native type before formatting predicates 2018-01-07 21:06:35 +09:00
John Estropia
abf15c8aa8 Merge pull request #232 from kf99916/external-storage-migration
External storage migration
2018-01-06 17:48:38 +09:00
Zheng-Xiang Ke
d9db7e4a82 Typo 2018-01-06 15:00:53 +08:00
John Estropia
65dbc22ddd Merge pull request #231 from doodzik/patch-1
Fix syntax error in readme
2018-01-06 15:11:48 +09:00
Zheng-Xiang Ke
51961dd737 Migrate external storage 2018-01-06 10:22:44 +08:00
Frederik Dudzik
18a7055cdf Fix syntax error 2018-01-05 21:16:04 +01:00
John Rommel Estropia
4b9fddad6a Merge branch 'develop' 2017-12-29 01:09:07 +09:00
John Rommel Estropia
fbe7bd7bf8 update podfile 2017-12-29 00:53:48 +09:00
John Rommel Estropia
15edabdbb5 changed keyPath string utility to use String initializer 2017-12-29 00:05:11 +09:00
John Rommel Estropia
f447bcfb95 Merge branch 'develop' into prototype/Swift_4_0
# Conflicts:
#	CoreStore.podspec
#	Sources/DataStack+Migration.swift
#	Sources/Info.plist
2017-11-19 15:35:29 +09:00
John Rommel Estropia
15e5e4fdf6 delete shm file after converting to DELETE journal mode 2017-11-19 15:34:09 +09:00
John Rommel Estropia
583c6b7249 minor code cleanup 2017-11-19 13:49:21 +09:00
John Rommel Estropia
18b933957e version bump 2017-11-16 02:28:18 +09:00
John Rommel Estropia
2c7039232e merge sqlite journal files before migration 2017-11-16 02:27:06 +09:00
John Rommel Estropia
d3b3b5ff4a added fake progress for lightweight migrations 2017-11-16 02:26:56 +09:00
John Rommel Estropia
d90e8d1303 force true lightweight migration 2017-11-16 02:26:44 +09:00
John Rommel Estropia
b55dd13dff merge sqlite journal files before migration 2017-11-15 23:50:10 +09:00
John Rommel Estropia
66dd5b6f27 added fake progress for lightweight migrations 2017-11-13 02:44:26 +09:00
John Estropia
49c4b770eb WIP: Readme 2017-11-10 19:19:48 +09:00
John Rommel Estropia
662aaa1e75 force true lightweight migration 2017-11-10 02:48:37 +09:00
John Rommel Estropia
dd4e47d7f9 revert null overloads, remove optional objectIDs as condition 2017-11-09 23:26:53 +09:00
John Estropia
9ea5073bc8 Merge branch 'master' into prototype/Swift_4_0
# Conflicts:
#	CoreStore.podspec
#	Sources/Info.plist
2017-11-09 19:52:29 +09:00
John Estropia
e314db8f56 version bump 2017-11-09 19:45:21 +09:00
John Estropia
48d936d068 Fix regression for ARC bugfix (fixes #221) 2017-11-09 19:44:27 +09:00
John Estropia
b2ff8a15ef add query overloads to == so comparison with nil don't confuse the compiler 2017-11-09 19:27:56 +09:00
John Estropia
8a4d1cd7c6 fix demo app warnings 2017-11-09 19:27:05 +09:00
John Rommel Estropia
8ce26c213d more source docs, deprecated some Where clause utilities 2017-11-04 10:37:54 +09:00
John Estropia
f3816b9abf update for Xcode 9.1 2017-11-01 19:49:42 +09:00
John Estropia
21961780d4 force dynamic typing on DynamicObject.Type to mitigate optimization issues 2017-11-01 19:38:38 +09:00
John Rommel Estropia
305e2b61a0 fix compile errors for Xcode 9.1 beta 2017-11-01 19:37:53 +09:00
John Estropia
0430f66240 force dynamic typing on DynamicObject.Type to mitigate optimization issues 2017-11-01 11:33:41 +09:00
John Estropia
65772edd00 Merge pull request #208 from volodg/prototype/Swift_4_0
(Xcode 9.1) fix compile error:
2017-10-29 18:55:13 +09:00
John Rommel Estropia
02d7870d75 fix compile errors for Xcode 9.1 beta 2017-10-29 15:20:58 +09:00
John Rommel Estropia
aca1709e13 WIP: documentation 2017-10-29 15:06:57 +09:00
John Rommel Estropia
b6ee0b014f WIP: documentations 2017-10-24 00:31:27 +09:00
John Estropia
e37186da73 Merge branch 'prototype/Swift_3_2' into prototype/Swift_4_0
# Conflicts:
#	CoreStore.podspec
#	Sources/Info.plist
2017-10-17 13:42:04 +09:00
John Estropia
588fa35c84 version bump 2017-10-17 13:39:57 +09:00
John Estropia
f6614cda66 Merge branch 'develop' 2017-10-17 13:39:20 +09:00
John Estropia
639574d8c2 remove inline casts because optimized builds seem to trip on them 2017-10-17 13:38:25 +09:00
John Rommel Estropia
094703155c Merge branch 'master' into prototype/Swift_4_0
# Conflicts:
#	.swift-version
2017-10-13 08:14:20 +09:00
John Rommel Estropia
6dd254e713 Merge branch 'prototype/Swift_3_2' into prototype/Swift_4_0
# Conflicts:
#	CoreStore.podspec
#	Sources/Info.plist
2017-10-13 08:10:56 +09:00
John Rommel Estropia
204025721c version bump 2017-10-13 08:10:26 +09:00
John Rommel Estropia
27ffc1d225 Merge branch 'develop'
# Conflicts:
#	CoreStore.podspec
#	Sources/Info.plist
2017-10-13 08:01:30 +09:00
John Rommel Estropia
ba6f0c39d5 swift version 3.2 2017-10-13 08:00:39 +09:00
John Rommel Estropia
ab2eac8f6c Swift 3.2 README update 2017-10-13 07:58:37 +09:00
John Rommel Estropia
f460a0b30f CI: test demo app 2017-10-12 01:10:08 +09:00
John Rommel Estropia
50bc3ace06 travis 2017-10-12 00:02:39 +09:00
John Rommel Estropia
d2ddf2002f version update 2017-10-11 22:40:27 +09:00
John Rommel Estropia
b4117eeb02 updated documentation (fixes #198) 2017-10-11 07:50:24 +09:00
Vladimir
106275b2dd fix compile error:
inheritance from 'AnyObject'
2017-10-07 12:21:27 +08:00
John Rommel Estropia
08d9298be0 Merge branch 'prototype/Swift_4_0' into prototype/queryBuilders
# Conflicts:
#	Sources/OrderBy.swift
2017-10-07 01:13:30 +09:00
John Rommel Estropia
ff0c4d94fc Merge branch 'prototype/Swift_3_2' into prototype/Swift_4_0 2017-10-07 01:10:28 +09:00
John Rommel Estropia
50e50c0613 Merge branch 'develop' into prototype/Swift_3_2 2017-10-07 01:07:09 +09:00
John Rommel Estropia
5c8a0e425b version bump 2017-10-07 00:59:37 +09:00
John Rommel Estropia
03b71caf7e Merge branch 'develop' 2017-10-07 00:58:04 +09:00
John Rommel Estropia
7ff29d6086 version bump 2017-10-07 00:57:41 +09:00
John Rommel Estropia
8d86425875 always create subclass type from cs_rawObject 2017-10-07 00:56:19 +09:00
John Estropia
97242d9726 added type-erasers for CoreStoreObject property containers 2017-10-02 12:00:45 +09:00
John Estropia
780ff4e60b fix compile errors 2017-10-02 11:10:28 +09:00
John Estropia
11743dfb5f oops 2017-10-02 11:08:44 +09:00
John Estropia
9eaf85388c relax generic type requirements for some Where utilities 2017-10-02 10:33:59 +09:00
John Rommel Estropia
06635c9d2f orderby utilities 2017-10-02 08:04:28 +09:00
John Rommel Estropia
1d2eef7894 revert 2017-10-01 01:01:10 +09:00
John Rommel Estropia
85ed815ec2 WIP: more chain clause builder utilities 2017-10-01 00:45:21 +09:00
John Estropia
096e5493a6 WIP: protocol cleanup 2017-09-29 20:33:10 +09:00
John Estropia
0aa8c03424 Merge pull request #205 from jannon/case-insensitive-orderby
add case-insensitive sortkeys
2017-09-29 19:38:36 +09:00
John Estropia
4ead3c34dd delete errant operator 2017-09-26 11:59:28 +09:00
John Rommel Estropia
645034dde5 keyPath utilities for SectionBy clauses 2017-09-24 10:38:17 +09:00
John Rommel Estropia
85706a3c57 version bump 2017-09-22 23:43:19 +09:00
John Rommel Estropia
c5ae4606b9 move cocoapods.yml 2017-09-22 23:41:07 +09:00
John Rommel Estropia
fa682215c5 version bump 2017-09-22 23:26:15 +09:00
John Rommel Estropia
e814733ae9 Merge branch 'prototype/Swift_4_0' into prototype/queryBuilders
# Conflicts:
#	Sources/DynamicObject.swift
2017-09-22 23:20:16 +09:00
John Rommel Estropia
e2236698fa Merge branch 'prototype/Swift_3_2' into prototype/Swift_4_0 2017-09-22 23:18:38 +09:00
John Rommel Estropia
be5da632b3 fix segmentation fault 2017-09-22 23:18:25 +09:00
John Estropia
dc73cd6dd9 added a yml file for pod try (#200) 2017-09-22 15:48:02 +09:00
John Rommel Estropia
7beb3bec75 rename methods 2017-09-22 08:02:13 +09:00
Jannon Frank
53100b202d add case-insensitive sortkeys 2017-09-21 11:38:29 -07:00
John Rommel Estropia
cc84b1f8bd minor 2017-09-22 01:00:03 +09:00
John Rommel Estropia
474f52ed2b alow nil comparison for relationship keypaths 2017-09-22 00:30:02 +09:00
John Rommel Estropia
16225fc4c6 allow optionals in relationship keyPaths 2017-09-22 00:20:55 +09:00
John Rommel Estropia
03bb7619da added queryBuilder utilities for clause sequences 2017-09-22 00:08:01 +09:00
John Rommel Estropia
1bfb7451c3 keyPath utilities for Select queries 2017-09-21 07:56:02 +09:00
John Rommel Estropia
3e082d5ed4 queryBuilders for list monitors 2017-09-20 00:45:38 +09:00
John Rommel Estropia
e45d67252c CoreStore querying utilities 2017-09-20 00:24:03 +09:00
John Rommel Estropia
3d427c29c4 added required settings 2017-09-20 00:09:57 +09:00
John Rommel Estropia
1068517b94 Merge branch 'prototype/queryBuilders' of github.com:JohnEstropia/CoreStore into prototype/queryBuilders 2017-09-20 00:02:36 +09:00
John Estropia
0d23ce1598 fix Demo app compiler errors 2017-09-19 16:22:59 +09:00
John Estropia
fd1ce20863 set swift version 2017-09-19 16:04:26 +09:00
John Estropia
2c5fa63f40 revert 2017-09-19 15:55:51 +09:00
John Estropia
78e43a37a5 fix OSX compiler errors 2017-09-19 15:54:15 +09:00
John Rommel Estropia
fde85a9743 Merge branch 'prototype/Swift_4_0' into prototype/queryBuilders 2017-09-17 01:15:55 +09:00
John Rommel Estropia
dbbc0adae5 Merge branch 'prototype/Swift_3_2' into prototype/Swift_4_0 2017-09-17 01:10:11 +09:00
John Rommel Estropia
2a62770552 Merge branch 'develop' into prototype/Swift_3_2 2017-09-10 12:31:30 +09:00
John Rommel Estropia
f436b26e8e allow compound keypaths in Select terms 2017-09-08 01:28:24 +09:00
John Rommel Estropia
c566226747 Merge branch 'prototype/Swift_4_0' into prototype/queryBuilders 2017-08-31 23:50:12 +09:00
John Rommel Estropia
cd405e038e updated demo app 2017-08-31 23:00:17 +09:00
John Estropia
92a37053b0 Merge branch 'prototype/Swift_3_2' into prototype/Swift_4_0 2017-08-31 18:33:28 +09:00
John Estropia
0b57cff27d Merge branch 'develop' into prototype/Swift_3_2
# Conflicts:
#	Sources/DynamicSchema+Convenience.swift
2017-08-31 18:33:12 +09:00
John Estropia
3ebc44b546 optimize redundant casting in printCoreStoreSchema() 2017-08-31 18:28:23 +09:00
John Estropia
68f1027ba7 fix code misuse in readme 2017-08-31 17:55:10 +09:00
John Rommel Estropia
005729be85 Merge branch 'prototype/Swift_4_0' into prototype/queryBuilders 2017-08-26 14:29:16 +09:00
John Estropia
8bac4aa901 Fixed Xcode 9 beta 6 errors 2017-08-24 10:11:12 +09:00
John Estropia
da170c7e51 Fixed Xcode 9 beta 6 errors 2017-08-23 18:40:06 +09:00
John Estropia
211e69023e version bump 2017-08-23 12:59:36 +09:00
John Rommel Estropia
2912dcf010 iOS 11 fixed the NSFetchRequest.affectedStores bug 2017-08-23 12:55:02 +09:00
John Rommel Estropia
3e00a3da06 fix demo app errors 2017-08-17 09:24:33 +09:00
John Rommel Estropia
a33e248828 Merge branch 'prototype/Swift_4_0' into prototype/queryBuilders
# Conflicts:
#	Sources/NSManagedObjectContext+Querying.swift
2017-08-16 21:09:09 +09:00
John Rommel Estropia
75e14fbbed Merge branch 'prototype/Swift_3_2' into prototype/Swift_4_0
# Conflicts:
#	Sources/NSManagedObjectContext+Querying.swift
2017-08-16 21:08:33 +09:00
John Rommel Estropia
9922deac4d Merge branch 'develop' into prototype/Swift_3_2
# Conflicts:
#	Sources/AttributeProtocol.swift
#	Sources/DynamicSchema+Convenience.swift
#	Sources/ImportableAttributeType.swift
#	Sources/Relationship.swift
#	Sources/RelationshipProtocol.swift
#	Sources/Transformable.swift
#	Sources/Value.swift
2017-08-16 21:07:34 +09:00
John Rommel Estropia
86be046c9f updated podspec 2017-08-16 20:43:10 +09:00
John Rommel Estropia
0f10bc3349 version bump 2017-08-16 20:26:22 +09:00
John Rommel Estropia
9685f0aef2 #191 2017-08-16 20:21:26 +09:00
John Estropia
1e51000155 Merge pull request #191 from sidmani/prototype/Swift_4_0
Corrected type-checking in fetchExisting to preserve input type
2017-08-16 20:20:23 +09:00
John Rommel Estropia
3bd459bb1a updated docs 2017-08-16 20:09:09 +09:00
Sid Mani
c89bc3c227 Corrected type-checking in fetchExisting to preserve input type 2017-08-16 00:36:06 -07:00
John Rommel Estropia
0f405a50aa WIP: KeyPath utilities for all clauses 2017-08-10 00:42:29 +09:00
John Estropia
f5e1643ef7 minor cleanup 2017-08-10 00:10:15 +09:00
John Rommel Estropia
f62137fb58 rename file 2017-08-10 00:10:08 +09:00
John Rommel Estropia
37fbedd799 WIP: keypath utilities for all raw clauses 2017-08-09 08:11:41 +09:00
John Rommel Estropia
28b43f33fa Value.Required now requires an "initial:" parameter. For previous CoreStoreObject users, use the appropriate empty value for your existing properties (0 for numeric types, false for Bool, "" for String) 2017-08-08 18:36:25 +09:00
John Rommel Estropia
81a72f29ea Merge branch 'prototype/Swift_4_0' into prototype/queryBuilders 2017-08-08 08:02:17 +09:00
John Rommel Estropia
f7aaf4fb2a Fix compile errors for Xcode 9 beta 5 2017-08-08 08:02:05 +09:00
John Rommel Estropia
a52acf2ebd Merge branch 'prototype/Swift_3_2' into prototype/Swift_4_0 2017-08-08 07:56:32 +09:00
John Rommel Estropia
74c64619c3 Fix compile error for Xcode 9 beta 5 2017-08-08 07:56:21 +09:00
John Rommel Estropia
4a5bc6450b complete query utilities 2017-08-08 07:36:52 +09:00
John Rommel Estropia
fe69e7c6c4 Merge branch 'prototype/Swift_4_0' into prototype/queryBuilders
# Conflicts:
#	CoreStore.xcodeproj/project.pbxproj
#	Sources/Relationship.swift
#	Sources/Value.swift
2017-08-05 23:02:00 +09:00
John Rommel Estropia
ccf7c62aad Merge branch 'prototype/Swift_3_2' into prototype/Swift_4_0 2017-08-05 08:25:49 +09:00
John Rommel Estropia
f36cb8af63 iOS 11 fixed the NSFetchRequest.affectedStores bug 2017-08-05 08:25:28 +09:00
John Rommel Estropia
10ccadd96c update demo app 2017-08-05 08:25:03 +09:00
John Rommel Estropia
5c0e78bd53 Deleted EmptyableAttributeType and require "initial" parameter for Value.Required 2017-08-05 00:03:17 +09:00
John Rommel Estropia
8a09688117 Merge branch 'develop' into prototype/Swift_3_2 2017-07-15 21:30:05 +09:00
John Estropia
a366bcf1a3 Merge branch 'develop' of github.com:JohnEstropia/CoreStore into develop 2017-07-11 15:47:20 +09:00
John Rommel Estropia
fcd4be9011 WIP: chained queries for section monitors 2017-07-10 08:23:59 +09:00
John Rommel Estropia
535eb76adc WIP: query chains! 2017-07-09 10:44:53 +09:00
John Rommel Estropia
c6e68ac24f reset transactions' context on deinit to break reference cycles in unsafed many-to-many relationships 2017-07-05 23:32:45 +09:00
John Rommel Estropia
aff966aac9 WIP: Query builders 2017-07-05 08:45:10 +09:00
John Rommel Estropia
32743b3aee Merge branch 'prototype/Swift_3_2' into prototype/Swift_4_0 2017-07-04 23:16:49 +09:00
John Rommel Estropia
a20ad87583 Merge branch 'develop' into prototype/Swift_3_2 2017-07-04 23:14:06 +09:00
John Estropia
a11915db12 minor cleanup 2017-07-04 12:21:46 +09:00
John Rommel Estropia
961f39a806 add internal utilities to force checkpoint operations on SQLite 2017-07-01 17:05:10 +09:00
John Rommel Estropia
3096cb784c add internal utilities to force checkpoint operations on SQLite 2017-07-01 16:45:11 +09:00
John Rommel Estropia
809aa4ff96 allow querying file size on SQLiteStore 2017-07-01 11:50:23 +09:00
John Estropia
8d926d25ec Merge pull request #177 from blender/feature/optional-where-chaining
Add optional && and || operators to Where clause
2017-06-28 13:32:16 +09:00
Tommaso Piazza
790454f514 Add optional && and || operators to Where clause 2017-06-27 13:58:16 +02:00
John Rommel Estropia
9a38707c58 Merge branch 'prototype/Swift_3_2' into prototype/Swift_4_0 2017-06-26 00:36:07 +09:00
John Rommel Estropia
fb7e2f7f7f Merge branch 'develop' into prototype/Swift_3_2 2017-06-26 00:34:32 +09:00
John Rommel Estropia
f72efc80b2 added utilities for combining Where arrays and OrderBy arrays 2017-06-24 17:42:56 +09:00
John Estropia
fcda5399da Merge branch 'prototype/Swift_3_2' into prototype/Swift_4_0 2017-06-23 17:58:49 +09:00
John Estropia
fd3a9b00ec fix FRC breaking again for iOS 8 2017-06-23 17:58:34 +09:00
John Estropia
f56c37f9ee Merge branch 'prototype/Swift_3_2' into prototype/Swift_4_0 2017-06-23 12:43:20 +09:00
John Estropia
5f5000218a Merge branch 'develop' into prototype/Swift_3_2
# Conflicts:
#	CoreStoreDemo/CoreStoreDemo/List and Object Observers Demo/Palette.swift
#	Sources/Value.swift
2017-06-23 12:43:03 +09:00
John Estropia
e8eb309d82 Added source docs on usage of custom getters and setters for CoreStoreObject properties (Value.Required, etc) 2017-06-20 20:32:27 +09:00
John Rommel Estropia
d0c3203e63 force reset contexts after autocommit 2017-06-17 21:50:21 +09:00
John Rommel Estropia
f5b3901caa fix tests and demo app 2017-06-17 02:13:54 +09:00
John Rommel Estropia
1a99fea820 complete PartialObject utilities 2017-06-17 01:55:36 +09:00
John Rommel Estropia
195b60615b added missing utilities 2017-06-16 01:42:09 +09:00
John Rommel Estropia
2c394965b8 remove direct access to CoreStoreObject.primitiveValues and replace PartialObject<O> 2017-06-16 01:02:23 +09:00
John Rommel Estropia
746d697691 WIP: new PartialObject to act as faster KVC wrappers when implementing custom getters and setters for CoreStoreObject 2017-06-15 08:27:08 +09:00
John Estropia
5689158b43 version bump 2017-06-14 21:50:58 +09:00
John Estropia
6fcdf3d011 fix logger demo 2017-06-14 17:43:34 +09:00
John Estropia
e26573c18e converted the Demo app's observer demo to use CoreStoreObject instead of NSManagedObject 2017-06-14 17:39:57 +09:00
John Estropia
801cf8d9f0 Fixed ListMonitor bug for CoreStoreObjects where ListObservers don't get update notifications 2017-06-14 17:37:46 +09:00
John Rommel Estropia
eced8f2e93 fixed compile error on release mode 2017-06-12 22:39:06 +09:00
John Rommel Estropia
3b735d07ec fix merge compile errors 2017-06-11 09:33:25 +09:00
John Rommel Estropia
5eb5476e3a Merge branch 'prototype/Swift_3_2' into prototype/Swift_4_0 2017-06-11 09:17:03 +09:00
John Rommel Estropia
6a42a0054e Merge branch 'develop' into prototype/Swift_3_2
# Conflicts:
#	Sources/CoreStoreManagedObject.swift
#	Sources/CoreStoreSchema.swift
#	Sources/NSEntityDescription+DynamicModel.swift
#	Sources/Value.swift
2017-06-11 09:16:34 +09:00
John Rommel Estropia
8c437e19b8 version bump 2017-06-10 23:19:02 +09:00
John Rommel Estropia
9cd3b6c879 code cleanup 2017-06-10 22:13:32 +09:00
John Rommel Estropia
fe135acbec Improve CoreStoreObjects KVO behavior 2017-06-10 21:02:36 +09:00
John Estropia
997c5bdcfa uniquify subclass names across model versions 2017-06-09 12:47:22 +09:00
John Estropia
23e12c4539 add constraints to Value.Optional and Value.Required native types 2017-06-09 11:30:09 +09:00
John Estropia
ca9798be14 add constraints to Value.Optional and Value.Required native types 2017-06-09 11:29:51 +09:00
John Estropia
6e01a58c85 Swift 4 support 2017-06-09 11:25:28 +09:00
John Estropia
f618617053 work around issue that crashes the Swift 3.2 compiler (fixes #171) 2017-06-08 20:18:50 +09:00
John Rommel Estropia
49b8b9c372 Merge branch 'master' into prototype/Swift_3_2 2017-06-08 08:10:59 +09:00
John Rommel Estropia
129f975d96 version bump 2017-06-08 01:17:39 +09:00
John Rommel Estropia
a2e463e58c Merge branch 'prototype/customMigrationTest' of github.com:JohnEstropia/CoreStore into prototype/customMigrationTest 2017-06-08 01:07:00 +09:00
John Rommel Estropia
5fd50f0e15 fix migration for CoreStoreObject relationships 2017-06-08 01:06:51 +09:00
John Estropia
7f9a915d71 WIP: Swift 3.2 2017-06-07 20:07:43 +09:00
John Estropia
0a81736b7a Merge branch 'develop' into prototype/customMigrationTest 2017-06-07 12:31:42 +09:00
John Estropia
f9b6dd0c6a fix bug when using ObjectMonitor with CoreStoreObjects 2017-06-06 17:40:29 +09:00
John Rommel Estropia
0354401b56 WIP: bugfix for CustomSchemaMappingProvider relationship migration bug 2017-06-06 08:39:59 +09:00
John Rommel Estropia
0304067beb fix ToManyOrdered and ToManyUnordered enumeration crash 2017-06-06 00:49:16 +09:00
John Rommel Estropia
ddd83da434 add Where comparison operators for optional values 2017-06-05 23:09:19 +09:00
John Estropia
fc7df671de Fixes https://bugs.swift.org/browse/SR-4981 2017-06-05 12:45:35 +09:00
John Rommel Estropia
5fde9030c7 use stronger namespace for CoreStoreObject's internal managed object type 2017-06-05 08:03:37 +09:00
John Rommel Estropia
d7b07b3f00 Added alternative way to set keyPathsForValuesAffectingValue(forKey:) for CoreStoreObjects 2017-06-05 01:30:26 +09:00
John Rommel Estropia
ddd1ffb29f added ~= operation to create Where clauses for value arrays 2017-06-03 08:51:52 +09:00
John Rommel Estropia
98094000bb Merge branch 'master' into develop 2017-06-02 23:10:31 +09:00
John Estropia
d5026ef996 Merge branch 'temp/develop' into develop 2017-06-02 19:35:01 +09:00
John Estropia
2cd913b9dd added more utilities for CoreStoreObject meta 2017-06-02 19:34:54 +09:00
John Estropia
ad9520abbc Update README.md 2017-06-02 13:24:15 +09:00
John Estropia
c0fc57d10c Update README.md 2017-06-02 11:34:04 +09:00
John Estropia
0cf4d303e4 Added README sample on how to version CoreStoreObjects 2017-06-02 11:32:48 +09:00
John Rommel Estropia
6de397958a fix demo app warnings 2017-06-02 02:06:47 +09:00
John Rommel Estropia
55292a84dc made mapping modell providers public 2017-06-02 02:03:41 +09:00
John Estropia
981b560d53 test travis ci 2017-05-30 11:14:57 +09:00
John Estropia
c4c4dd55cd test travis build 2017-05-30 11:06:30 +09:00
John Rommel Estropia
1ddbe20c86 Updated README, fixed demo app, and bumped to 4.0.1 2017-05-28 11:37:40 +09:00
John Rommel Estropia
da9e8c1550 disallow "empty" default values on some ImportableAttributeTypes 2017-05-28 10:50:25 +09:00
John Estropia
ef0937fec4 make unit tests happy 2017-05-24 12:15:55 +09:00
John Estropia
35885b40de README done! Welcome to CoreStore 4.0! 2017-05-24 12:05:34 +09:00
John Rommel Estropia
d669569196 WIP: readme 2017-05-24 00:37:32 +09:00
John Rommel Estropia
ae919ff3c8 WIP: readme 2017-05-24 00:35:25 +09:00
John Rommel Estropia
1a7a4690d1 WIP: readme 2017-05-24 00:33:43 +09:00
John Rommel Estropia
b9b96d1a35 WIP: Updating README and other docs. Some minor fixes 2017-05-22 01:27:38 +09:00
John Rommel Estropia
da3a9590ac accept optionals in setValue 2017-05-21 09:38:56 +09:00
John Rommel Estropia
6b3d75bea1 fix fixits 2017-05-21 09:29:34 +09:00
John Rommel Estropia
d44721fef0 fix xcode hints 2017-05-21 09:11:34 +09:00
John Rommel Estropia
3f268e8376 added NSManagedObject.setValue(_:forKvcKey:willSetValue:didSetValue:) 2017-05-21 09:06:29 +09:00
John Rommel Estropia
303fea4ebe fix warnings 2017-05-21 08:51:38 +09:00
John Estropia
77173cdad0 minor fix 2017-05-18 21:10:43 +09:00
John Estropia
1e24a7d739 ListObserver's listMonitorDidChange(_:) and listMonitorDidRefetch(_:) handlers are now required. 2017-05-18 12:59:58 +09:00
John Estropia
a3b33bedb8 added more migration error types 2017-05-18 12:59:02 +09:00
John Estropia
eaf7544c50 fix error when CoreStoreObject types have deep namespaces 2017-05-17 15:55:33 +09:00
John Estropia
67863120e0 WIP: readme 2017-05-15 11:03:21 +09:00
John Estropia
1b0e305d9a beta bump 2017-05-15 10:23:55 +09:00
John Rommel Estropia
91fda01071 WIP: readme 2017-05-15 08:51:31 +09:00
John Estropia
feb0e30735 tag as beta 2017-05-12 14:46:28 +09:00
John Rommel Estropia
9c25336ff6 WIP: documentation 2017-05-12 01:42:19 +09:00
John Estropia
66bef87422 WIP: documentation 2017-05-11 20:55:31 +09:00
John Rommel Estropia
dd2949ee18 WIP: documentation 2017-05-11 00:03:13 +09:00
John Estropia
e0abb9b0af Merge branch 'develop' into corestore4_develop
# Conflicts:
#	CoreStore.podspec
#	Sources/CoreStoreImportableAttributeType.swift
#	Sources/CoreStoreQueryableAttributeType.swift
#	Sources/Info.plist
#	Sources/NSManagedObjectModel+Setup.swift
2017-05-10 19:11:01 +09:00
John Estropia
42c28b064a remove unneeded swift flags 2017-05-10 12:47:40 +09:00
John Estropia
0b097b8c85 version bump 2017-05-10 12:43:18 +09:00
John Estropia
fce5d2f301 Flatten file directories (fixes #159) 2017-05-10 12:42:20 +09:00
John Rommel Estropia
8ff163af30 WIP: documentation 2017-05-10 02:00:47 +09:00
John Estropia
19abedfa9f WIP: documentation 2017-05-09 21:16:03 +09:00
John Estropia
48828fdca3 Custom migrations! 2017-05-09 17:58:41 +09:00
John Rommel Estropia
9d65a27557 WIP: custom migration 2017-05-09 03:10:35 +09:00
John Rommel Estropia
6d04806608 WIP 2017-04-26 08:31:37 +09:00
John Rommel Estropia
54129f7362 Merge branch 'corestore4_develop' of github.com:JohnEstropia/CoreStore into corestore4_develop 2017-04-25 22:08:58 +09:00
John Estropia
54c81d23f5 WIP: dynamic migrations 2017-04-25 18:08:43 +09:00
John Estropia
53ab140341 Improve refetch method (may fix #118) 2017-04-24 11:57:47 +09:00
John Estropia
9dc4331b26 oops 2017-04-21 21:21:47 +09:00
John Estropia
e6aa72fb5f support transformable values 2017-04-21 19:35:29 +09:00
John Estropia
274a54451a fix compiler errors 2017-04-21 15:07:26 +09:00
John Estropia
fe70b7a27d added tool to convert existing NSManagedObjectModels to the new CoreStoreSchema 2017-04-21 14:54:57 +09:00
John Estropia
02a660e4a6 WIP: Migrations 2017-04-20 20:26:11 +09:00
John Estropia
a543a4c94a Added a "userInfo" property to relevant types to allow external code to store custom data 2017-04-20 16:40:27 +09:00
John Estropia
fd14a18248 Unify generics usage in ListMonitor and ObjectMonitor 2017-04-20 10:42:47 +09:00
John Estropia
b0e2655bdf added a typealias for the object type contained in ListMonitor and ObjectMonitor 2017-04-19 17:04:34 +09:00
John Estropia
b6bc7c2edf allow edit() calls to any DynamicObject 2017-04-18 18:14:16 +09:00
John Estropia
1938f0d9de no need to be optional 2017-04-18 12:09:37 +09:00
John Estropia
94e6db669f added a way to lazily-initialize user info data 2017-04-18 12:02:39 +09:00
John Estropia
b1972b82f1 added way to store userInfo in DataStack and in transactions 2017-04-18 11:29:16 +09:00
John Rommel Estropia
5ffaca1375 WIP: docs 2017-04-18 08:02:07 +09:00
John Estropia
a73306fecb check correct queue for managed object value access 2017-04-12 19:22:18 +09:00
John Estropia
9f3db61ff7 WIP: allow migrations for CoreStoreObjects 2017-04-11 19:13:35 +09:00
John Estropia
e5ef4992d3 WIP: migrations for CoreStoreObjects 2017-04-07 21:57:45 +09:00
John Estropia
c0ae129b22 NSManagedObject features are now fully supported for CoreStoreObject types. MacOSX 10.12 onwards now support ListMonitors and ObjectMonitors 2017-04-07 20:14:13 +09:00
John Estropia
4aa1a63f9a updated unit tests with easier to understand examples 2017-04-06 20:45:54 +09:00
John Estropia
4fc10afe1e relationships done! 2017-04-06 20:28:17 +09:00
John Estropia
8b77e4e5a0 WIP: prototype for ManagedObjectProtocol 2017-04-05 21:56:19 +09:00
John Estropia
258c237100 It works! (WIP!) 2017-04-04 20:25:40 +09:00
John Estropia
6948db516d WIP: typesafe queries 2017-04-03 22:02:24 +09:00
John Estropia
b5d80fd272 WIP: Dynamic models (Goodbye xcdatamodel files!) 2017-04-03 21:41:25 +09:00
John Rommel Estropia
cdcd7d0416 removed deprecated functions in unit tests and demo app 2017-04-01 23:08:36 +09:00
John Rommel Estropia
a5162239d5 kick-off deprecations with 4.0 version bump 2017-04-01 21:23:50 +09:00
John Rommel Estropia
1ad6ac5769 accept NSManagedObject as Where predicate argument 2017-04-01 17:15:24 +09:00
John Rommel Estropia
ecb3d0cfa0 revert prototyped stack setup 2017-04-01 01:31:40 +09:00
John Estropia
81355fd9c5 update travis file for Xcode 8.3 2017-03-31 19:56:19 +09:00
John Estropia
97d7a276fe new auto-commit transaction methods 2017-03-31 19:44:18 +09:00
John Estropia
d72d1afe8b Merge branch 'develop' into corestore4_develop
# Conflicts:
#	CoreStore.xcodeproj/project.pbxproj
2017-03-28 11:38:02 +09:00
John Estropia
716e069984 version bump 2017-03-28 11:25:24 +09:00
John Estropia
881ee4af0a remove warnings when calling unsafeBitCast() 2017-03-28 10:54:08 +09:00
John Estropia
acc0ce1c32 Merge pull request #157 from ruslanskorb/fetched-objects-dynamicCast
Use `dynamicCast()` to cast `fetchedObjects` to `[T]?` without checking the type.
2017-03-28 10:10:23 +09:00
John Estropia
b97f6d6a0a Merge branch 'prototype/mainContextToPSC' into corestore4_develop 2017-03-27 14:08:07 +09:00
John Rommel Estropia
818abfc1a1 WIP 2017-03-27 01:48:51 +09:00
Ruslan Skorb
f055c54a66 [ListMonitor] Use dynamicCast() to cast fetchedObjects to [T]? without checking the type.
Type checking takes a time. So there is a performance problem when casting a large number of fetched objects to an array of a certain type using the operator `as?`.
2017-03-24 21:30:46 +02:00
John Estropia
cb6d5b015b WIP: prototyping new transaction structure 2017-03-24 21:15:51 +09:00
John Rommel Estropia
494965de23 changed protocol naming 2017-03-10 08:30:12 +09:00
John Estropia
fe25a9aa36 remove warnings when calling unsafeBitCast() 2017-03-09 18:59:37 +09:00
John Estropia
f21e4e12e0 Merge branch 'develop' into corestore4_develop 2017-03-09 18:08:35 +09:00
John Estropia
92890d1e1d Merge pull request #154 from ruslanskorb/remove-duplicate-code
[FetchedResultsControllerDelegate] Remove duplicate code.
2017-03-07 12:58:18 +09:00
Ruslan Skorb
0c483e0e19 [FetchedResultsControllerDelegate] Remove duplicate code. 2017-03-05 12:20:12 +02:00
John Rommel Estropia
6055685c00 WIP: compilable again now 2017-03-02 22:26:45 +09:00
John Rommel Estropia
ee71442b08 Merge branch 'develop' into corestore4_develop 2017-03-02 21:07:30 +09:00
John Estropia
341ec5e771 reverted unsafeDowncast usage to unsafeBitCast (It worked differently) 2017-03-01 19:56:13 +09:00
John Estropia
8569c3c524 WIP: rehaul of type-safe fetching and querying 2017-03-01 19:34:07 +09:00
John Estropia
3224fcf71d move type safety goodness 2017-02-21 19:17:06 +09:00
John Rommel Estropia
9ff1c9d545 declare operators as static functions 2017-02-19 20:05:23 +09:00
John Rommel Estropia
c40d17a6ad Merge branch 'develop' of github.com:JohnEstropia/CoreStore into develop 2017-02-19 09:56:40 +09:00
John Estropia
9d5e04854a extra extra type safety for attributes (fetching and importing) 2017-02-17 14:13:16 +09:00
John Estropia
d2fd03c1f0 Where clauses are now more strict with the argument types 2017-02-17 10:47:38 +09:00
John Rommel Estropia
7baaee493d unit test for scalar IDs for ImportableUniqueObject 2017-02-13 22:17:03 +09:00
John Estropia
03973790a8 revert recent swizzling update. sorry about that 2017-02-10 20:33:07 +09:00
John Estropia
7ee027f44d Test mainContext fetching directly from PSC. Needs benchmarking esp. with merging 2017-02-09 10:49:50 +09:00
John Estropia
19fea6953a Merge branch 'master' into develop 2017-02-08 13:13:27 +09:00
John Estropia
9f11b1005d added .swift-version file 2017-02-08 13:08:44 +09:00
John Estropia
698326f89a version bump 2017-02-07 18:21:54 +09:00
John Estropia
bdf6308d8f swift 3.1 support 2017-02-07 18:17:40 +09:00
John Estropia
69d96c53d6 WIP: object concurrency debugging utilities 2017-02-02 19:53:47 +09:00
John Estropia
7b961fa249 Display list of model files in bundle when requested modelname is not found 2017-02-01 19:03:59 +09:00
John Estropia
73450d0b29 WIP: minor conveniences to the ImportableUniqueObject protocol 2017-01-20 21:51:00 +09:00
John Estropia
6d83564a1a Swift 3 master candidate 2017-01-06 16:50:38 +09:00
John Estropia
c0d72799b4 Merge branch 'swift3_develop' into develop
# Conflicts:
#	.travis.yml
#	CoreStore.podspec
#	CoreStore.xcodeproj/project.pbxproj
#	Sources/Info.plist
2017-01-06 16:03:28 +09:00
John Estropia
06a1919e91 minor fixes 2017-01-06 15:56:47 +09:00
John Rommel Estropia
16def2d84b disable tests on iOS 8.2 and 8.1 (keeps failing due to xcode bug) 2016-12-31 13:14:50 +08:00
John Rommel Estropia
e9a2c58f32 travis bug 2016-12-31 11:26:35 +08:00
John Rommel Estropia
1a3e0dd4c6 CoreStore 3 master candidate 2016-12-31 11:03:03 +08:00
John Rommel Estropia
518bb134f9 merge fix 2016-12-26 14:55:06 +08:00
John Estropia
4d7feca848 Merge pull request #139 from deanWombourne/swift3_develop
Add an override to cs_typeName which deals with String explicitly.
2016-12-26 14:53:51 +08:00
John Rommel Estropia
64a80bf401 Swift 3.0.1 support 2016-12-26 14:51:36 +08:00
John Rommel Estropia
4d63fc744a Add String overload for cs_typeName (fixes #138) 2016-12-26 14:51:23 +08:00
Sam Dean
9480e372f1 Add an override to cs_typeName which deals with String explicitly. 2016-12-23 11:06:09 +00:00
John Rommel Estropia
23df460c35 require transaction logs path from icloud stores 2016-12-10 18:39:53 +09:00
John Rommel Estropia
1c233b7302 don't access iCloud's ubiquitous cache file 2016-12-10 09:43:45 +09:00
John Estropia
f42288802c Merge branch 'swift3_develop' of github.com:JohnEstropia/CoreStore into swift3_develop
# Conflicts:
#	Sources/Convenience/NSManagedObject+Convenience.swift
2016-12-08 19:00:38 +09:00
John Estropia
a27556f294 minor Swift 3 cleanup 2016-12-08 18:59:41 +09:00
John Rommel Estropia
e330291e1b support generics for KVC accessors 2016-12-03 10:13:50 +09:00
John Rommel Estropia
4a282150f0 utilities for safer KVO access in objects 2016-12-03 09:59:17 +09:00
John Rommel Estropia
5d2956d674 Make RecreateStoreOnModelMismatch flag work again (fixes #126) 2016-11-26 16:19:12 +09:00
John Estropia
92756fec42 always dispatch completion right after adding a store to the coordinator (allow stores to fully complete their run loop) 2016-11-17 16:27:28 +09:00
John Estropia
2b37daefe0 minor documentation updates 2016-11-17 14:31:06 +09:00
John Estropia
5724d4599e Merge pull request #122 from ruslanskorb/rename-error-type-to-error
`ErrorType` has been renamed to `Error` in Swift 3.
2016-11-17 13:34:03 +09:00
Ruslan Skorb
4a882e6108 ErrorType has been renamed to Error in Swift 3. 2016-11-15 19:16:18 +02:00
John Estropia
b230ed6400 FetchableSource and QueryableSource protocols 2016-11-15 18:00:39 +09:00
John Estropia
33a5c123aa resurrect utilities for creating NSFetchedResultsController (fixes #119) 2016-11-11 17:32:13 +09:00
John Estropia
73637321ce xcode 8.1 (swift 3.0.1) update 2016-11-11 14:03:37 +09:00
John Estropia
088f1717f9 Merge pull request #115 from deville/import-unique-objects-order
Import unique objects in the same order as the array of import sources (with fix for potential duplicates)
2016-11-11 11:46:27 +09:00
John Estropia
cff2bb1740 version bump 2016-10-27 19:16:17 +09:00
John Estropia
d902d62172 Turn off whole-module-optimization to prevent Swift compiler bugs (#113) 2016-10-27 18:41:27 +09:00
John Estropia
b955495012 Turn off whole-module-optimization to prevent Swift compiler bugs (#113) 2016-10-27 18:30:35 +09:00
Andrii Chernenko
d2e78a70e1 add test for the order of unique object import 2016-10-23 16:22:26 +02:00
Andrii Chernenko
970957cbc2 Merge branch 'duplicate-import-fix' into import-unique-objects-order 2016-10-23 14:52:34 +02:00
John Rommel Estropia
2f9e5db89f Added comment (fixes #106) 2016-10-16 14:40:25 +09:00
John Estropia
1789eb7daf Merge pull request #112 from JohnEstropia/revert-109-import-unique-objects-order
Revert "Import unique objects in the same order as the array of import sources"
2016-10-14 17:46:27 +09:00
John Estropia
3999654ee7 Revert "Import unique objects in the same order as the array of import sources" 2016-10-14 17:45:31 +09:00
Andrii Chernenko
4c3bec287c fix duplication when using importUniqueObjects with non-unique import sources 2016-10-12 02:01:23 +02:00
John Estropia
2a2d9b3483 Merge pull request #109 from deville/import-unique-objects-order
Import unique objects in the same order as the array of import sources
2016-10-10 20:29:59 +09:00
Andrii Chernenko
32a388e0ca import unique objects in the same order as the array of import sources 2016-10-08 23:14:22 +02:00
John Rommel Estropia
1a6fbad3d4 force dynamic dispatch on generic types 2016-10-09 00:52:18 +09:00
John Estropia
ac55f20f5f Merge pull request #108 from deville/type-method-dispatch-fix
Fix type method dispatch when importing objects
2016-10-08 10:43:21 +09:00
Andrii Chernenko
910b5039fd fix type method dispatch when importing objects 2016-10-07 15:26:45 +02:00
John Estropia
ffea06ee7e try again 2016-09-30 19:16:14 +09:00
John Estropia
a92d6cac02 try again 2016-09-30 19:08:17 +09:00
John Estropia
de5d660257 try again 2016-09-30 17:53:15 +09:00
John Estropia
55b2e6eecd try again 2016-09-30 17:36:48 +09:00
John Estropia
b64c776335 try again 2016-09-30 17:28:02 +09:00
John Estropia
432af667e8 try again 2016-09-30 17:08:04 +09:00
John Estropia
cf60a4bc2e updated travis.yml 2016-09-30 17:00:11 +09:00
John Estropia
c620859899 run demo project on CI 2016-09-30 13:58:11 +09:00
John Estropia
65ac069a0b skip observer testing on macOS 2016-09-30 13:32:31 +09:00
John Estropia
862ef27374 version bump, cleanup, unit test 2016-09-30 13:28:19 +09:00
John Estropia
243b6a76d5 Merge pull request #104 from colinmorelli/feature/sync-transaction-async-merge
Fixes #98 (deadlock when merge happens while main queue is querying)
2016-09-30 12:38:28 +09:00
Colin Morelli
8be20370d5 Fixes #98 (deadlock when merge happens while main queue is querying) 2016-09-29 14:47:51 -04:00
John Estropia
a9c0feae46 NSFetchRequest.affectedStores bug workaround 2016-09-27 19:02:24 +09:00
John Estropia
2e44f86eb6 Merge branch 'develop' into swift3_develop
# Conflicts:
#	Cartfile
#	Carthage/Checkouts/GCDKit
#	CoreStore.podspec
#	CoreStore.xcodeproj/project.pbxproj
#	CoreStoreDemo/CoreStoreDemo.xcodeproj/project.pbxproj
#	CoreStoreTests/BaseTests/BaseTestCase.swift
#	CoreStoreTests/FromTests.swift
#	CoreStoreTests/GroupByTests.swift
#	CoreStoreTests/OrderByTests.swift
#	CoreStoreTests/StorageInterfaceTests.swift
#	CoreStoreTests/TweakTests.swift
#	CoreStoreTests/WhereTests.swift
#	README.md
#	Sources/Internal/CoreStoreFetchRequest.swift
#	Sources/Internal/NSManagedObjectContext+Querying.swift
#	Sources/Internal/NSManagedObjectModel+Setup.swift
#	Sources/Migrating/DataStack+Migration.swift
#	Sources/ObjectiveC/CSSQliteStore.swift
#	Sources/ObjectiveC/CSStorageInterface.swift
#	Sources/ObjectiveC/CoreStoreBridge.swift
#	Sources/Observing/ListMonitor.swift
#	Sources/Setup/DataStack.swift
#	Sources/Setup/StorageInterfaces/ICloudStore.swift
#	Sources/Setup/StorageInterfaces/LegacySQLiteStore.swift
#	Sources/Setup/StorageInterfaces/SQLiteStore.swift
#	Sources/Setup/StorageInterfaces/StorageInterface.swift
2016-09-27 18:55:37 +09:00
John Estropia
ed8c7b35e8 Reduce leaking (a little) on the workaround for NSFetchRequest.affectedStores ARC bug 2016-09-27 17:31:08 +09:00
John Rommel Estropia
4d2ebe4ea8 workaround #100 (NSFetchRequest.affectedStores ARC bug) 2016-09-27 02:39:28 +09:00
John Estropia
54be9d471c renamed ImportableObject and ImportableUniqueObject protocol methods to Swift 3 naming style 2016-09-21 12:00:48 +09:00
John Rommel Estropia
f18d62f643 travis yml update 2016-09-17 14:27:36 +09:00
John Rommel Estropia
af141d4a31 travis yml update 2016-09-17 14:26:33 +09:00
John Rommel Estropia
2da659a967 travis yml update 2016-09-17 14:14:29 +09:00
John Rommel Estropia
e5f162c5e1 minor readme edits 2016-09-17 13:59:04 +09:00
John Rommel Estropia
effa231719 fix travis 2016-09-17 13:37:00 +09:00
John Rommel Estropia
6cef8f4b4f updated travis yml 2016-09-17 13:23:56 +09:00
John Rommel Estropia
aa6bceaaf3 working for Swift 2.3! 2016-09-17 12:22:25 +09:00
John Rommel Estropia
0dbd05b172 version bump 2016-09-11 14:30:32 +09:00
John Rommel Estropia
243c4044ab fix bridging producing base abstract class instead of subclass concrete class 2016-09-11 14:30:25 +09:00
John Rommel Estropia
df835114cb ignore errors when deleting wal files 2016-09-10 22:57:45 +09:00
John Rommel Estropia
f99d3cc21a fix RecreateStoreOnModelMismatch option not working when an existing xcdatamodel gets updated without adding a new version 2016-09-10 22:51:33 +09:00
John Estropia
a51ed1a007 WIP: Renaming to meet Swift 3 API guidelines 2016-09-09 18:30:08 +09:00
John Estropia
e5245a0e5b user #keyPath() for keys in demo app and in unit tests 2016-09-09 17:05:55 +09:00
John Estropia
0fa2a23461 workaround for iOS 10 regression in "affectedStores" retain bug 2016-09-09 13:09:13 +09:00
John Estropia
3f28198552 Magical NSFetchedResultsController bugfix.... 2016-09-09 12:49:10 +09:00
John Rommel Estropia
4a34012d58 version bump 2016-09-08 00:40:58 +09:00
John Estropia
45690a29c6 Merge pull request #92 from ThibaultVlacich/develop
Add DEBUG flag to the Debug config
2016-09-07 19:01:19 +09:00
Thibault Vlacich
0d4d036a86 Add DEBUG flag to the Debug config 2016-09-07 10:43:43 +02:00
John Estropia
82de482191 WIP: broken generics 2016-09-06 20:16:46 +09:00
John Estropia
b502895d63 Merge branch 'develop' into swift3_develop
# Conflicts:
#	Sources/Internal/NotificationObserver.swift
2016-09-06 12:05:40 +09:00
John Estropia
0ba63c6e72 WIP: Xcode 8 beta 6 2016-09-06 09:57:28 +09:00
John Rommel Estropia
e9be711d4c WIP: demo app 2016-07-25 08:21:22 +09:00
John Rommel Estropia
db5b8ca702 Merge branch 'develop' into swift3_develop
# Conflicts:
#	Cartfile.resolved
#	Carthage/Checkouts/GCDKit
#	CoreStoreTests/ErrorTests.swift
#	Sources/Fetching and Querying/Concrete Clauses/Select.swift
#	Sources/ObjectiveC/CSError.swift
2016-07-22 00:47:03 +09:00
John Rommel Estropia
2f39f9188b WIP: the great renaming 2016-07-21 23:12:24 +09:00
John Rommel Estropia
872e69ddc6 WIP 2016-07-21 08:34:13 +09:00
John Rommel Estropia
f9e33101a0 WIP 2016-07-21 08:32:16 +09:00
John Rommel Estropia
0621c54868 WIP 2016-07-21 02:48:23 +09:00
John Rommel Estropia
a638620858 WIP 2016-07-21 02:45:42 +09:00
John Rommel Estropia
267c21063a WIP: segfault 2016-07-20 08:12:04 +09:00
644 changed files with 455840 additions and 18433 deletions

2
.cocoapods.yml Normal file
View File

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

1
.gitignore vendored
View File

@@ -7,3 +7,4 @@ CoreStore.xcworkspace/xcuserdata
.DS_Store .DS_Store
DerivedData DerivedData
*.orig *.orig
build

3
.gitmodules vendored
View File

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

15
.jazzy.yaml Normal file
View File

@@ -0,0 +1,15 @@
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,5 +1,5 @@
language: objective-c language: objective-c
osx_image: xcode7.3 osx_image: xcode10
sudo: false sudo: false
git: git:
submodules: false submodules: false
@@ -10,22 +10,25 @@ env:
- LC_CTYPE=en_US.UTF-8 - LC_CTYPE=en_US.UTF-8
- LANG=en_US.UTF-8 - LANG=en_US.UTF-8
matrix: matrix:
- DESTINATION="OS=9.3,name=iPhone 6s" SCHEME="CoreStore iOS" SDK=iphonesimulator9.3 RUN_TESTS="YES" POD_LINT="NO" - DESTINATION="arch=x86_64" SCHEME="CoreStore OSX" SDK=macosx10.14 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=12.0,name=iPhone XS" SCHEME="CoreStore iOS" SDK=iphonesimulator12.0 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=11.0.1,name=iPhone 8" SCHEME="CoreStore iOS" SDK=iphonesimulator12.0 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=10.3.1,name=iPhone 7" SCHEME="CoreStore iOS" SDK=iphonesimulator12.0 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=10.1,name=iPhone 7" SCHEME="CoreStore iOS" SDK=iphonesimulator12.0 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=4.0,name=Apple Watch - 42mm" SCHEME="CoreStore watchOS" SDK=watchsimulator5.0 RUN_TESTS="NO" POD_LINT="NO"
- DESTINATION="OS=8.1,name=iPhone 4S" SCHEME="CoreStore iOS7" SDK=iphonesimulator9.3 RUN_TESTS="YES" POD_LINT="YES" - DESTINATION="OS=3.2,name=Apple Watch - 42mm" SCHEME="CoreStore watchOS" SDK=watchsimulator5.0 RUN_TESTS="NO" POD_LINT="NO"
- 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=watchsimulator5.0 RUN_TESTS="NO" 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=12.0,name=Apple TV 4K" SCHEME="CoreStore tvOS" SDK=appletvsimulator12.0 RUN_TESTS="YES" POD_LINT="NO"
- DESTINATION="OS=9.2,name=Apple TV 1080p" SCHEME="CoreStore tvOS" SDK=appletvsimulator9.2 RUN_TESTS="YES" POD_LINT="NO" - DESTINATION="OS=11.0,name=Apple TV 4K (at 1080p)" SCHEME="CoreStore tvOS" SDK=appletvsimulator12.0 RUN_TESTS="YES" POD_LINT="NO"
- DESTINATION="OS=10.2,name=Apple TV 1080p" SCHEME="CoreStore tvOS" SDK=appletvsimulator12.0 RUN_TESTS="YES" POD_LINT="NO"
before_install: before_install:
- gem install cocoapods --no-rdoc --no-ri --no-document --quiet - gem install cocoapods --no-rdoc --no-ri --no-document --quiet
- gem install xcpretty --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" - curl -OlL "https://github.com/Carthage/Carthage/releases/download/0.26.0/Carthage.pkg"
- sudo installer -pkg "Carthage.pkg" -target / - sudo installer -pkg "Carthage.pkg" -target /
- rm "Carthage.pkg" - rm "Carthage.pkg"
- npm install ios-sim -g
- ios-sim start --devicetypeid "com.apple.CoreSimulator.SimDeviceType.iPhone-8, 11.0"
before_script: before_script:
- carthage update --use-submodules - carthage update --use-submodules
script: script:
@@ -36,8 +39,8 @@ script:
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 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; xcodebuild -workspace CoreStore.xcworkspace -scheme "$SCHEME" -sdk "$SDK" -destination "$DESTINATION" -configuration Release ONLY_ACTIVE_ARCH=NO clean test | xcpretty -c;
fi 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 "CoreStoreDemo" -sdk "iphonesimulator12.0" -destination "OS=11.0.1,name=iPhone 8" -configuration Debug ONLY_ACTIVE_ARCH=NO build | xcpretty -c;
- xcodebuild -workspace "CoreStore.xcworkspace" -scheme "CoreStore iOS" -sdk "iphonesimulator9.3" -destination "OS=9.3,name=iPhone 6s" -configuration Release ONLY_ACTIVE_ARCH=NO clean test | xcpretty -c; - xcodebuild -workspace "CoreStore.xcworkspace" -scheme "CoreStoreDemo" -sdk "iphonesimulator12.0" -destination "OS=11.0.1,name=iPhone 8" -configuration Release ONLY_ACTIVE_ARCH=NO build | xcpretty -c;
- if [ $POD_LINT == "YES" ]; then - if [ $POD_LINT == "YES" ]; then
pod lib lint --quick; pod lib lint --quick;
fi fi

View File

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

View File

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

View File

@@ -1,23 +1,22 @@
Pod::Spec.new do |s| Pod::Spec.new do |s|
s.name = "CoreStore" s.name = "CoreStore"
s.version = "2.0.4" s.version = "5.4.0"
s.swift_version = "4.2"
s.license = "MIT" s.license = "MIT"
s.summary = "Unleashing the real power of Core Data with the elegance and safety of Swift"
s.homepage = "https://github.com/JohnEstropia/CoreStore" 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.author = { "John Rommel Estropia" => "rommel.estropia@gmail.com" } s.author = { "John Rommel Estropia" => "rommel.estropia@gmail.com" }
s.source = { :git => "https://github.com/JohnEstropia/CoreStore.git", :tag => s.version.to_s } s.source = { :git => "https://github.com/JohnEstropia/CoreStore.git", :tag => s.version.to_s }
s.ios.deployment_target = "8.0" s.ios.deployment_target = "10.0"
s.osx.deployment_target = "10.10" s.osx.deployment_target = "10.12"
s.watchos.deployment_target = "2.0" s.watchos.deployment_target = "3.0"
s.tvos.deployment_target = "9.0" s.tvos.deployment_target = "10.0"
s.source_files = "Sources", "Sources/**/*.{swift,h,m}" s.source_files = "Sources", "Sources/**/*.{swift,h,m}"
s.public_header_files = "Sources/**/*.h" s.public_header_files = "Sources/**/*.h"
s.frameworks = "Foundation", "CoreData" s.frameworks = "Foundation", "CoreData"
s.requires_arc = true s.requires_arc = true
s.pod_target_xcconfig = { 'OTHER_SWIFT_FLAGS' => '-D USE_FRAMEWORKS', s.pod_target_xcconfig = { 'OTHER_SWIFT_FLAGS[config=Debug]' => '-D DEBUG' }
'GCC_PREPROCESSOR_DEFINITIONS' => 'USE_FRAMEWORKS=1' } end
s.dependency "GCDKit", "1.2.6"
end

File diff suppressed because it is too large Load Diff

View File

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

View File

@@ -0,0 +1,8 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>IDEDidComputeMac32BitWarning</key>
<true/>
</dict>
</plist>

View File

@@ -1,6 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?> <?xml version="1.0" encoding="UTF-8"?>
<Scheme <Scheme
LastUpgradeVersion = "0710" LastUpgradeVersion = "0930"
version = "1.3"> version = "1.3">
<BuildAction <BuildAction
parallelizeBuildables = "YES" parallelizeBuildables = "YES"

View File

@@ -1,6 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?> <?xml version="1.0" encoding="UTF-8"?>
<Scheme <Scheme
LastUpgradeVersion = "0700" LastUpgradeVersion = "0930"
version = "1.3"> version = "1.3">
<BuildAction <BuildAction
parallelizeBuildables = "YES" parallelizeBuildables = "YES"
@@ -11,8 +11,7 @@
buildForRunning = "YES" buildForRunning = "YES"
buildForProfiling = "YES" buildForProfiling = "YES"
buildForArchiving = "YES" buildForArchiving = "YES"
buildForAnalyzing = "YES" buildForAnalyzing = "YES">
hideIssues = "NO">
<BuildableReference <BuildableReference
BuildableIdentifier = "primary" BuildableIdentifier = "primary"
BlueprintIdentifier = "2F03A52F19C5C6DA005002A5" BlueprintIdentifier = "2F03A52F19C5C6DA005002A5"
@@ -26,8 +25,7 @@
buildForRunning = "NO" buildForRunning = "NO"
buildForProfiling = "NO" buildForProfiling = "NO"
buildForArchiving = "NO" buildForArchiving = "NO"
buildForAnalyzing = "NO" buildForAnalyzing = "NO">
hideIssues = "NO">
<BuildableReference <BuildableReference
BuildableIdentifier = "primary" BuildableIdentifier = "primary"
BlueprintIdentifier = "2F03A53A19C5C6DA005002A5" BlueprintIdentifier = "2F03A53A19C5C6DA005002A5"
@@ -65,6 +63,11 @@
</BuildableReference> </BuildableReference>
</MacroExpansion> </MacroExpansion>
<AdditionalOptions> <AdditionalOptions>
<AdditionalOption
key = "NSZombieEnabled"
value = "YES"
isEnabled = "YES">
</AdditionalOption>
</AdditionalOptions> </AdditionalOptions>
</TestAction> </TestAction>
<LaunchAction <LaunchAction
@@ -86,6 +89,12 @@
ReferencedContainer = "container:CoreStore.xcodeproj"> ReferencedContainer = "container:CoreStore.xcodeproj">
</BuildableReference> </BuildableReference>
</MacroExpansion> </MacroExpansion>
<CommandLineArguments>
<CommandLineArgument
argument = "-com.apple.CoreData.SQLDebug 2"
isEnabled = "NO">
</CommandLineArgument>
</CommandLineArguments>
<AdditionalOptions> <AdditionalOptions>
</AdditionalOptions> </AdditionalOptions>
</LaunchAction> </LaunchAction>

View File

@@ -1,6 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?> <?xml version="1.0" encoding="UTF-8"?>
<Scheme <Scheme
LastUpgradeVersion = "0720" LastUpgradeVersion = "0930"
version = "1.3"> version = "1.3">
<BuildAction <BuildAction
parallelizeBuildables = "YES" parallelizeBuildables = "YES"

View File

@@ -1,6 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?> <?xml version="1.0" encoding="UTF-8"?>
<Scheme <Scheme
LastUpgradeVersion = "0700" LastUpgradeVersion = "0930"
version = "1.3"> version = "1.3">
<BuildAction <BuildAction
parallelizeBuildables = "YES" parallelizeBuildables = "YES"

View File

@@ -7,7 +7,4 @@
<FileRef <FileRef
location = "group:CoreStoreDemo/CoreStoreDemo.xcodeproj"> location = "group:CoreStoreDemo/CoreStoreDemo.xcodeproj">
</FileRef> </FileRef>
<FileRef
location = "group:Carthage/Checkouts/GCDKit/GCDKit.xcodeproj">
</FileRef>
</Workspace> </Workspace>

View File

@@ -0,0 +1,8 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>IDEDidComputeMac32BitWarning</key>
<true/>
</dict>
</plist>

View File

@@ -0,0 +1,5 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict/>
</plist>

View File

@@ -12,7 +12,6 @@
B503FAE11AFDC71700F90881 /* Palette.swift in Sources */ = {isa = PBXBuildFile; fileRef = B503FADD1AFDC71700F90881 /* Palette.swift */; }; B503FAE11AFDC71700F90881 /* Palette.swift in Sources */ = {isa = PBXBuildFile; fileRef = B503FADD1AFDC71700F90881 /* Palette.swift */; };
B503FAE21AFDC71700F90881 /* PaletteTableViewCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = B503FADE1AFDC71700F90881 /* PaletteTableViewCell.swift */; }; B503FAE21AFDC71700F90881 /* PaletteTableViewCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = B503FADE1AFDC71700F90881 /* PaletteTableViewCell.swift */; };
B5125C121B521B78003A42C7 /* OrganismV2ToV3.xcmappingmodel in Sources */ = {isa = PBXBuildFile; fileRef = B5125C111B521B78003A42C7 /* OrganismV2ToV3.xcmappingmodel */; }; 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 */; }; B52977D91B120B80003D50A5 /* ObserversViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = B52977D81B120B80003D50A5 /* ObserversViewController.swift */; };
B52977DD1B120F3B003D50A5 /* TransactionsDemoViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = B52977DC1B120F3B003D50A5 /* TransactionsDemoViewController.swift */; }; B52977DD1B120F3B003D50A5 /* TransactionsDemoViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = B52977DC1B120F3B003D50A5 /* TransactionsDemoViewController.swift */; };
B52977DF1B120F83003D50A5 /* MapKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = B52977DE1B120F83003D50A5 /* MapKit.framework */; }; B52977DF1B120F83003D50A5 /* MapKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = B52977DE1B120F83003D50A5 /* MapKit.framework */; };
@@ -36,8 +35,6 @@
B569651C1B30889A0075EE4A /* QueryingResultsViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = B569651B1B30889A0075EE4A /* QueryingResultsViewController.swift */; }; B569651C1B30889A0075EE4A /* QueryingResultsViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = B569651B1B30889A0075EE4A /* QueryingResultsViewController.swift */; };
B56965291B3582D30075EE4A /* MigrationDemo.xcdatamodeld in Sources */ = {isa = PBXBuildFile; fileRef = B56965271B3582D30075EE4A /* MigrationDemo.xcdatamodeld */; }; B56965291B3582D30075EE4A /* MigrationDemo.xcdatamodeld in Sources */ = {isa = PBXBuildFile; fileRef = B56965271B3582D30075EE4A /* MigrationDemo.xcdatamodeld */; };
B5E599321B5240F50084BD5F /* OrganismTableViewCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = B5E599311B5240F50084BD5F /* OrganismTableViewCell.swift */; }; 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 */; }; 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, ); }; }; 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 */; }; B5EE25851B36E23C0000406B /* OrganismV1.swift in Sources */ = {isa = PBXBuildFile; fileRef = B5EE25841B36E23C0000406B /* OrganismV1.swift */; };
@@ -54,7 +51,6 @@
dstPath = ""; dstPath = "";
dstSubfolderSpec = 10; dstSubfolderSpec = 10;
files = ( files = (
B5E89ACE1C52929C003B04A9 /* GCDKit.framework in Embed Frameworks */,
B5E89AD11C5292A2003B04A9 /* CoreStore.framework in Embed Frameworks */, B5E89AD11C5292A2003B04A9 /* CoreStore.framework in Embed Frameworks */,
); );
name = "Embed Frameworks"; name = "Embed Frameworks";
@@ -94,7 +90,6 @@
B569651B1B30889A0075EE4A /* QueryingResultsViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = QueryingResultsViewController.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>"; }; 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; }; 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; }; 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>"; }; 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>"; }; B5EE25841B36E23C0000406B /* OrganismV1.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = OrganismV1.swift; sourceTree = "<group>"; };
@@ -110,7 +105,6 @@
isa = PBXFrameworksBuildPhase; isa = PBXFrameworksBuildPhase;
buildActionMask = 2147483647; buildActionMask = 2147483647;
files = ( files = (
B5E89ACD1C52929C003B04A9 /* GCDKit.framework in Frameworks */,
B5E89AD01C5292A2003B04A9 /* CoreStore.framework in Frameworks */, B5E89AD01C5292A2003B04A9 /* CoreStore.framework in Frameworks */,
B52977E11B120F8A003D50A5 /* CoreLocation.framework in Frameworks */, B52977E11B120F8A003D50A5 /* CoreLocation.framework in Frameworks */,
B52977DF1B120F83003D50A5 /* MapKit.framework in Frameworks */, B52977DF1B120F83003D50A5 /* MapKit.framework in Frameworks */,
@@ -146,7 +140,6 @@
children = ( children = (
B52977E01B120F8A003D50A5 /* CoreLocation.framework */, B52977E01B120F8A003D50A5 /* CoreLocation.framework */,
B5BDC9211C202429008147CD /* CoreStore.framework */, B5BDC9211C202429008147CD /* CoreStore.framework */,
B5BDC9241C202429008147CD /* GCDKit.framework */,
B52977DE1B120F83003D50A5 /* MapKit.framework */, B52977DE1B120F83003D50A5 /* MapKit.framework */,
); );
name = Frameworks; name = Frameworks;
@@ -272,11 +265,12 @@
isa = PBXProject; isa = PBXProject;
attributes = { attributes = {
LastSwiftUpdateCheck = 0700; LastSwiftUpdateCheck = 0700;
LastUpgradeCheck = 0700; LastUpgradeCheck = 0930;
ORGANIZATIONNAME = "John Rommel Estropia"; ORGANIZATIONNAME = "John Rommel Estropia";
TargetAttributes = { TargetAttributes = {
B54AAD481AF4D26E00848AE0 = { B54AAD481AF4D26E00848AE0 = {
CreatedOnToolsVersion = 6.3; CreatedOnToolsVersion = 6.3;
LastSwiftMigration = 0900;
}; };
}; };
}; };
@@ -336,7 +330,6 @@
B503FAE11AFDC71700F90881 /* Palette.swift in Sources */, B503FAE11AFDC71700F90881 /* Palette.swift in Sources */,
B503FAE21AFDC71700F90881 /* PaletteTableViewCell.swift in Sources */, B503FAE21AFDC71700F90881 /* PaletteTableViewCell.swift in Sources */,
B560070F1B3EC90F00A9A8F9 /* OrganismV2ToV3MigrationPolicy.swift in Sources */, B560070F1B3EC90F00A9A8F9 /* OrganismV2ToV3MigrationPolicy.swift in Sources */,
B5125C141B521BA7003A42C7 /* OrganismV3ToV2.xcmappingmodel in Sources */,
B503FADF1AFDC71700F90881 /* ListObserverDemoViewController.swift in Sources */, B503FADF1AFDC71700F90881 /* ListObserverDemoViewController.swift in Sources */,
B54AAD4F1AF4D26E00848AE0 /* AppDelegate.swift in Sources */, B54AAD4F1AF4D26E00848AE0 /* AppDelegate.swift in Sources */,
B56964D71B231AE90075EE4A /* StackSetupDemo.xcdatamodeld in Sources */, B56964D71B231AE90075EE4A /* StackSetupDemo.xcdatamodeld in Sources */,
@@ -378,13 +371,23 @@
CLANG_CXX_LIBRARY = "libc++"; CLANG_CXX_LIBRARY = "libc++";
CLANG_ENABLE_MODULES = YES; CLANG_ENABLE_MODULES = YES;
CLANG_ENABLE_OBJC_ARC = YES; CLANG_ENABLE_OBJC_ARC = YES;
CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;
CLANG_WARN_BOOL_CONVERSION = YES; CLANG_WARN_BOOL_CONVERSION = YES;
CLANG_WARN_COMMA = YES;
CLANG_WARN_CONSTANT_CONVERSION = YES; CLANG_WARN_CONSTANT_CONVERSION = YES;
CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES;
CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
CLANG_WARN_EMPTY_BODY = YES; CLANG_WARN_EMPTY_BODY = YES;
CLANG_WARN_ENUM_CONVERSION = YES; CLANG_WARN_ENUM_CONVERSION = YES;
CLANG_WARN_INFINITE_RECURSION = YES;
CLANG_WARN_INT_CONVERSION = YES; CLANG_WARN_INT_CONVERSION = YES;
CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;
CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES;
CLANG_WARN_OBJC_LITERAL_CONVERSION = YES;
CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
CLANG_WARN_RANGE_LOOP_ANALYSIS = YES;
CLANG_WARN_STRICT_PROTOTYPES = YES;
CLANG_WARN_SUSPICIOUS_MOVE = YES;
CLANG_WARN_UNREACHABLE_CODE = YES; CLANG_WARN_UNREACHABLE_CODE = YES;
CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
"CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer";
@@ -407,11 +410,13 @@
GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
GCC_WARN_UNUSED_FUNCTION = YES; GCC_WARN_UNUSED_FUNCTION = YES;
GCC_WARN_UNUSED_VARIABLE = YES; GCC_WARN_UNUSED_VARIABLE = YES;
IPHONEOS_DEPLOYMENT_TARGET = 8.0; IPHONEOS_DEPLOYMENT_TARGET = 10.0;
MTL_ENABLE_DEBUG_INFO = YES; MTL_ENABLE_DEBUG_INFO = YES;
ONLY_ACTIVE_ARCH = YES; ONLY_ACTIVE_ARCH = YES;
SDKROOT = iphoneos; SDKROOT = iphoneos;
SWIFT_OPTIMIZATION_LEVEL = "-Onone"; SWIFT_OPTIMIZATION_LEVEL = "-Onone";
SWIFT_SWIFT3_OBJC_INFERENCE = Off;
SWIFT_VERSION = 4.0;
}; };
name = Debug; name = Debug;
}; };
@@ -423,13 +428,23 @@
CLANG_CXX_LIBRARY = "libc++"; CLANG_CXX_LIBRARY = "libc++";
CLANG_ENABLE_MODULES = YES; CLANG_ENABLE_MODULES = YES;
CLANG_ENABLE_OBJC_ARC = YES; CLANG_ENABLE_OBJC_ARC = YES;
CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;
CLANG_WARN_BOOL_CONVERSION = YES; CLANG_WARN_BOOL_CONVERSION = YES;
CLANG_WARN_COMMA = YES;
CLANG_WARN_CONSTANT_CONVERSION = YES; CLANG_WARN_CONSTANT_CONVERSION = YES;
CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES;
CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
CLANG_WARN_EMPTY_BODY = YES; CLANG_WARN_EMPTY_BODY = YES;
CLANG_WARN_ENUM_CONVERSION = YES; CLANG_WARN_ENUM_CONVERSION = YES;
CLANG_WARN_INFINITE_RECURSION = YES;
CLANG_WARN_INT_CONVERSION = YES; CLANG_WARN_INT_CONVERSION = YES;
CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;
CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES;
CLANG_WARN_OBJC_LITERAL_CONVERSION = YES;
CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
CLANG_WARN_RANGE_LOOP_ANALYSIS = YES;
CLANG_WARN_STRICT_PROTOTYPES = YES;
CLANG_WARN_SUSPICIOUS_MOVE = YES;
CLANG_WARN_UNREACHABLE_CODE = YES; CLANG_WARN_UNREACHABLE_CODE = YES;
CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
"CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer";
@@ -445,9 +460,11 @@
GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
GCC_WARN_UNUSED_FUNCTION = YES; GCC_WARN_UNUSED_FUNCTION = YES;
GCC_WARN_UNUSED_VARIABLE = YES; GCC_WARN_UNUSED_VARIABLE = YES;
IPHONEOS_DEPLOYMENT_TARGET = 8.0; IPHONEOS_DEPLOYMENT_TARGET = 10.0;
MTL_ENABLE_DEBUG_INFO = NO; MTL_ENABLE_DEBUG_INFO = NO;
SDKROOT = iphoneos; SDKROOT = iphoneos;
SWIFT_SWIFT3_OBJC_INFERENCE = Off;
SWIFT_VERSION = 4.0;
VALIDATE_PRODUCT = YES; VALIDATE_PRODUCT = YES;
}; };
name = Release; name = Release;
@@ -457,10 +474,11 @@
buildSettings = { buildSettings = {
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
INFOPLIST_FILE = CoreStoreDemo/Info.plist; INFOPLIST_FILE = CoreStoreDemo/Info.plist;
IPHONEOS_DEPLOYMENT_TARGET = 8.0;
LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks";
PRODUCT_BUNDLE_IDENTIFIER = com.johnestropia.corestore.demo; PRODUCT_BUNDLE_IDENTIFIER = com.johnestropia.corestore.demo;
PRODUCT_NAME = "$(TARGET_NAME)"; PRODUCT_NAME = "$(TARGET_NAME)";
SWIFT_SWIFT3_OBJC_INFERENCE = Off;
SWIFT_VERSION = 4.0;
}; };
name = Debug; name = Debug;
}; };
@@ -469,10 +487,12 @@
buildSettings = { buildSettings = {
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
INFOPLIST_FILE = CoreStoreDemo/Info.plist; INFOPLIST_FILE = CoreStoreDemo/Info.plist;
IPHONEOS_DEPLOYMENT_TARGET = 8.0;
LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks";
PRODUCT_BUNDLE_IDENTIFIER = com.johnestropia.corestore.demo; PRODUCT_BUNDLE_IDENTIFIER = com.johnestropia.corestore.demo;
PRODUCT_NAME = "$(TARGET_NAME)"; PRODUCT_NAME = "$(TARGET_NAME)";
SWIFT_OPTIMIZATION_LEVEL = "-Owholemodule";
SWIFT_SWIFT3_OBJC_INFERENCE = Off;
SWIFT_VERSION = 4.0;
}; };
name = Release; name = Release;
}; };

View File

@@ -1,6 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?> <?xml version="1.0" encoding="UTF-8"?>
<Scheme <Scheme
LastUpgradeVersion = "0700" LastUpgradeVersion = "0930"
version = "1.3"> version = "1.3">
<BuildAction <BuildAction
parallelizeBuildables = "YES" parallelizeBuildables = "YES"
@@ -14,24 +14,10 @@
buildForAnalyzing = "YES"> buildForAnalyzing = "YES">
<BuildableReference <BuildableReference
BuildableIdentifier = "primary" BuildableIdentifier = "primary"
BlueprintIdentifier = "B5D9E2ED1CA2C317007A9D52" BlueprintIdentifier = "B54AAD481AF4D26E00848AE0"
BuildableName = "CoreStore_iOS7.framework" BuildableName = "CoreStoreDemo.app"
BlueprintName = "CoreStore iOS7" BlueprintName = "CoreStoreDemo"
ReferencedContainer = "container:CoreStore.xcodeproj"> ReferencedContainer = "container:CoreStoreDemo.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> </BuildableReference>
</BuildActionEntry> </BuildActionEntry>
</BuildActionEntries> </BuildActionEntries>
@@ -42,24 +28,14 @@
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB" selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
shouldUseLaunchSchemeArgsEnv = "YES"> shouldUseLaunchSchemeArgsEnv = "YES">
<Testables> <Testables>
<TestableReference
skipped = "NO">
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "2F03A53A19C5C6DA005002A5"
BuildableName = "CoreStoreTests.xctest"
BlueprintName = "CoreStoreTests iOS"
ReferencedContainer = "container:CoreStore.xcodeproj">
</BuildableReference>
</TestableReference>
</Testables> </Testables>
<MacroExpansion> <MacroExpansion>
<BuildableReference <BuildableReference
BuildableIdentifier = "primary" BuildableIdentifier = "primary"
BlueprintIdentifier = "2F03A52F19C5C6DA005002A5" BlueprintIdentifier = "B54AAD481AF4D26E00848AE0"
BuildableName = "CoreStore.framework" BuildableName = "CoreStoreDemo.app"
BlueprintName = "CoreStore iOS" BlueprintName = "CoreStoreDemo"
ReferencedContainer = "container:CoreStore.xcodeproj"> ReferencedContainer = "container:CoreStoreDemo.xcodeproj">
</BuildableReference> </BuildableReference>
</MacroExpansion> </MacroExpansion>
<AdditionalOptions> <AdditionalOptions>
@@ -75,15 +51,16 @@
debugDocumentVersioning = "YES" debugDocumentVersioning = "YES"
debugServiceExtension = "internal" debugServiceExtension = "internal"
allowLocationSimulation = "YES"> allowLocationSimulation = "YES">
<MacroExpansion> <BuildableProductRunnable
runnableDebuggingMode = "0">
<BuildableReference <BuildableReference
BuildableIdentifier = "primary" BuildableIdentifier = "primary"
BlueprintIdentifier = "B5D9E2ED1CA2C317007A9D52" BlueprintIdentifier = "B54AAD481AF4D26E00848AE0"
BuildableName = "CoreStore_iOS7.framework" BuildableName = "CoreStoreDemo.app"
BlueprintName = "CoreStore iOS7" BlueprintName = "CoreStoreDemo"
ReferencedContainer = "container:CoreStore.xcodeproj"> ReferencedContainer = "container:CoreStoreDemo.xcodeproj">
</BuildableReference> </BuildableReference>
</MacroExpansion> </BuildableProductRunnable>
<AdditionalOptions> <AdditionalOptions>
</AdditionalOptions> </AdditionalOptions>
</LaunchAction> </LaunchAction>
@@ -93,9 +70,19 @@
savedToolIdentifier = "" savedToolIdentifier = ""
useCustomWorkingDirectory = "NO" useCustomWorkingDirectory = "NO"
debugDocumentVersioning = "YES"> debugDocumentVersioning = "YES">
<BuildableProductRunnable
runnableDebuggingMode = "0">
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "B54AAD481AF4D26E00848AE0"
BuildableName = "CoreStoreDemo.app"
BlueprintName = "CoreStoreDemo"
ReferencedContainer = "container:CoreStoreDemo.xcodeproj">
</BuildableReference>
</BuildableProductRunnable>
</ProfileAction> </ProfileAction>
<AnalyzeAction <AnalyzeAction
buildConfiguration = "Release"> buildConfiguration = "Debug">
</AnalyzeAction> </AnalyzeAction>
<ArchiveAction <ArchiveAction
buildConfiguration = "Release" buildConfiguration = "Release"

View File

@@ -3,7 +3,7 @@
// CoreStoreDemo // CoreStoreDemo
// //
// Created by John Rommel Estropia on 2015/05/02. // Created by John Rommel Estropia on 2015/05/02.
// Copyright © 2015 John Rommel Estropia. All rights reserved. // Copyright © 2018 John Rommel Estropia. All rights reserved.
// //
import UIKit import UIKit
@@ -18,9 +18,7 @@ class AppDelegate: UIResponder, UIApplicationDelegate {
var window: UIWindow? var window: UIWindow?
func application(application: UIApplication, didFinishLaunchingWithOptions launchOptions: [NSObject: AnyObject]?) -> Bool { func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplicationLaunchOptionsKey: Any]? = nil) -> Bool {
application.statusBarStyle = .LightContent
return true return true
} }

View File

@@ -1,9 +1,11 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?> <?xml version="1.0" encoding="UTF-8"?>
<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"> <document type="com.apple.InterfaceBuilder3.CocoaTouch.XIB" version="3.0" toolsVersion="14313.18" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" launchScreen="YES" useTraitCollections="YES" colorMatched="YES">
<device id="retina4_7" orientation="portrait">
<adaptation id="fullscreen"/>
</device>
<dependencies> <dependencies>
<deployment identifier="iOS"/> <plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="14283.14"/>
<plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="10083"/> <capability name="documents saved in the Xcode 8 format" minToolsVersion="8.0"/>
<capability name="Constraints with non-1.0 multipliers" minToolsVersion="5.1"/>
</dependencies> </dependencies>
<objects> <objects>
<placeholder placeholderIdentifier="IBFilesOwner" id="-1" userLabel="File's Owner"/> <placeholder placeholderIdentifier="IBFilesOwner" id="-1" userLabel="File's Owner"/>
@@ -12,10 +14,10 @@
<rect key="frame" x="0.0" y="0.0" width="480" height="480"/> <rect key="frame" x="0.0" y="0.0" width="480" height="480"/>
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/> <autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
<subviews> <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"> <label opaque="NO" clipsSubviews="YES" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text=" Copyright © 2018 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"/> <rect key="frame" x="20" y="439" width="440" height="21"/>
<fontDescription key="fontDescription" type="system" pointSize="17"/> <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"/> <color key="textColor" red="0.90744441747665405" green="0.9265514612197876" blue="0.93116652965545654" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
<nil key="highlightedColor"/> <nil key="highlightedColor"/>
</label> </label>
<imageView userInteractionEnabled="NO" contentMode="center" horizontalHuggingPriority="251" verticalHuggingPriority="251" image="CoreStoreIcon" translatesAutoresizingMaskIntoConstraints="NO" id="q8C-V6-gXH"> <imageView userInteractionEnabled="NO" contentMode="center" horizontalHuggingPriority="251" verticalHuggingPriority="251" image="CoreStoreIcon" translatesAutoresizingMaskIntoConstraints="NO" id="q8C-V6-gXH">
@@ -24,11 +26,11 @@
<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"> <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"/> <rect key="frame" x="20" y="273" width="440" height="57.5"/>
<fontDescription key="fontDescription" name="HelveticaNeue-UltraLight" family="Helvetica Neue" pointSize="50"/> <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"/> <color key="textColor" red="0.90744441747665405" green="0.9265514612197876" blue="0.93116652965545654" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
<nil key="highlightedColor"/> <nil key="highlightedColor"/>
</label> </label>
</subviews> </subviews>
<color key="backgroundColor" red="0.20392156862745098" green="0.28627450980392155" blue="0.36862745098039218" alpha="1" colorSpace="custom" customColorSpace="sRGB"/> <color key="backgroundColor" red="0.15542715787887573" green="0.2203737199306488" blue="0.2959403395652771" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
<constraints> <constraints>
<constraint firstAttribute="centerX" secondItem="kId-c2-rCX" secondAttribute="centerX" id="Koa-jz-hwk"/> <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 firstAttribute="bottom" secondItem="8ie-xW-0ye" secondAttribute="bottom" constant="20" id="Kzo-t9-V3l"/>

View File

@@ -1,39 +1,25 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?> <?xml version="1.0" encoding="UTF-8"?>
<document type="com.apple.InterfaceBuilder3.CocoaTouch.Storyboard.XIB" version="3.0" toolsVersion="10112" systemVersion="15D21" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" useTraitCollections="YES" initialViewController="Ni8-QF-XHB"> <document type="com.apple.InterfaceBuilder3.CocoaTouch.Storyboard.XIB" version="3.0" toolsVersion="14460.31" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" useTraitCollections="YES" colorMatched="YES" initialViewController="Ni8-QF-XHB">
<device id="retina4_7" orientation="portrait">
<adaptation id="fullscreen"/>
</device>
<dependencies> <dependencies>
<deployment identifier="iOS"/> <deployment identifier="iOS"/>
<plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="10083"/> <plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="14460.20"/>
<capability name="Aspect ratio constraints" minToolsVersion="5.1"/> <capability name="documents saved in the Xcode 8 format" minToolsVersion="8.0"/>
<capability name="Constraints to layout margins" minToolsVersion="6.0"/>
<capability name="Constraints with non-1.0 multipliers" minToolsVersion="5.1"/>
</dependencies> </dependencies>
<customFonts key="customFonts"> <customFonts key="customFonts">
<mutableArray key="AppleSDGothicNeo.ttc"> <array key="AppleSDGothicNeo.ttc">
<string>AppleSDGothicNeo-Regular</string> <string>AppleSDGothicNeo-Regular</string>
</mutableArray> </array>
<mutableArray key="HelveticaNeue.ttc"> <array key="HelveticaNeue.ttc">
<string>HelveticaNeue-Bold</string>
<string>HelveticaNeue-Bold</string>
<string>HelveticaNeue</string> <string>HelveticaNeue</string>
<string>HelveticaNeue</string> <string>HelveticaNeue-Bold</string>
</mutableArray> </array>
<mutableArray key="HelveticaNeueLights.ttc"> <array key="HelveticaNeueLights.ttc">
<string>HelveticaNeue-Light</string>
<string>HelveticaNeue-Light</string>
<string>HelveticaNeue-Light</string>
<string>HelveticaNeue-Light</string> <string>HelveticaNeue-Light</string>
<string>HelveticaNeue-Thin</string> <string>HelveticaNeue-Thin</string>
<string>HelveticaNeue-Light</string> </array>
<string>HelveticaNeue-Light</string>
<string>HelveticaNeue-Light</string>
<string>HelveticaNeue-Light</string>
<string>HelveticaNeue-Light</string>
<string>HelveticaNeue-Light</string>
<string>HelveticaNeue-Light</string>
<string>HelveticaNeue-Light</string>
<string>HelveticaNeue-Light</string>
<string>HelveticaNeue-Light</string>
</mutableArray>
</customFonts> </customFonts>
<scenes> <scenes>
<!--SNS Accounts--> <!--SNS Accounts-->
@@ -41,34 +27,34 @@
<objects> <objects>
<tableViewController id="AW4-lY-JNk" customClass="StackSetupDemoViewController" customModule="CoreStoreDemo" customModuleProvider="target" sceneMemberID="viewController"> <tableViewController id="AW4-lY-JNk" customClass="StackSetupDemoViewController" customModule="CoreStoreDemo" customModuleProvider="target" sceneMemberID="viewController">
<tableView key="view" clipsSubviews="YES" contentMode="scaleToFill" alwaysBounceVertical="YES" dataMode="prototypes" style="plain" separatorStyle="default" rowHeight="44" sectionHeaderHeight="22" sectionFooterHeight="22" id="S3A-lm-AuA"> <tableView key="view" clipsSubviews="YES" contentMode="scaleToFill" alwaysBounceVertical="YES" dataMode="prototypes" style="plain" separatorStyle="default" rowHeight="44" sectionHeaderHeight="22" sectionFooterHeight="22" id="S3A-lm-AuA">
<rect key="frame" x="0.0" y="0.0" width="600" height="600"/> <rect key="frame" x="0.0" y="0.0" width="375" height="667"/>
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/> <autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
<color key="backgroundColor" red="0.20392156859999999" green="0.28627450980000002" blue="0.36862745099999999" alpha="1" colorSpace="custom" customColorSpace="sRGB"/> <color key="backgroundColor" red="0.15542715787887573" green="0.2203737199306488" blue="0.2959403395652771" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
<color key="separatorColor" red="0.20392156859999999" green="0.28627450980000002" blue="0.36862745099999999" alpha="1" colorSpace="custom" customColorSpace="sRGB"/> <color key="separatorColor" red="0.15542715787887573" green="0.2203737199306488" blue="0.2959403395652771" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
<view key="tableHeaderView" contentMode="scaleToFill" id="yud-WH-MPa"> <view key="tableHeaderView" contentMode="scaleToFill" id="yud-WH-MPa">
<rect key="frame" x="0.0" y="64" width="600" height="150"/> <rect key="frame" x="0.0" y="0.0" width="375" height="150"/>
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMaxY="YES"/> <autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMaxY="YES"/>
<subviews> <subviews>
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="sns" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="czc-nd-es9"> <label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="sns" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="czc-nd-es9">
<rect key="frame" x="20" y="20" width="560" height="26.5"/> <rect key="frame" x="20" y="20" width="335" height="26.5"/>
<fontDescription key="fontDescription" name="HelveticaNeue-Bold" family="Helvetica Neue" pointSize="22"/> <fontDescription key="fontDescription" name="HelveticaNeue-Bold" family="Helvetica Neue" pointSize="22"/>
<color key="textColor" red="0.92549019610000005" green="0.94117647059999998" blue="0.94509803920000002" alpha="1" colorSpace="custom" customColorSpace="sRGB"/> <color key="textColor" red="0.90744441747665405" green="0.9265514612197876" blue="0.93116652965545654" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
<nil key="highlightedColor"/> <nil key="highlightedColor"/>
</label> </label>
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="name" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="1eh-91-O2N"> <label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="name" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="1eh-91-O2N">
<rect key="frame" x="20" y="70" width="41" height="20.5"/> <rect key="frame" x="20" y="70" width="41" height="20.5"/>
<fontDescription key="fontDescription" name="HelveticaNeue-Light" family="Helvetica Neue" pointSize="17"/> <fontDescription key="fontDescription" name="HelveticaNeue-Light" family="Helvetica Neue" pointSize="17"/>
<color key="textColor" red="0.92549019610000005" green="0.94117647059999998" blue="0.94509803920000002" alpha="1" colorSpace="custom" customColorSpace="sRGB"/> <color key="textColor" red="0.90744441747665405" green="0.9265514612197876" blue="0.93116652965545654" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
<nil key="highlightedColor"/> <nil key="highlightedColor"/>
</label> </label>
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="friends" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="p2y-0T-hQs"> <label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="friends" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="p2y-0T-hQs">
<rect key="frame" x="539.5" y="72" width="40.5" height="17"/> <rect key="frame" x="314.5" y="72" width="40.5" height="17"/>
<fontDescription key="fontDescription" name="HelveticaNeue-Light" family="Helvetica Neue" pointSize="14"/> <fontDescription key="fontDescription" name="HelveticaNeue-Light" family="Helvetica Neue" pointSize="14"/>
<color key="textColor" red="0.92549019610000005" green="0.94117647059999998" blue="0.94509803920000002" alpha="1" colorSpace="custom" customColorSpace="sRGB"/> <color key="textColor" red="0.90744441747665405" green="0.9265514612197876" blue="0.93116652965545654" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
<nil key="highlightedColor"/> <nil key="highlightedColor"/>
</label> </label>
</subviews> </subviews>
<color key="backgroundColor" red="0.20392156862745098" green="0.28627450980392155" blue="0.36862745098039218" alpha="1" colorSpace="custom" customColorSpace="sRGB"/> <color key="backgroundColor" red="0.15542715787887573" green="0.2203737199306488" blue="0.2959403395652771" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
<constraints> <constraints>
<constraint firstItem="1eh-91-O2N" firstAttribute="top" secondItem="czc-nd-es9" secondAttribute="bottom" constant="23.5" id="F6q-Jt-glI"/> <constraint firstItem="1eh-91-O2N" firstAttribute="top" secondItem="czc-nd-es9" secondAttribute="bottom" constant="23.5" id="F6q-Jt-glI"/>
<constraint firstItem="p2y-0T-hQs" firstAttribute="leading" relation="greaterThanOrEqual" secondItem="1eh-91-O2N" secondAttribute="trailing" constant="20" id="GVS-6o-rmj"/> <constraint firstItem="p2y-0T-hQs" firstAttribute="leading" relation="greaterThanOrEqual" secondItem="1eh-91-O2N" secondAttribute="trailing" constant="20" id="GVS-6o-rmj"/>
@@ -82,24 +68,24 @@
</view> </view>
<prototypes> <prototypes>
<tableViewCell contentMode="scaleToFill" selectionStyle="default" indentationWidth="10" reuseIdentifier="UITableViewCell" textLabel="8b8-lM-Krq" detailTextLabel="hR1-Zb-BOk" style="IBUITableViewCellStyleValue1" id="dMt-nx-EO5"> <tableViewCell contentMode="scaleToFill" selectionStyle="default" indentationWidth="10" reuseIdentifier="UITableViewCell" textLabel="8b8-lM-Krq" detailTextLabel="hR1-Zb-BOk" style="IBUITableViewCellStyleValue1" id="dMt-nx-EO5">
<rect key="frame" x="0.0" y="236" width="600" height="44"/> <rect key="frame" x="0.0" y="172" width="375" height="44"/>
<autoresizingMask key="autoresizingMask"/> <autoresizingMask key="autoresizingMask"/>
<tableViewCellContentView key="contentView" opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center" tableViewCell="dMt-nx-EO5" id="gdK-VV-zNb"> <tableViewCellContentView key="contentView" opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center" tableViewCell="dMt-nx-EO5" id="gdK-VV-zNb">
<rect key="frame" x="0.0" y="0.0" width="600" height="43.5"/> <rect key="frame" x="0.0" y="0.0" width="375" height="43.5"/>
<autoresizingMask key="autoresizingMask"/> <autoresizingMask key="autoresizingMask"/>
<subviews> <subviews>
<label opaque="NO" multipleTouchEnabled="YES" contentMode="left" text="Title" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" id="8b8-lM-Krq"> <label opaque="NO" multipleTouchEnabled="YES" contentMode="left" text="Title" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" id="8b8-lM-Krq">
<rect key="frame" x="15" y="13" width="28.5" height="19"/> <rect key="frame" x="16" y="13" width="28.5" height="19"/>
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMaxY="YES"/> <autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMaxY="YES"/>
<fontDescription key="fontDescription" name="HelveticaNeue-Light" family="Helvetica Neue" pointSize="16"/> <fontDescription key="fontDescription" name="HelveticaNeue-Light" family="Helvetica Neue" pointSize="16"/>
<color key="textColor" red="0.17254901959999999" green="0.24313725489999999" blue="0.31372549020000001" alpha="1" colorSpace="custom" customColorSpace="sRGB"/> <color key="textColor" red="0.13079629838466644" green="0.184075728058815" blue="0.24594299495220184" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
<nil key="highlightedColor"/> <nil key="highlightedColor"/>
</label> </label>
<label opaque="NO" multipleTouchEnabled="YES" contentMode="left" text="Subtitle" textAlignment="right" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" id="hR1-Zb-BOk"> <label opaque="NO" multipleTouchEnabled="YES" contentMode="left" text="Subtitle" textAlignment="right" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" id="hR1-Zb-BOk">
<rect key="frame" x="533" y="13" width="52" height="19"/> <rect key="frame" x="307" y="13" width="52" height="19"/>
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMaxY="YES"/> <autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMaxY="YES"/>
<fontDescription key="fontDescription" name="HelveticaNeue-Light" family="Helvetica Neue" pointSize="16"/> <fontDescription key="fontDescription" name="HelveticaNeue-Light" family="Helvetica Neue" pointSize="16"/>
<color key="textColor" red="0.55686274509803924" green="0.55686274509803924" blue="0.57647058823529407" alpha="1" colorSpace="calibratedRGB"/> <color key="textColor" red="0.55686274509803924" green="0.55686274509803924" blue="0.57647058823529407" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
<nil key="highlightedColor"/> <nil key="highlightedColor"/>
</label> </label>
</subviews> </subviews>
@@ -131,23 +117,23 @@
<viewControllerLayoutGuide type="bottom" id="t9A-zf-Iew"/> <viewControllerLayoutGuide type="bottom" id="t9A-zf-Iew"/>
</layoutGuides> </layoutGuides>
<view key="view" contentMode="scaleToFill" id="75P-2m-6cr"> <view key="view" contentMode="scaleToFill" id="75P-2m-6cr">
<rect key="frame" x="0.0" y="0.0" width="600" height="600"/> <rect key="frame" x="0.0" y="0.0" width="375" height="667"/>
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/> <autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
<subviews> <subviews>
<tableView clipsSubviews="YES" contentMode="scaleToFill" alwaysBounceVertical="YES" dataMode="prototypes" style="plain" separatorStyle="default" rowHeight="44" sectionHeaderHeight="22" sectionFooterHeight="22" translatesAutoresizingMaskIntoConstraints="NO" id="WUc-3Y-Quw"> <tableView clipsSubviews="YES" contentMode="scaleToFill" alwaysBounceVertical="YES" dataMode="prototypes" style="plain" separatorStyle="default" rowHeight="44" sectionHeaderHeight="22" sectionFooterHeight="22" translatesAutoresizingMaskIntoConstraints="NO" id="WUc-3Y-Quw">
<rect key="frame" x="0.0" y="324" width="600" height="276"/> <rect key="frame" x="0.0" y="324" width="375" height="343"/>
<color key="backgroundColor" red="0.93725490196078431" green="0.93725490196078431" blue="0.95686274509803926" alpha="1" colorSpace="calibratedRGB"/> <color key="backgroundColor" red="0.93725490196078431" green="0.93725490196078431" blue="0.95686274509803926" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
<color key="separatorColor" red="0.20392156859999999" green="0.28627450980000002" blue="0.36862745099999999" alpha="1" colorSpace="custom" customColorSpace="sRGB"/> <color key="separatorColor" red="0.15542715787887573" green="0.2203737199306488" blue="0.2959403395652771" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
<prototypes> <prototypes>
<tableViewCell contentMode="scaleToFill" selectionStyle="default" indentationWidth="10" reuseIdentifier="OrganismTableViewCell" id="WVb-th-o8c" customClass="OrganismTableViewCell" customModule="CoreStoreDemo" customModuleProvider="target"> <tableViewCell contentMode="scaleToFill" selectionStyle="default" indentationWidth="10" reuseIdentifier="OrganismTableViewCell" id="WVb-th-o8c" customClass="OrganismTableViewCell" customModule="CoreStoreDemo" customModuleProvider="target">
<rect key="frame" x="0.0" y="22" width="600" height="44"/> <rect key="frame" x="0.0" y="22" width="375" height="44"/>
<autoresizingMask key="autoresizingMask"/> <autoresizingMask key="autoresizingMask"/>
<tableViewCellContentView key="contentView" opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center" tableViewCell="WVb-th-o8c" id="JBq-Ml-a9p"> <tableViewCellContentView key="contentView" opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center" tableViewCell="WVb-th-o8c" id="JBq-Ml-a9p">
<rect key="frame" x="0.0" y="0.0" width="600" height="43.5"/> <rect key="frame" x="0.0" y="0.0" width="375" height="43.5"/>
<autoresizingMask key="autoresizingMask"/> <autoresizingMask key="autoresizingMask"/>
<subviews> <subviews>
<button opaque="NO" contentMode="scaleToFill" horizontalHuggingPriority="750" contentHorizontalAlignment="center" contentVerticalAlignment="center" buttonType="roundedRect" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="OQf-Bd-Zze"> <button opaque="NO" contentMode="scaleToFill" horizontalHuggingPriority="750" contentHorizontalAlignment="center" contentVerticalAlignment="center" buttonType="roundedRect" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="OQf-Bd-Zze">
<rect key="frame" x="520" y="8" width="72" height="27.5"/> <rect key="frame" x="288" y="11" width="72" height="22"/>
<fontDescription key="fontDescription" type="boldSystem" pointSize="15"/> <fontDescription key="fontDescription" type="boldSystem" pointSize="15"/>
<inset key="contentEdgeInsets" minX="7" minY="0.0" maxX="7" maxY="0.0"/> <inset key="contentEdgeInsets" minX="7" minY="0.0" maxX="7" maxY="0.0"/>
<state key="normal" title="mutate!"/> <state key="normal" title="mutate!"/>
@@ -156,9 +142,9 @@
</connections> </connections>
</button> </button>
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="Label" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="VZk-6K-4ut"> <label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="Label" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="VZk-6K-4ut">
<rect key="frame" x="15" y="8" width="495" height="27.5"/> <rect key="frame" x="22" y="11" width="256" height="22"/>
<fontDescription key="fontDescription" name="HelveticaNeue-Thin" family="Helvetica Neue" pointSize="17"/> <fontDescription key="fontDescription" name="HelveticaNeue-Thin" family="Helvetica Neue" pointSize="17"/>
<color key="textColor" red="0.20392156859999999" green="0.28627450980000002" blue="0.36862745099999999" alpha="1" colorSpace="custom" customColorSpace="sRGB"/> <color key="textColor" red="0.15542715787887573" green="0.2203737199306488" blue="0.2959403395652771" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
<nil key="highlightedColor"/> <nil key="highlightedColor"/>
</label> </label>
</subviews> </subviews>
@@ -184,42 +170,42 @@
</connections> </connections>
</tableView> </tableView>
<view contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="XKA-Ub-c2X"> <view contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="XKA-Ub-c2X">
<rect key="frame" x="0.0" y="64" width="600" height="260"/> <rect key="frame" x="0.0" y="64" width="375" height="260"/>
<subviews> <subviews>
<view contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="i7U-bW-juB" customClass="UIButton"> <view contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="i7U-bW-juB" customClass="UIButton">
<rect key="frame" x="0.0" y="0.0" width="600" height="260"/> <rect key="frame" x="0.0" y="0.0" width="375" height="260"/>
<subviews> <subviews>
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="Organism" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="zxy-nY-P44"> <label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="Organism" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="zxy-nY-P44">
<rect key="frame" x="20" y="90.5" width="560" height="26.5"/> <rect key="frame" x="20" y="90.5" width="335" height="26.5"/>
<fontDescription key="fontDescription" name="HelveticaNeue-Bold" family="Helvetica Neue" pointSize="22"/> <fontDescription key="fontDescription" name="HelveticaNeue-Bold" family="Helvetica Neue" pointSize="22"/>
<color key="textColor" red="0.92549019610000005" green="0.94117647059999998" blue="0.94509803920000002" alpha="1" colorSpace="custom" customColorSpace="sRGB"/> <color key="textColor" red="0.90744441747665405" green="0.9265514612197876" blue="0.93116652965545654" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
<nil key="highlightedColor"/> <nil key="highlightedColor"/>
</label> </label>
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="attributes" lineBreakMode="wordWrap" numberOfLines="0" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="6Ac-xl-ldZ"> <label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="attributes" lineBreakMode="wordWrap" numberOfLines="0" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="6Ac-xl-ldZ">
<rect key="frame" x="20" y="131.5" width="560" height="20.5"/> <rect key="frame" x="20" y="131.5" width="335" height="20.5"/>
<fontDescription key="fontDescription" name="HelveticaNeue-Light" family="Helvetica Neue" pointSize="17"/> <fontDescription key="fontDescription" name="HelveticaNeue-Light" family="Helvetica Neue" pointSize="17"/>
<color key="textColor" red="0.92549019610000005" green="0.94117647059999998" blue="0.94509803920000002" alpha="1" colorSpace="custom" customColorSpace="sRGB"/> <color key="textColor" red="0.90744441747665405" green="0.9265514612197876" blue="0.93116652965545654" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
<nil key="highlightedColor"/> <nil key="highlightedColor"/>
</label> </label>
<segmentedControl opaque="NO" contentMode="scaleToFill" contentHorizontalAlignment="left" contentVerticalAlignment="top" segmentControlStyle="plain" selectedSegmentIndex="0" translatesAutoresizingMaskIntoConstraints="NO" id="rAZ-eJ-sxy"> <segmentedControl opaque="NO" contentMode="scaleToFill" contentHorizontalAlignment="left" contentVerticalAlignment="top" segmentControlStyle="plain" selectedSegmentIndex="0" translatesAutoresizingMaskIntoConstraints="NO" id="rAZ-eJ-sxy">
<rect key="frame" x="20" y="20" width="560" height="29"/> <rect key="frame" x="20" y="20" width="335" height="29"/>
<segments> <segments>
<segment title="First"/> <segment title="First"/>
<segment title="Second"/> <segment title="Second"/>
<segment title=""/> <segment title=""/>
</segments> </segments>
<color key="tintColor" red="1" green="1" blue="1" alpha="1" colorSpace="calibratedRGB"/> <color key="tintColor" red="1" green="1" blue="1" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
<connections> <connections>
<action selector="segmentedControlValueChanged:" destination="iVv-Vc-nCL" eventType="valueChanged" id="RwG-kW-RPg"/> <action selector="segmentedControlValueChanged:" destination="iVv-Vc-nCL" eventType="valueChanged" id="RwG-kW-RPg"/>
</connections> </connections>
</segmentedControl> </segmentedControl>
<progressView opaque="NO" clipsSubviews="YES" contentMode="scaleToFill" verticalHuggingPriority="750" progress="0.5" translatesAutoresizingMaskIntoConstraints="NO" id="869-wx-Odb"> <progressView opaque="NO" clipsSubviews="YES" contentMode="scaleToFill" verticalHuggingPriority="750" progress="0.5" translatesAutoresizingMaskIntoConstraints="NO" id="869-wx-Odb">
<rect key="frame" x="20" y="68" width="560" height="2"/> <rect key="frame" x="20" y="68" width="335" height="2"/>
<color key="progressTintColor" red="1" green="1" blue="1" alpha="1" colorSpace="calibratedRGB"/> <color key="progressTintColor" red="1" green="1" blue="1" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
<color key="trackTintColor" white="1" alpha="0.20000000000000001" colorSpace="calibratedWhite"/> <color key="trackTintColor" red="1" green="1" blue="1" alpha="0.20000000000000001" colorSpace="custom" customColorSpace="sRGB"/>
</progressView> </progressView>
</subviews> </subviews>
<color key="backgroundColor" red="0.20392156859999999" green="0.28627450980000002" blue="0.36862745099999999" alpha="1" colorSpace="custom" customColorSpace="sRGB"/> <color key="backgroundColor" red="0.15542715787887573" green="0.2203737199306488" blue="0.2959403395652771" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
<constraints> <constraints>
<constraint firstItem="zxy-nY-P44" firstAttribute="leading" secondItem="i7U-bW-juB" secondAttribute="leading" constant="20" id="1u1-Tq-hRn"/> <constraint firstItem="zxy-nY-P44" firstAttribute="leading" secondItem="i7U-bW-juB" secondAttribute="leading" constant="20" id="1u1-Tq-hRn"/>
<constraint firstItem="6Ac-xl-ldZ" firstAttribute="top" secondItem="zxy-nY-P44" secondAttribute="bottom" constant="14.5" id="39B-9l-O3g"/> <constraint firstItem="6Ac-xl-ldZ" firstAttribute="top" secondItem="zxy-nY-P44" secondAttribute="bottom" constant="14.5" id="39B-9l-O3g"/>
@@ -237,7 +223,7 @@
</constraints> </constraints>
</view> </view>
</subviews> </subviews>
<color key="backgroundColor" white="1" alpha="1" colorSpace="calibratedWhite"/> <color key="backgroundColor" red="1" green="1" blue="1" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
<constraints> <constraints>
<constraint firstAttribute="height" constant="260" id="90R-Mf-iAB"/> <constraint firstAttribute="height" constant="260" id="90R-Mf-iAB"/>
<constraint firstItem="i7U-bW-juB" firstAttribute="leading" secondItem="XKA-Ub-c2X" secondAttribute="leading" id="e9h-f4-c37"/> <constraint firstItem="i7U-bW-juB" firstAttribute="leading" secondItem="XKA-Ub-c2X" secondAttribute="leading" id="e9h-f4-c37"/>
@@ -246,7 +232,7 @@
</constraints> </constraints>
</view> </view>
</subviews> </subviews>
<color key="backgroundColor" white="1" alpha="1" colorSpace="calibratedWhite"/> <color key="backgroundColor" red="1" green="1" blue="1" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
<constraints> <constraints>
<constraint firstAttribute="trailing" secondItem="XKA-Ub-c2X" secondAttribute="trailing" id="U0P-51-KT9"/> <constraint firstAttribute="trailing" secondItem="XKA-Ub-c2X" secondAttribute="trailing" id="U0P-51-KT9"/>
<constraint firstAttribute="trailing" secondItem="WUc-3Y-Quw" secondAttribute="trailing" id="i7I-7B-97K"/> <constraint firstAttribute="trailing" secondItem="WUc-3Y-Quw" secondAttribute="trailing" id="i7I-7B-97K"/>
@@ -276,31 +262,31 @@
<objects> <objects>
<tableViewController id="t0d-B0-B7U" sceneMemberID="viewController"> <tableViewController id="t0d-B0-B7U" sceneMemberID="viewController">
<tableView key="view" clipsSubviews="YES" contentMode="scaleToFill" alwaysBounceVertical="YES" dataMode="static" style="grouped" separatorStyle="default" rowHeight="50" sectionHeaderHeight="10" sectionFooterHeight="10" id="uHB-Yr-ujV"> <tableView key="view" clipsSubviews="YES" contentMode="scaleToFill" alwaysBounceVertical="YES" dataMode="static" style="grouped" separatorStyle="default" rowHeight="50" sectionHeaderHeight="10" sectionFooterHeight="10" id="uHB-Yr-ujV">
<rect key="frame" x="0.0" y="0.0" width="600" height="600"/> <rect key="frame" x="0.0" y="0.0" width="375" height="667"/>
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/> <autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
<color key="backgroundColor" red="0.93725490196078431" green="0.93725490196078431" blue="0.95686274509803926" alpha="1" colorSpace="calibratedRGB"/> <color key="backgroundColor" red="0.93725490196078431" green="0.93725490196078431" blue="0.95686274509803926" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
<sections> <sections>
<tableViewSection id="wIP-Hn-YfF"> <tableViewSection id="wIP-Hn-YfF">
<cells> <cells>
<tableViewCell contentMode="scaleToFill" selectionStyle="default" accessoryType="disclosureIndicator" indentationWidth="10" textLabel="Q3n-Df-v1t" detailTextLabel="Hbn-cf-Y7m" style="IBUITableViewCellStyleSubtitle" id="AXm-KE-45G"> <tableViewCell contentMode="scaleToFill" selectionStyle="default" accessoryType="disclosureIndicator" indentationWidth="10" textLabel="Q3n-Df-v1t" detailTextLabel="Hbn-cf-Y7m" style="IBUITableViewCellStyleSubtitle" id="AXm-KE-45G">
<rect key="frame" x="0.0" y="99" width="600" height="50"/> <rect key="frame" x="0.0" y="35" width="375" height="50"/>
<autoresizingMask key="autoresizingMask"/> <autoresizingMask key="autoresizingMask"/>
<tableViewCellContentView key="contentView" opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center" tableViewCell="AXm-KE-45G" id="9te-Wx-hkf"> <tableViewCellContentView key="contentView" opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center" tableViewCell="AXm-KE-45G" id="9te-Wx-hkf">
<rect key="frame" x="0.0" y="0.0" width="567" height="49.5"/> <rect key="frame" x="0.0" y="0.0" width="341" height="49.5"/>
<autoresizingMask key="autoresizingMask"/> <autoresizingMask key="autoresizingMask"/>
<subviews> <subviews>
<label opaque="NO" multipleTouchEnabled="YES" contentMode="left" text="Accounts" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" id="Q3n-Df-v1t"> <label opaque="NO" multipleTouchEnabled="YES" contentMode="left" text="Accounts" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" id="Q3n-Df-v1t">
<rect key="frame" x="15" y="6" width="82" height="24"/> <rect key="frame" x="16" y="6" width="82" height="24"/>
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMaxY="YES"/> <autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMaxY="YES"/>
<fontDescription key="fontDescription" name="HelveticaNeue-Light" family="Helvetica Neue" pointSize="20"/> <fontDescription key="fontDescription" name="HelveticaNeue-Light" family="Helvetica Neue" pointSize="20"/>
<color key="textColor" red="0.17254901960784313" green="0.24313725490196078" blue="0.31372549019607843" alpha="1" colorSpace="custom" customColorSpace="sRGB"/> <color key="textColor" red="0.13079629838466644" green="0.184075728058815" blue="0.24594299495220184" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
<nil key="highlightedColor"/> <nil key="highlightedColor"/>
</label> </label>
<label opaque="NO" multipleTouchEnabled="YES" contentMode="left" text="Setting up multiple persistent store configurations" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" id="Hbn-cf-Y7m"> <label opaque="NO" multipleTouchEnabled="YES" contentMode="left" text="Setting up multiple persistent store configurations" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" id="Hbn-cf-Y7m">
<rect key="frame" x="15" y="30" width="263.5" height="13.5"/> <rect key="frame" x="16" y="30" width="263.5" height="13.5"/>
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMaxY="YES"/> <autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMaxY="YES"/>
<fontDescription key="fontDescription" type="system" pointSize="11"/> <fontDescription key="fontDescription" type="system" pointSize="11"/>
<color key="textColor" red="0.17254901959999999" green="0.24313725489999999" blue="0.31372549020000001" alpha="1" colorSpace="custom" customColorSpace="sRGB"/> <color key="textColor" red="0.13079629838466644" green="0.184075728058815" blue="0.24594299495220184" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
<nil key="highlightedColor"/> <nil key="highlightedColor"/>
</label> </label>
</subviews> </subviews>
@@ -310,24 +296,24 @@
</connections> </connections>
</tableViewCell> </tableViewCell>
<tableViewCell contentMode="scaleToFill" selectionStyle="default" accessoryType="disclosureIndicator" indentationWidth="10" textLabel="vpt-cT-gMo" detailTextLabel="ou9-TZ-8bf" style="IBUITableViewCellStyleSubtitle" id="fsb-zw-8Ii"> <tableViewCell contentMode="scaleToFill" selectionStyle="default" accessoryType="disclosureIndicator" indentationWidth="10" textLabel="vpt-cT-gMo" detailTextLabel="ou9-TZ-8bf" style="IBUITableViewCellStyleSubtitle" id="fsb-zw-8Ii">
<rect key="frame" x="0.0" y="149" width="600" height="50"/> <rect key="frame" x="0.0" y="85" width="375" height="50"/>
<autoresizingMask key="autoresizingMask"/> <autoresizingMask key="autoresizingMask"/>
<tableViewCellContentView key="contentView" opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center" tableViewCell="fsb-zw-8Ii" id="Upm-AO-Fw3"> <tableViewCellContentView key="contentView" opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center" tableViewCell="fsb-zw-8Ii" id="Upm-AO-Fw3">
<rect key="frame" x="0.0" y="0.0" width="567" height="49.5"/> <rect key="frame" x="0.0" y="0.0" width="341" height="49.5"/>
<autoresizingMask key="autoresizingMask"/> <autoresizingMask key="autoresizingMask"/>
<subviews> <subviews>
<label opaque="NO" multipleTouchEnabled="YES" contentMode="left" text="Colors" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" id="vpt-cT-gMo"> <label opaque="NO" multipleTouchEnabled="YES" contentMode="left" text="Colors" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" id="vpt-cT-gMo">
<rect key="frame" x="15" y="6" width="56" height="24"/> <rect key="frame" x="16" y="6" width="56" height="24"/>
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMaxY="YES"/> <autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMaxY="YES"/>
<fontDescription key="fontDescription" name="HelveticaNeue-Light" family="Helvetica Neue" pointSize="20"/> <fontDescription key="fontDescription" name="HelveticaNeue-Light" family="Helvetica Neue" pointSize="20"/>
<color key="textColor" red="0.17254901959999999" green="0.24313725489999999" blue="0.31372549020000001" alpha="1" colorSpace="custom" customColorSpace="sRGB"/> <color key="textColor" red="0.13079629838466644" green="0.184075728058815" blue="0.24594299495220184" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
<nil key="highlightedColor"/> <nil key="highlightedColor"/>
</label> </label>
<label opaque="NO" multipleTouchEnabled="YES" contentMode="left" text="Observing list changes and single object changes" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" id="ou9-TZ-8bf"> <label opaque="NO" multipleTouchEnabled="YES" contentMode="left" text="Observing list changes and single object changes" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" id="ou9-TZ-8bf">
<rect key="frame" x="15" y="30" width="260.5" height="13.5"/> <rect key="frame" x="16" y="30" width="260.5" height="13.5"/>
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMaxY="YES"/> <autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMaxY="YES"/>
<fontDescription key="fontDescription" type="system" pointSize="11"/> <fontDescription key="fontDescription" type="system" pointSize="11"/>
<color key="textColor" red="0.17254901959999999" green="0.24313725489999999" blue="0.31372549020000001" alpha="1" colorSpace="custom" customColorSpace="sRGB"/> <color key="textColor" red="0.13079629838466644" green="0.184075728058815" blue="0.24594299495220184" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
<nil key="highlightedColor"/> <nil key="highlightedColor"/>
</label> </label>
</subviews> </subviews>
@@ -337,24 +323,24 @@
</connections> </connections>
</tableViewCell> </tableViewCell>
<tableViewCell contentMode="scaleToFill" selectionStyle="default" accessoryType="disclosureIndicator" indentationWidth="10" textLabel="UbU-Kd-yrY" detailTextLabel="uP1-Jc-o9v" style="IBUITableViewCellStyleSubtitle" id="ekW-PJ-mbo"> <tableViewCell contentMode="scaleToFill" selectionStyle="default" accessoryType="disclosureIndicator" indentationWidth="10" textLabel="UbU-Kd-yrY" detailTextLabel="uP1-Jc-o9v" style="IBUITableViewCellStyleSubtitle" id="ekW-PJ-mbo">
<rect key="frame" x="0.0" y="199" width="600" height="50"/> <rect key="frame" x="0.0" y="135" width="375" height="50"/>
<autoresizingMask key="autoresizingMask"/> <autoresizingMask key="autoresizingMask"/>
<tableViewCellContentView key="contentView" opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center" tableViewCell="ekW-PJ-mbo" id="CYq-mg-PVS"> <tableViewCellContentView key="contentView" opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center" tableViewCell="ekW-PJ-mbo" id="CYq-mg-PVS">
<rect key="frame" x="0.0" y="0.0" width="567" height="49.5"/> <rect key="frame" x="0.0" y="0.0" width="341" height="49.5"/>
<autoresizingMask key="autoresizingMask"/> <autoresizingMask key="autoresizingMask"/>
<subviews> <subviews>
<label opaque="NO" multipleTouchEnabled="YES" contentMode="left" text="Placemarks" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" id="UbU-Kd-yrY"> <label opaque="NO" multipleTouchEnabled="YES" contentMode="left" text="Placemarks" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" id="UbU-Kd-yrY">
<rect key="frame" x="15" y="6" width="100.5" height="24"/> <rect key="frame" x="16" y="6" width="100.5" height="24"/>
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMaxY="YES"/> <autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMaxY="YES"/>
<fontDescription key="fontDescription" name="HelveticaNeue-Light" family="Helvetica Neue" pointSize="20"/> <fontDescription key="fontDescription" name="HelveticaNeue-Light" family="Helvetica Neue" pointSize="20"/>
<color key="textColor" red="0.17254901959999999" green="0.24313725489999999" blue="0.31372549020000001" alpha="1" colorSpace="custom" customColorSpace="sRGB"/> <color key="textColor" red="0.13079629838466644" green="0.184075728058815" blue="0.24594299495220184" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
<nil key="highlightedColor"/> <nil key="highlightedColor"/>
</label> </label>
<label opaque="NO" multipleTouchEnabled="YES" contentMode="left" text="Making changes with transactions" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" id="uP1-Jc-o9v"> <label opaque="NO" multipleTouchEnabled="YES" contentMode="left" text="Making changes with transactions" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" id="uP1-Jc-o9v">
<rect key="frame" x="15" y="30" width="179" height="13.5"/> <rect key="frame" x="16" y="30" width="179" height="13.5"/>
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMaxY="YES"/> <autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMaxY="YES"/>
<fontDescription key="fontDescription" type="system" pointSize="11"/> <fontDescription key="fontDescription" type="system" pointSize="11"/>
<color key="textColor" red="0.17254901959999999" green="0.24313725489999999" blue="0.31372549020000001" alpha="1" colorSpace="custom" customColorSpace="sRGB"/> <color key="textColor" red="0.13079629838466644" green="0.184075728058815" blue="0.24594299495220184" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
<nil key="highlightedColor"/> <nil key="highlightedColor"/>
</label> </label>
</subviews> </subviews>
@@ -364,24 +350,24 @@
</connections> </connections>
</tableViewCell> </tableViewCell>
<tableViewCell contentMode="scaleToFill" selectionStyle="default" accessoryType="disclosureIndicator" indentationWidth="10" textLabel="C8Y-0y-lEG" detailTextLabel="jZw-qE-0ws" style="IBUITableViewCellStyleSubtitle" id="ph1-8z-C1m"> <tableViewCell contentMode="scaleToFill" selectionStyle="default" accessoryType="disclosureIndicator" indentationWidth="10" textLabel="C8Y-0y-lEG" detailTextLabel="jZw-qE-0ws" style="IBUITableViewCellStyleSubtitle" id="ph1-8z-C1m">
<rect key="frame" x="0.0" y="249" width="600" height="50"/> <rect key="frame" x="0.0" y="185" width="375" height="50"/>
<autoresizingMask key="autoresizingMask"/> <autoresizingMask key="autoresizingMask"/>
<tableViewCellContentView key="contentView" opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center" tableViewCell="ph1-8z-C1m" id="nNz-rd-ksg"> <tableViewCellContentView key="contentView" opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center" tableViewCell="ph1-8z-C1m" id="nNz-rd-ksg">
<rect key="frame" x="0.0" y="0.0" width="567" height="49.5"/> <rect key="frame" x="0.0" y="0.0" width="341" height="49.5"/>
<autoresizingMask key="autoresizingMask"/> <autoresizingMask key="autoresizingMask"/>
<subviews> <subviews>
<label opaque="NO" multipleTouchEnabled="YES" contentMode="left" text="Time Zones" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" id="C8Y-0y-lEG"> <label opaque="NO" multipleTouchEnabled="YES" contentMode="left" text="Time Zones" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" id="C8Y-0y-lEG">
<rect key="frame" x="15" y="6" width="101.5" height="24"/> <rect key="frame" x="16" y="6" width="101.5" height="24"/>
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMaxY="YES"/> <autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMaxY="YES"/>
<fontDescription key="fontDescription" name="HelveticaNeue-Light" family="Helvetica Neue" pointSize="20"/> <fontDescription key="fontDescription" name="HelveticaNeue-Light" family="Helvetica Neue" pointSize="20"/>
<color key="textColor" red="0.17254901959999999" green="0.24313725489999999" blue="0.31372549020000001" alpha="1" colorSpace="custom" customColorSpace="sRGB"/> <color key="textColor" red="0.13079629838466644" green="0.184075728058815" blue="0.24594299495220184" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
<nil key="highlightedColor"/> <nil key="highlightedColor"/>
</label> </label>
<label opaque="NO" multipleTouchEnabled="YES" contentMode="left" text="Fetching objects and raw values" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" id="jZw-qE-0ws"> <label opaque="NO" multipleTouchEnabled="YES" contentMode="left" text="Fetching objects and raw values" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" id="jZw-qE-0ws">
<rect key="frame" x="15" y="30" width="168.5" height="13.5"/> <rect key="frame" x="16" y="30" width="168.5" height="13.5"/>
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMaxY="YES"/> <autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMaxY="YES"/>
<fontDescription key="fontDescription" type="system" pointSize="11"/> <fontDescription key="fontDescription" type="system" pointSize="11"/>
<color key="textColor" red="0.17254901959999999" green="0.24313725489999999" blue="0.31372549020000001" alpha="1" colorSpace="custom" customColorSpace="sRGB"/> <color key="textColor" red="0.13079629838466644" green="0.184075728058815" blue="0.24594299495220184" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
<nil key="highlightedColor"/> <nil key="highlightedColor"/>
</label> </label>
</subviews> </subviews>
@@ -391,24 +377,24 @@
</connections> </connections>
</tableViewCell> </tableViewCell>
<tableViewCell contentMode="scaleToFill" selectionStyle="default" accessoryType="disclosureIndicator" indentationWidth="10" textLabel="ZfY-Aq-Ykq" detailTextLabel="QzD-9b-k1j" style="IBUITableViewCellStyleSubtitle" id="wyK-rk-3tI"> <tableViewCell contentMode="scaleToFill" selectionStyle="default" accessoryType="disclosureIndicator" indentationWidth="10" textLabel="ZfY-Aq-Ykq" detailTextLabel="QzD-9b-k1j" style="IBUITableViewCellStyleSubtitle" id="wyK-rk-3tI">
<rect key="frame" x="0.0" y="299" width="600" height="50"/> <rect key="frame" x="0.0" y="235" width="375" height="50"/>
<autoresizingMask key="autoresizingMask"/> <autoresizingMask key="autoresizingMask"/>
<tableViewCellContentView key="contentView" opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center" tableViewCell="wyK-rk-3tI" id="fLd-KK-QcW"> <tableViewCellContentView key="contentView" opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center" tableViewCell="wyK-rk-3tI" id="fLd-KK-QcW">
<rect key="frame" x="0.0" y="0.0" width="567" height="49.5"/> <rect key="frame" x="0.0" y="0.0" width="341" height="49.5"/>
<autoresizingMask key="autoresizingMask"/> <autoresizingMask key="autoresizingMask"/>
<subviews> <subviews>
<label opaque="NO" multipleTouchEnabled="YES" contentMode="left" text="Logger" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" id="ZfY-Aq-Ykq"> <label opaque="NO" multipleTouchEnabled="YES" contentMode="left" text="Logger" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" id="ZfY-Aq-Ykq">
<rect key="frame" x="15" y="6" width="61" height="24"/> <rect key="frame" x="16" y="6" width="61" height="24"/>
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMaxY="YES"/> <autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMaxY="YES"/>
<fontDescription key="fontDescription" name="HelveticaNeue-Light" family="Helvetica Neue" pointSize="20"/> <fontDescription key="fontDescription" name="HelveticaNeue-Light" family="Helvetica Neue" pointSize="20"/>
<color key="textColor" red="0.17254901959999999" green="0.24313725489999999" blue="0.31372549020000001" alpha="1" colorSpace="custom" customColorSpace="sRGB"/> <color key="textColor" red="0.13079629838466644" green="0.184075728058815" blue="0.24594299495220184" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
<nil key="highlightedColor"/> <nil key="highlightedColor"/>
</label> </label>
<label opaque="NO" multipleTouchEnabled="YES" contentMode="left" text="Implementing a custom logger" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" id="QzD-9b-k1j"> <label opaque="NO" multipleTouchEnabled="YES" contentMode="left" text="Implementing a custom logger" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" id="QzD-9b-k1j">
<rect key="frame" x="15" y="30" width="159" height="13.5"/> <rect key="frame" x="16" y="30" width="159" height="13.5"/>
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMaxY="YES"/> <autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMaxY="YES"/>
<fontDescription key="fontDescription" type="system" pointSize="11"/> <fontDescription key="fontDescription" type="system" pointSize="11"/>
<color key="textColor" red="0.17254901959999999" green="0.24313725489999999" blue="0.31372549020000001" alpha="1" colorSpace="custom" customColorSpace="sRGB"/> <color key="textColor" red="0.13079629838466644" green="0.184075728058815" blue="0.24594299495220184" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
<nil key="highlightedColor"/> <nil key="highlightedColor"/>
</label> </label>
</subviews> </subviews>
@@ -418,24 +404,24 @@
</connections> </connections>
</tableViewCell> </tableViewCell>
<tableViewCell contentMode="scaleToFill" selectionStyle="default" accessoryType="disclosureIndicator" indentationWidth="10" textLabel="hSG-mG-YBw" detailTextLabel="X9P-TQ-LYh" style="IBUITableViewCellStyleSubtitle" id="xTM-Cf-0if"> <tableViewCell contentMode="scaleToFill" selectionStyle="default" accessoryType="disclosureIndicator" indentationWidth="10" textLabel="hSG-mG-YBw" detailTextLabel="X9P-TQ-LYh" style="IBUITableViewCellStyleSubtitle" id="xTM-Cf-0if">
<rect key="frame" x="0.0" y="349" width="600" height="50"/> <rect key="frame" x="0.0" y="285" width="375" height="50"/>
<autoresizingMask key="autoresizingMask"/> <autoresizingMask key="autoresizingMask"/>
<tableViewCellContentView key="contentView" opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center" tableViewCell="xTM-Cf-0if" id="DfO-BW-krd"> <tableViewCellContentView key="contentView" opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center" tableViewCell="xTM-Cf-0if" id="DfO-BW-krd">
<rect key="frame" x="0.0" y="0.0" width="567" height="49.5"/> <rect key="frame" x="0.0" y="0.0" width="341" height="49.5"/>
<autoresizingMask key="autoresizingMask"/> <autoresizingMask key="autoresizingMask"/>
<subviews> <subviews>
<label opaque="NO" multipleTouchEnabled="YES" contentMode="left" text="Evolution" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" id="hSG-mG-YBw"> <label opaque="NO" multipleTouchEnabled="YES" contentMode="left" text="Evolution" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" id="hSG-mG-YBw">
<rect key="frame" x="15" y="6" width="78.5" height="24"/> <rect key="frame" x="16" y="6" width="78.5" height="24"/>
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMaxY="YES"/> <autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMaxY="YES"/>
<fontDescription key="fontDescription" name="HelveticaNeue-Light" family="Helvetica Neue" pointSize="20"/> <fontDescription key="fontDescription" name="HelveticaNeue-Light" family="Helvetica Neue" pointSize="20"/>
<color key="textColor" red="0.17254901959999999" green="0.24313725489999999" blue="0.31372549020000001" alpha="1" colorSpace="custom" customColorSpace="sRGB"/> <color key="textColor" red="0.13079629838466644" green="0.184075728058815" blue="0.24594299495220184" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
<nil key="highlightedColor"/> <nil key="highlightedColor"/>
</label> </label>
<label opaque="NO" multipleTouchEnabled="YES" contentMode="left" text="Migrating and de-migrating stores" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" id="X9P-TQ-LYh"> <label opaque="NO" multipleTouchEnabled="YES" contentMode="left" text="Migrating and de-migrating stores" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" id="X9P-TQ-LYh">
<rect key="frame" x="15" y="30" width="179.5" height="13.5"/> <rect key="frame" x="16" y="30" width="179.5" height="13.5"/>
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMaxY="YES"/> <autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMaxY="YES"/>
<fontDescription key="fontDescription" type="system" pointSize="11"/> <fontDescription key="fontDescription" type="system" pointSize="11"/>
<color key="textColor" red="0.17254901959999999" green="0.24313725489999999" blue="0.31372549020000001" alpha="1" colorSpace="custom" customColorSpace="sRGB"/> <color key="textColor" red="0.13079629838466644" green="0.184075728058815" blue="0.24594299495220184" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
<nil key="highlightedColor"/> <nil key="highlightedColor"/>
</label> </label>
</subviews> </subviews>
@@ -467,69 +453,69 @@
<viewControllerLayoutGuide type="bottom" id="aI4-O3-OCi"/> <viewControllerLayoutGuide type="bottom" id="aI4-O3-OCi"/>
</layoutGuides> </layoutGuides>
<view key="view" contentMode="scaleToFill" id="w8K-eN-RvU"> <view key="view" contentMode="scaleToFill" id="w8K-eN-RvU">
<rect key="frame" x="0.0" y="0.0" width="592" height="268"/> <rect key="frame" x="0.0" y="0.0" width="375" height="301.5"/>
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/> <autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
<subviews> <subviews>
<view contentMode="scaleToFill" verticalCompressionResistancePriority="250" translatesAutoresizingMaskIntoConstraints="NO" id="NhC-oM-bkd"> <view contentMode="scaleToFill" verticalCompressionResistancePriority="250" translatesAutoresizingMaskIntoConstraints="NO" id="NhC-oM-bkd">
<rect key="frame" x="20" y="69.5" width="552" height="36.5"/> <rect key="frame" x="16" y="69.5" width="343" height="70"/>
<color key="backgroundColor" white="1" alpha="1" colorSpace="calibratedWhite"/> <color key="backgroundColor" red="1" green="1" blue="1" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
<constraints> <constraints>
<constraint firstAttribute="height" relation="greaterThanOrEqual" id="TIX-qi-B34"/> <constraint firstAttribute="height" relation="greaterThanOrEqual" id="TIX-qi-B34"/>
</constraints> </constraints>
</view> </view>
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" verticalCompressionResistancePriority="250" text="Label" textAlignment="center" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" minimumScaleFactor="0.5" adjustsLetterSpacingToFitWidth="YES" translatesAutoresizingMaskIntoConstraints="NO" id="Vfe-Yq-3Xa"> <label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" verticalCompressionResistancePriority="250" text="Label" textAlignment="center" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" minimumScaleFactor="0.5" adjustsLetterSpacingToFitWidth="YES" translatesAutoresizingMaskIntoConstraints="NO" id="Vfe-Yq-3Xa">
<rect key="frame" x="20" y="116" width="552" height="18"/> <rect key="frame" x="16" y="149.5" width="343" height="18"/>
<constraints> <constraints>
<constraint firstAttribute="height" relation="greaterThanOrEqual" id="4h9-ha-EzR"/> <constraint firstAttribute="height" relation="greaterThanOrEqual" id="4h9-ha-EzR"/>
</constraints> </constraints>
<fontDescription key="fontDescription" type="boldSystem" pointSize="15"/> <fontDescription key="fontDescription" type="boldSystem" pointSize="15"/>
<color key="textColor" red="0.0" green="0.0" blue="0.0" alpha="1" colorSpace="calibratedRGB"/> <color key="textColor" red="0.0" green="0.0" blue="0.0" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
<nil key="highlightedColor"/> <nil key="highlightedColor"/>
</label> </label>
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="Hue" textAlignment="right" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="sgg-Md-Nf3"> <label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="Hue" textAlignment="right" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="sgg-Md-Nf3">
<rect key="frame" x="20" y="154" width="74" height="18"/> <rect key="frame" x="16" y="187.5" width="74" height="18"/>
<fontDescription key="fontDescription" type="system" pointSize="15"/> <fontDescription key="fontDescription" type="system" pointSize="15"/>
<color key="textColor" red="0.0" green="0.0" blue="0.0" alpha="1" colorSpace="calibratedRGB"/> <color key="textColor" red="0.0" green="0.0" blue="0.0" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
<nil key="highlightedColor"/> <nil key="highlightedColor"/>
</label> </label>
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="Saturation" textAlignment="right" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="rry-vh-bRK"> <label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="Saturation" textAlignment="right" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="rry-vh-bRK">
<rect key="frame" x="20" y="192" width="74" height="18"/> <rect key="frame" x="16" y="225.5" width="74" height="18"/>
<fontDescription key="fontDescription" type="system" pointSize="15"/> <fontDescription key="fontDescription" type="system" pointSize="15"/>
<color key="textColor" red="0.0" green="0.0" blue="0.0" alpha="1" colorSpace="calibratedRGB"/> <color key="textColor" red="0.0" green="0.0" blue="0.0" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
<nil key="highlightedColor"/> <nil key="highlightedColor"/>
</label> </label>
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="Brightness" textAlignment="right" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="vTa-ly-eyO"> <label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="Brightness" textAlignment="right" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="vTa-ly-eyO">
<rect key="frame" x="20" y="230" width="74" height="18"/> <rect key="frame" x="16" y="263.5" width="74" height="18"/>
<fontDescription key="fontDescription" type="system" pointSize="15"/> <fontDescription key="fontDescription" type="system" pointSize="15"/>
<color key="textColor" red="0.0" green="0.0" blue="0.0" alpha="1" colorSpace="calibratedRGB"/> <color key="textColor" red="0.0" green="0.0" blue="0.0" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
<nil key="highlightedColor"/> <nil key="highlightedColor"/>
</label> </label>
<slider opaque="NO" contentMode="scaleToFill" contentHorizontalAlignment="center" contentVerticalAlignment="center" minValue="0.0" maxValue="359" translatesAutoresizingMaskIntoConstraints="NO" id="YQ6-fq-3Wb"> <slider opaque="NO" contentMode="scaleToFill" contentHorizontalAlignment="center" contentVerticalAlignment="center" minValue="0.0" maxValue="359" translatesAutoresizingMaskIntoConstraints="NO" id="YQ6-fq-3Wb">
<rect key="frame" x="102" y="148" width="472" height="31"/> <rect key="frame" x="98" y="181.5" width="263" height="31"/>
<connections> <connections>
<action selector="hueSliderValueDidChange:" destination="dX3-kR-CYC" eventType="valueChanged" id="9Hy-3h-llE"/> <action selector="hueSliderValueDidChange:" destination="dX3-kR-CYC" eventType="valueChanged" id="9Hy-3h-llE"/>
</connections> </connections>
</slider> </slider>
<slider opaque="NO" contentMode="scaleToFill" contentHorizontalAlignment="center" contentVerticalAlignment="center" value="1" minValue="0.0" maxValue="1" translatesAutoresizingMaskIntoConstraints="NO" id="xXz-78-tAd"> <slider opaque="NO" contentMode="scaleToFill" contentHorizontalAlignment="center" contentVerticalAlignment="center" value="1" minValue="0.0" maxValue="1" translatesAutoresizingMaskIntoConstraints="NO" id="xXz-78-tAd">
<rect key="frame" x="102" y="186" width="472" height="31"/> <rect key="frame" x="98" y="219.5" width="263" height="31"/>
<connections> <connections>
<action selector="saturationSliderValueDidChange:" destination="dX3-kR-CYC" eventType="valueChanged" id="qtU-ua-ZTc"/> <action selector="saturationSliderValueDidChange:" destination="dX3-kR-CYC" eventType="valueChanged" id="qtU-ua-ZTc"/>
</connections> </connections>
</slider> </slider>
<slider opaque="NO" contentMode="scaleToFill" contentHorizontalAlignment="center" contentVerticalAlignment="center" value="0.5" minValue="0.0" maxValue="1" translatesAutoresizingMaskIntoConstraints="NO" id="hpy-2d-eOP"> <slider opaque="NO" contentMode="scaleToFill" contentHorizontalAlignment="center" contentVerticalAlignment="center" value="0.5" minValue="0.0" maxValue="1" translatesAutoresizingMaskIntoConstraints="NO" id="hpy-2d-eOP">
<rect key="frame" x="102" y="224" width="472" height="31"/> <rect key="frame" x="98" y="257.5" width="263" height="31"/>
<connections> <connections>
<action selector="brightnessSliderValueDidChange:" destination="dX3-kR-CYC" eventType="valueChanged" id="F09-EP-2iD"/> <action selector="brightnessSliderValueDidChange:" destination="dX3-kR-CYC" eventType="valueChanged" id="F09-EP-2iD"/>
</connections> </connections>
</slider> </slider>
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="Label" textAlignment="center" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="p4O-tf-dgt"> <label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="Label" textAlignment="center" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="p4O-tf-dgt">
<rect key="frame" x="20" y="49" width="552" height="20.5"/> <rect key="frame" x="16" y="49" width="343" height="20.5"/>
<fontDescription key="fontDescription" type="boldSystem" pointSize="17"/> <fontDescription key="fontDescription" type="boldSystem" pointSize="17"/>
<color key="textColor" red="0.0" green="0.0" blue="0.0" alpha="1" colorSpace="calibratedRGB"/> <color key="textColor" red="0.0" green="0.0" blue="0.0" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
<nil key="highlightedColor"/> <nil key="highlightedColor"/>
</label> </label>
</subviews> </subviews>
<color key="backgroundColor" white="1" alpha="1" colorSpace="calibratedWhite"/> <color key="backgroundColor" red="1" green="1" blue="1" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
<constraints> <constraints>
<constraint firstItem="p4O-tf-dgt" firstAttribute="trailing" secondItem="w8K-eN-RvU" secondAttribute="trailingMargin" id="022-ll-1s1"/> <constraint firstItem="p4O-tf-dgt" firstAttribute="trailing" secondItem="w8K-eN-RvU" secondAttribute="trailingMargin" id="022-ll-1s1"/>
<constraint firstItem="vTa-ly-eyO" firstAttribute="top" secondItem="rry-vh-bRK" secondAttribute="bottom" constant="20" id="1hd-Ti-CnT"/> <constraint firstItem="vTa-ly-eyO" firstAttribute="top" secondItem="rry-vh-bRK" secondAttribute="bottom" constant="20" id="1hd-Ti-CnT"/>
@@ -591,23 +577,23 @@
<viewControllerLayoutGuide type="bottom" id="LNL-mj-D7l"/> <viewControllerLayoutGuide type="bottom" id="LNL-mj-D7l"/>
</layoutGuides> </layoutGuides>
<view key="view" contentMode="scaleToFill" id="6x3-vn-Egt"> <view key="view" contentMode="scaleToFill" id="6x3-vn-Egt">
<rect key="frame" x="0.0" y="0.0" width="600" height="600"/> <rect key="frame" x="0.0" y="0.0" width="375" height="667"/>
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/> <autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
<subviews> <subviews>
<containerView opaque="NO" contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="L5f-tW-lXf"> <containerView opaque="NO" contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="L5f-tW-lXf">
<rect key="frame" x="4" y="64" width="592" height="268"/> <rect key="frame" x="0.0" y="64" width="375" height="301.5"/>
<connections> <connections>
<segue destination="5Fw-je-9gI" kind="embed" id="YcI-2Z-ijV"/> <segue destination="5Fw-je-9gI" kind="embed" id="YcI-2Z-ijV"/>
</connections> </connections>
</containerView> </containerView>
<containerView opaque="NO" contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="6So-f3-4Gp"> <containerView opaque="NO" contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="6So-f3-4Gp">
<rect key="frame" x="4" y="332" width="592" height="268"/> <rect key="frame" x="0.0" y="365.5" width="375" height="301.5"/>
<connections> <connections>
<segue destination="sll-yo-mBc" kind="embed" id="AAl-HS-dq2"/> <segue destination="sll-yo-mBc" kind="embed" id="AAl-HS-dq2"/>
</connections> </connections>
</containerView> </containerView>
</subviews> </subviews>
<color key="backgroundColor" white="1" alpha="1" colorSpace="calibratedWhite"/> <color key="backgroundColor" red="1" green="1" blue="1" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
<constraints> <constraints>
<constraint firstItem="6So-f3-4Gp" firstAttribute="top" secondItem="L5f-tW-lXf" secondAttribute="bottom" id="3m8-tj-Nd4"/> <constraint firstItem="6So-f3-4Gp" firstAttribute="top" secondItem="L5f-tW-lXf" secondAttribute="bottom" id="3m8-tj-Nd4"/>
<constraint firstAttribute="trailingMargin" secondItem="6So-f3-4Gp" secondAttribute="trailing" constant="-16" id="4L8-wZ-F59"/> <constraint firstAttribute="trailingMargin" secondItem="6So-f3-4Gp" secondAttribute="trailing" constant="-16" id="4L8-wZ-F59"/>
@@ -634,13 +620,13 @@
<tabBarItem key="tabBarItem" title="Demo" image="second" id="3iQ-I2-4LW"/> <tabBarItem key="tabBarItem" title="Demo" image="second" id="3iQ-I2-4LW"/>
<toolbarItems/> <toolbarItems/>
<navigationBar key="navigationBar" contentMode="scaleToFill" id="00L-5k-Eno"> <navigationBar key="navigationBar" contentMode="scaleToFill" id="00L-5k-Eno">
<rect key="frame" x="0.0" y="0.0" width="320" height="44"/> <rect key="frame" x="0.0" y="20" width="375" height="44"/>
<autoresizingMask key="autoresizingMask"/> <autoresizingMask key="autoresizingMask"/>
<color key="tintColor" red="0.92549019610000005" green="0.94117647059999998" blue="0.94509803920000002" alpha="1" colorSpace="custom" customColorSpace="sRGB"/> <color key="tintColor" red="0.90744441747665405" green="0.9265514612197876" blue="0.93116652965545654" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
<color key="barTintColor" red="0.20392156859999999" green="0.28627450980000002" blue="0.36862745099999999" alpha="1" colorSpace="custom" customColorSpace="sRGB"/> <color key="barTintColor" red="0.15542715787887573" green="0.2203737199306488" blue="0.2959403395652771" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
<textAttributes key="titleTextAttributes"> <textAttributes key="titleTextAttributes">
<fontDescription key="fontDescription" name="HelveticaNeue-UltraLight" family="Helvetica Neue" pointSize="24"/> <fontDescription key="fontDescription" name="HelveticaNeue-UltraLight" family="Helvetica Neue" pointSize="24"/>
<color key="textColor" red="0.92549019607843142" green="0.94117647058823528" blue="0.94509803921568625" alpha="1" colorSpace="custom" customColorSpace="sRGB"/> <color key="textColor" red="0.90744441747665405" green="0.9265514612197876" blue="0.93116652965545654" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
</textAttributes> </textAttributes>
</navigationBar> </navigationBar>
<nil name="viewControllers"/> <nil name="viewControllers"/>
@@ -657,27 +643,27 @@
<objects> <objects>
<tableViewController id="3AE-ED-0oj" customClass="ListObserverDemoViewController" customModule="CoreStoreDemo" customModuleProvider="target" sceneMemberID="viewController"> <tableViewController id="3AE-ED-0oj" customClass="ListObserverDemoViewController" customModule="CoreStoreDemo" customModuleProvider="target" sceneMemberID="viewController">
<tableView key="view" clipsSubviews="YES" contentMode="scaleToFill" alwaysBounceVertical="YES" dataMode="prototypes" style="plain" separatorStyle="default" rowHeight="44" sectionHeaderHeight="22" sectionFooterHeight="22" id="DAz-BE-6Ca"> <tableView key="view" clipsSubviews="YES" contentMode="scaleToFill" alwaysBounceVertical="YES" dataMode="prototypes" style="plain" separatorStyle="default" rowHeight="44" sectionHeaderHeight="22" sectionFooterHeight="22" id="DAz-BE-6Ca">
<rect key="frame" x="0.0" y="0.0" width="592" height="268"/> <rect key="frame" x="0.0" y="0.0" width="375" height="301.5"/>
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/> <autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
<prototypes> <prototypes>
<tableViewCell contentMode="scaleToFill" selectionStyle="default" accessoryType="disclosureIndicator" indentationWidth="10" reuseIdentifier="PaletteTableViewCell" id="G3X-70-BCD" customClass="PaletteTableViewCell" customModule="CoreStoreDemo" customModuleProvider="target"> <tableViewCell contentMode="scaleToFill" selectionStyle="default" accessoryType="disclosureIndicator" indentationWidth="10" reuseIdentifier="PaletteTableViewCell" id="G3X-70-BCD" customClass="PaletteTableViewCell" customModule="CoreStoreDemo" customModuleProvider="target">
<rect key="frame" x="0.0" y="66" width="592" height="44"/> <rect key="frame" x="0.0" y="22" width="375" height="44"/>
<autoresizingMask key="autoresizingMask"/> <autoresizingMask key="autoresizingMask"/>
<tableViewCellContentView key="contentView" opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center" tableViewCell="G3X-70-BCD" id="aT8-nz-i5l"> <tableViewCellContentView key="contentView" opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center" tableViewCell="G3X-70-BCD" id="aT8-nz-i5l">
<rect key="frame" x="0.0" y="0.0" width="559" height="43.5"/> <rect key="frame" x="0.0" y="0.0" width="341" height="43.5"/>
<autoresizingMask key="autoresizingMask"/> <autoresizingMask key="autoresizingMask"/>
<subviews> <subviews>
<view contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="uQX-PI-UWF"> <view contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="uQX-PI-UWF">
<rect key="frame" x="8" y="8" width="27" height="27"/> <rect key="frame" x="16" y="11" width="22" height="22"/>
<color key="backgroundColor" white="1" alpha="1" colorSpace="calibratedWhite"/> <color key="backgroundColor" red="1" green="1" blue="1" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
<constraints> <constraints>
<constraint firstAttribute="width" secondItem="uQX-PI-UWF" secondAttribute="height" multiplier="1:1" id="9qA-iN-Neb"/> <constraint firstAttribute="width" secondItem="uQX-PI-UWF" secondAttribute="height" multiplier="1:1" id="9qA-iN-Neb"/>
</constraints> </constraints>
</view> </view>
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="Label" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="HJC-5w-lIN"> <label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="Label" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="HJC-5w-lIN">
<rect key="frame" x="45" y="8" width="34.5" height="27"/> <rect key="frame" x="48" y="11" width="34.5" height="22"/>
<fontDescription key="fontDescription" name="HelveticaNeue" family="Helvetica Neue" pointSize="14"/> <fontDescription key="fontDescription" name="HelveticaNeue" family="Helvetica Neue" pointSize="14"/>
<color key="textColor" red="0.17254901959999999" green="0.24313725489999999" blue="0.31372549020000001" alpha="1" colorSpace="custom" customColorSpace="sRGB"/> <color key="textColor" red="0.13079629838466644" green="0.184075728058815" blue="0.24594299495220184" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
<nil key="highlightedColor"/> <nil key="highlightedColor"/>
</label> </label>
</subviews> </subviews>
@@ -716,28 +702,28 @@
<objects> <objects>
<tableViewController id="lCE-i6-UCT" customClass="ListObserverDemoViewController" customModule="CoreStoreDemo" customModuleProvider="target" sceneMemberID="viewController"> <tableViewController id="lCE-i6-UCT" customClass="ListObserverDemoViewController" customModule="CoreStoreDemo" customModuleProvider="target" sceneMemberID="viewController">
<tableView key="view" clipsSubviews="YES" contentMode="scaleToFill" alwaysBounceVertical="YES" dataMode="prototypes" style="plain" separatorStyle="default" rowHeight="44" sectionHeaderHeight="22" sectionFooterHeight="22" id="Zba-8M-Zd7"> <tableView key="view" clipsSubviews="YES" contentMode="scaleToFill" alwaysBounceVertical="YES" dataMode="prototypes" style="plain" separatorStyle="default" rowHeight="44" sectionHeaderHeight="22" sectionFooterHeight="22" id="Zba-8M-Zd7">
<rect key="frame" x="0.0" y="0.0" width="592" height="268"/> <rect key="frame" x="0.0" y="0.0" width="375" height="301.5"/>
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/> <autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
<color key="backgroundColor" white="1" alpha="1" colorSpace="calibratedWhite"/> <color key="backgroundColor" red="1" green="1" blue="1" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
<prototypes> <prototypes>
<tableViewCell contentMode="scaleToFill" selectionStyle="default" accessoryType="disclosureIndicator" indentationWidth="10" reuseIdentifier="PaletteTableViewCell" id="zSO-3e-OVq" customClass="PaletteTableViewCell" customModule="CoreStoreDemo" customModuleProvider="target"> <tableViewCell contentMode="scaleToFill" selectionStyle="default" accessoryType="disclosureIndicator" indentationWidth="10" reuseIdentifier="PaletteTableViewCell" id="zSO-3e-OVq" customClass="PaletteTableViewCell" customModule="CoreStoreDemo" customModuleProvider="target">
<rect key="frame" x="0.0" y="66" width="592" height="44"/> <rect key="frame" x="0.0" y="22" width="375" height="44"/>
<autoresizingMask key="autoresizingMask"/> <autoresizingMask key="autoresizingMask"/>
<tableViewCellContentView key="contentView" opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center" tableViewCell="zSO-3e-OVq" id="cHA-by-n4b"> <tableViewCellContentView key="contentView" opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center" tableViewCell="zSO-3e-OVq" id="cHA-by-n4b">
<rect key="frame" x="0.0" y="0.0" width="559" height="43.5"/> <rect key="frame" x="0.0" y="0.0" width="341" height="43.5"/>
<autoresizingMask key="autoresizingMask"/> <autoresizingMask key="autoresizingMask"/>
<subviews> <subviews>
<view contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="5uq-Yi-XwH"> <view contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="5uq-Yi-XwH">
<rect key="frame" x="8" y="8" width="27" height="27"/> <rect key="frame" x="16" y="11" width="22" height="22"/>
<color key="backgroundColor" white="1" alpha="1" colorSpace="calibratedWhite"/> <color key="backgroundColor" red="1" green="1" blue="1" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
<constraints> <constraints>
<constraint firstAttribute="width" secondItem="5uq-Yi-XwH" secondAttribute="height" multiplier="1:1" id="oOe-HC-VyN"/> <constraint firstAttribute="width" secondItem="5uq-Yi-XwH" secondAttribute="height" multiplier="1:1" id="oOe-HC-VyN"/>
</constraints> </constraints>
</view> </view>
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="Label" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="Zyu-PC-WmO"> <label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="Label" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="Zyu-PC-WmO">
<rect key="frame" x="45" y="8" width="34.5" height="27"/> <rect key="frame" x="48" y="11" width="34.5" height="22"/>
<fontDescription key="fontDescription" name="HelveticaNeue" family="Helvetica Neue" pointSize="14"/> <fontDescription key="fontDescription" name="HelveticaNeue" family="Helvetica Neue" pointSize="14"/>
<color key="textColor" red="0.17254901959999999" green="0.24313725489999999" blue="0.31372549020000001" alpha="1" colorSpace="custom" customColorSpace="sRGB"/> <color key="textColor" red="0.13079629838466644" green="0.184075728058815" blue="0.24594299495220184" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
<nil key="highlightedColor"/> <nil key="highlightedColor"/>
</label> </label>
</subviews> </subviews>
@@ -778,13 +764,13 @@
<extendedEdge key="edgesForExtendedLayout" bottom="YES"/> <extendedEdge key="edgesForExtendedLayout" bottom="YES"/>
<toolbarItems/> <toolbarItems/>
<navigationBar key="navigationBar" contentMode="scaleToFill" id="6XA-6M-yvZ"> <navigationBar key="navigationBar" contentMode="scaleToFill" id="6XA-6M-yvZ">
<rect key="frame" x="0.0" y="0.0" width="320" height="44"/> <rect key="frame" x="0.0" y="0.0" width="375" height="44"/>
<autoresizingMask key="autoresizingMask"/> <autoresizingMask key="autoresizingMask"/>
<color key="tintColor" red="0.74117647060000003" green="0.76470588240000004" blue="0.78039215689999997" alpha="1" colorSpace="custom" customColorSpace="sRGB"/> <color key="tintColor" red="0.68773996829986572" green="0.71417498588562012" blue="0.73246318101882935" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
<color key="barTintColor" red="0.17254901959999999" green="0.24313725489999999" blue="0.31372549020000001" alpha="1" colorSpace="custom" customColorSpace="sRGB"/> <color key="barTintColor" red="0.13079629838466644" green="0.184075728058815" blue="0.24594299495220184" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
<textAttributes key="titleTextAttributes"> <textAttributes key="titleTextAttributes">
<fontDescription key="fontDescription" name="HelveticaNeue-Thin" family="Helvetica Neue" pointSize="20"/> <fontDescription key="fontDescription" name="HelveticaNeue-Thin" family="Helvetica Neue" pointSize="20"/>
<color key="textColor" red="0.74117647060000003" green="0.76470588240000004" blue="0.78039215689999997" alpha="1" colorSpace="custom" customColorSpace="sRGB"/> <color key="textColor" red="0.68773996829986572" green="0.71417498588562012" blue="0.73246318101882935" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
</textAttributes> </textAttributes>
</navigationBar> </navigationBar>
<nil name="viewControllers"/> <nil name="viewControllers"/>
@@ -805,19 +791,19 @@
<viewControllerLayoutGuide type="bottom" id="RZg-hi-T8O"/> <viewControllerLayoutGuide type="bottom" id="RZg-hi-T8O"/>
</layoutGuides> </layoutGuides>
<view key="view" contentMode="scaleToFill" id="k4s-iL-Krh"> <view key="view" contentMode="scaleToFill" id="k4s-iL-Krh">
<rect key="frame" x="0.0" y="64" width="600" height="536"/> <rect key="frame" x="0.0" y="0.0" width="375" height="603"/>
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/> <autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
<subviews> <subviews>
<mapView clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="scaleToFill" mapType="standard" translatesAutoresizingMaskIntoConstraints="NO" id="V2U-0R-Ts0"> <mapView verifyAmbiguity="ignoreSizes" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="scaleToFill" mapType="standard" translatesAutoresizingMaskIntoConstraints="NO" id="V2U-0R-Ts0">
<rect key="frame" x="0.0" y="0.0" width="600" height="536"/> <rect key="frame" x="0.0" y="0.0" width="375" height="603"/>
<connections> <connections>
<outlet property="delegate" destination="jPl-fH-NlD" id="Sjn-YC-haS"/> <outlet property="delegate" destination="jPl-fH-NlD" id="Sjn-YC-haS"/>
</connections> </connections>
</mapView> </mapView>
</subviews> </subviews>
<color key="backgroundColor" white="1" alpha="1" colorSpace="calibratedWhite"/> <color key="backgroundColor" red="1" green="1" blue="1" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
<constraints> <constraints>
<constraint firstItem="RZg-hi-T8O" firstAttribute="top" secondItem="V2U-0R-Ts0" secondAttribute="bottom" id="GcS-Jz-Wcm"/> <constraint firstItem="RZg-hi-T8O" firstAttribute="top" secondItem="V2U-0R-Ts0" secondAttribute="bottom" id="N9r-9J-68d"/>
<constraint firstItem="V2U-0R-Ts0" firstAttribute="top" secondItem="k4s-iL-Krh" secondAttribute="top" id="S5Z-Da-V6J"/> <constraint firstItem="V2U-0R-Ts0" firstAttribute="top" secondItem="k4s-iL-Krh" secondAttribute="top" id="S5Z-Da-V6J"/>
<constraint firstAttribute="trailing" secondItem="V2U-0R-Ts0" secondAttribute="trailing" id="YPc-RK-5ib"/> <constraint firstAttribute="trailing" secondItem="V2U-0R-Ts0" secondAttribute="trailing" id="YPc-RK-5ib"/>
<constraint firstItem="V2U-0R-Ts0" firstAttribute="leading" secondItem="k4s-iL-Krh" secondAttribute="leading" id="hk5-Rz-FyU"/> <constraint firstItem="V2U-0R-Ts0" firstAttribute="leading" secondItem="k4s-iL-Krh" secondAttribute="leading" id="hk5-Rz-FyU"/>
@@ -831,7 +817,7 @@
</viewController> </viewController>
<placeholder placeholderIdentifier="IBFirstResponder" id="YnG-TD-zxQ" userLabel="First Responder" sceneMemberID="firstResponder"/> <placeholder placeholderIdentifier="IBFirstResponder" id="YnG-TD-zxQ" userLabel="First Responder" sceneMemberID="firstResponder"/>
</objects> </objects>
<point key="canvasLocation" x="3694" y="2020"/> <point key="canvasLocation" x="3693.5" y="2019.5"/>
</scene> </scene>
<!--Logger--> <!--Logger-->
<scene sceneID="n7W-0g-bbY"> <scene sceneID="n7W-0g-bbY">
@@ -842,30 +828,30 @@
<viewControllerLayoutGuide type="bottom" id="Cwn-Jd-4Lr"/> <viewControllerLayoutGuide type="bottom" id="Cwn-Jd-4Lr"/>
</layoutGuides> </layoutGuides>
<view key="view" contentMode="scaleToFill" id="n9M-Je-Dj0"> <view key="view" contentMode="scaleToFill" id="n9M-Je-Dj0">
<rect key="frame" x="0.0" y="0.0" width="600" height="600"/> <rect key="frame" x="0.0" y="0.0" width="375" height="667"/>
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/> <autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
<subviews> <subviews>
<textView clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="scaleToFill" directionalLockEnabled="YES" alwaysBounceVertical="YES" indicatorStyle="white" editable="NO" translatesAutoresizingMaskIntoConstraints="NO" id="TpK-gX-CTN"> <textView clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="scaleToFill" directionalLockEnabled="YES" alwaysBounceVertical="YES" indicatorStyle="white" editable="NO" translatesAutoresizingMaskIntoConstraints="NO" id="TpK-gX-CTN">
<rect key="frame" x="0.0" y="142" width="600" height="458"/> <rect key="frame" x="0.0" y="142" width="375" height="525"/>
<color key="backgroundColor" red="0.20392156862745098" green="0.28627450980392155" blue="0.36862745098039218" alpha="1" colorSpace="custom" customColorSpace="sRGB"/> <color key="backgroundColor" red="0.15542715787887573" green="0.2203737199306488" blue="0.2959403395652771" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
<color key="textColor" red="0.94509803921568625" green="0.7686274509803922" blue="0.058823529411764705" alpha="1" colorSpace="custom" customColorSpace="sRGB"/> <color key="textColor" red="0.92706394195556641" green="0.72759377956390381" blue="0.064024783670902252" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
<fontDescription key="fontDescription" name="AppleSDGothicNeo-Regular" family="Apple SD Gothic Neo" pointSize="15"/> <fontDescription key="fontDescription" name="AppleSDGothicNeo-Regular" family="Apple SD Gothic Neo" pointSize="15"/>
<textInputTraits key="textInputTraits" autocapitalizationType="sentences"/> <textInputTraits key="textInputTraits" autocapitalizationType="sentences"/>
</textView> </textView>
<segmentedControl opaque="NO" contentMode="scaleToFill" contentHorizontalAlignment="left" contentVerticalAlignment="top" segmentControlStyle="bordered" momentary="YES" translatesAutoresizingMaskIntoConstraints="NO" id="4iq-B4-k0p"> <segmentedControl opaque="NO" contentMode="scaleToFill" contentHorizontalAlignment="left" contentVerticalAlignment="top" segmentControlStyle="bordered" momentary="YES" translatesAutoresizingMaskIntoConstraints="NO" id="4iq-B4-k0p">
<rect key="frame" x="20" y="94" width="560" height="29"/> <rect key="frame" x="20" y="94" width="335" height="29"/>
<segments> <segments>
<segment title="Log"/> <segment title="Log"/>
<segment title="Error"/> <segment title="Error"/>
<segment title="Assert"/> <segment title="Assert"/>
</segments> </segments>
<color key="tintColor" red="0.20392156859999999" green="0.28627450980000002" blue="0.36862745099999999" alpha="1" colorSpace="custom" customColorSpace="sRGB"/> <color key="tintColor" red="0.15542715787887573" green="0.2203737199306488" blue="0.2959403395652771" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
<connections> <connections>
<action selector="segmentedControlValueChanged:" destination="5yy-0N-QDU" eventType="valueChanged" id="2pp-Vt-2Os"/> <action selector="segmentedControlValueChanged:" destination="5yy-0N-QDU" eventType="valueChanged" id="2pp-Vt-2Os"/>
</connections> </connections>
</segmentedControl> </segmentedControl>
</subviews> </subviews>
<color key="backgroundColor" white="1" alpha="1" colorSpace="calibratedWhite"/> <color key="backgroundColor" red="1" green="1" blue="1" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
<constraints> <constraints>
<constraint firstItem="4iq-B4-k0p" firstAttribute="leading" secondItem="n9M-Je-Dj0" secondAttribute="leading" constant="20" id="6SM-eN-NxP"/> <constraint firstItem="4iq-B4-k0p" firstAttribute="leading" secondItem="n9M-Je-Dj0" secondAttribute="leading" constant="20" id="6SM-eN-NxP"/>
<constraint firstItem="TpK-gX-CTN" firstAttribute="leading" secondItem="n9M-Je-Dj0" secondAttribute="leading" id="AAw-IG-taz"/> <constraint firstItem="TpK-gX-CTN" firstAttribute="leading" secondItem="n9M-Je-Dj0" secondAttribute="leading" id="AAw-IG-taz"/>
@@ -899,13 +885,13 @@
<extendedEdge key="edgesForExtendedLayout" bottom="YES"/> <extendedEdge key="edgesForExtendedLayout" bottom="YES"/>
<toolbarItems/> <toolbarItems/>
<navigationBar key="navigationBar" contentMode="scaleToFill" id="wJo-mp-1pS"> <navigationBar key="navigationBar" contentMode="scaleToFill" id="wJo-mp-1pS">
<rect key="frame" x="0.0" y="0.0" width="320" height="44"/> <rect key="frame" x="0.0" y="0.0" width="375" height="44"/>
<autoresizingMask key="autoresizingMask"/> <autoresizingMask key="autoresizingMask"/>
<color key="tintColor" red="0.74117647058823533" green="0.76470588235294112" blue="0.7803921568627451" alpha="1" colorSpace="custom" customColorSpace="sRGB"/> <color key="tintColor" red="0.68773996829986572" green="0.71417498588562012" blue="0.73246318101882935" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
<color key="barTintColor" red="0.17254901960784313" green="0.24313725490196078" blue="0.31372549019607843" alpha="1" colorSpace="custom" customColorSpace="sRGB"/> <color key="barTintColor" red="0.13079629838466644" green="0.184075728058815" blue="0.24594299495220184" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
<textAttributes key="titleTextAttributes"> <textAttributes key="titleTextAttributes">
<fontDescription key="fontDescription" name="HelveticaNeue-Thin" family="Helvetica Neue" pointSize="20"/> <fontDescription key="fontDescription" name="HelveticaNeue-Thin" family="Helvetica Neue" pointSize="20"/>
<color key="textColor" red="0.74117647060000003" green="0.76470588240000004" blue="0.78039215689999997" alpha="1" colorSpace="custom" customColorSpace="sRGB"/> <color key="textColor" red="0.68773996829986572" green="0.71417498588562012" blue="0.73246318101882935" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
</textAttributes> </textAttributes>
</navigationBar> </navigationBar>
<nil name="viewControllers"/> <nil name="viewControllers"/>
@@ -926,30 +912,30 @@
<viewControllerLayoutGuide type="bottom" id="DlN-cN-JXd"/> <viewControllerLayoutGuide type="bottom" id="DlN-cN-JXd"/>
</layoutGuides> </layoutGuides>
<view key="view" contentMode="scaleToFill" id="eC3-ql-d2o"> <view key="view" contentMode="scaleToFill" id="eC3-ql-d2o">
<rect key="frame" x="0.0" y="0.0" width="600" height="600"/> <rect key="frame" x="0.0" y="0.0" width="375" height="667"/>
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/> <autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
<subviews> <subviews>
<tableView clipsSubviews="YES" contentMode="scaleToFill" alwaysBounceVertical="YES" dataMode="prototypes" style="plain" separatorStyle="default" rowHeight="44" sectionHeaderHeight="22" sectionFooterHeight="22" translatesAutoresizingMaskIntoConstraints="NO" id="WGY-kX-mAx"> <tableView clipsSubviews="YES" contentMode="scaleToFill" alwaysBounceVertical="YES" dataMode="prototypes" style="plain" separatorStyle="default" rowHeight="44" sectionHeaderHeight="22" sectionFooterHeight="22" translatesAutoresizingMaskIntoConstraints="NO" id="WGY-kX-mAx">
<rect key="frame" x="0.0" y="64" width="600" height="536"/> <rect key="frame" x="0.0" y="64" width="375" height="603"/>
<color key="backgroundColor" red="0.20392156859999999" green="0.28627450980000002" blue="0.36862745099999999" alpha="1" colorSpace="custom" customColorSpace="sRGB"/> <color key="backgroundColor" red="0.15542715787887573" green="0.2203737199306488" blue="0.2959403395652771" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
<color key="separatorColor" red="0.20392156859999999" green="0.28627450980000002" blue="0.36862745099999999" alpha="1" colorSpace="custom" customColorSpace="sRGB"/> <color key="separatorColor" red="0.15542715787887573" green="0.2203737199306488" blue="0.2959403395652771" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
<view key="tableHeaderView" contentMode="scaleToFill" id="iaH-1W-Sbo"> <view key="tableHeaderView" contentMode="scaleToFill" id="iaH-1W-Sbo">
<rect key="frame" x="0.0" y="0.0" width="600" height="80"/> <rect key="frame" x="0.0" y="0.0" width="375" height="80"/>
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMaxY="YES"/> <autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMaxY="YES"/>
<subviews> <subviews>
<segmentedControl opaque="NO" contentMode="scaleToFill" contentHorizontalAlignment="left" contentVerticalAlignment="top" segmentControlStyle="bordered" selectedSegmentIndex="0" translatesAutoresizingMaskIntoConstraints="NO" id="YVj-dA-fyV"> <segmentedControl opaque="NO" contentMode="scaleToFill" contentHorizontalAlignment="left" contentVerticalAlignment="top" segmentControlStyle="bordered" selectedSegmentIndex="0" translatesAutoresizingMaskIntoConstraints="NO" id="YVj-dA-fyV">
<rect key="frame" x="20" y="26" width="560" height="29"/> <rect key="frame" x="20" y="26" width="335" height="29"/>
<segments> <segments>
<segment title="Fetch"/> <segment title="Fetch"/>
<segment title="Query"/> <segment title="Query"/>
</segments> </segments>
<color key="tintColor" red="0.20392156859999999" green="0.28627450980000002" blue="0.36862745099999999" alpha="1" colorSpace="custom" customColorSpace="sRGB"/> <color key="tintColor" red="0.15542715787887573" green="0.2203737199306488" blue="0.2959403395652771" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
<connections> <connections>
<action selector="segmentedControlValueChanged:" destination="qbj-MK-nIY" eventType="valueChanged" id="Wok-dl-uq7"/> <action selector="segmentedControlValueChanged:" destination="qbj-MK-nIY" eventType="valueChanged" id="Wok-dl-uq7"/>
</connections> </connections>
</segmentedControl> </segmentedControl>
</subviews> </subviews>
<color key="backgroundColor" white="1" alpha="0.80000000000000004" colorSpace="calibratedWhite"/> <color key="backgroundColor" red="1" green="1" blue="1" alpha="0.80000000000000004" colorSpace="custom" customColorSpace="sRGB"/>
<constraints> <constraints>
<constraint firstItem="YVj-dA-fyV" firstAttribute="leading" secondItem="iaH-1W-Sbo" secondAttribute="leading" constant="20" id="1dX-t7-dyR"/> <constraint firstItem="YVj-dA-fyV" firstAttribute="leading" secondItem="iaH-1W-Sbo" secondAttribute="leading" constant="20" id="1dX-t7-dyR"/>
<constraint firstAttribute="centerY" secondItem="YVj-dA-fyV" secondAttribute="centerY" id="HXU-Z7-jfu"/> <constraint firstAttribute="centerY" secondItem="YVj-dA-fyV" secondAttribute="centerY" id="HXU-Z7-jfu"/>
@@ -958,17 +944,17 @@
</view> </view>
<prototypes> <prototypes>
<tableViewCell contentMode="scaleToFill" selectionStyle="default" accessoryType="disclosureIndicator" indentationWidth="10" reuseIdentifier="UITableViewCell" textLabel="6db-P0-6Ms" style="IBUITableViewCellStyleDefault" id="vUr-WV-qur"> <tableViewCell contentMode="scaleToFill" selectionStyle="default" accessoryType="disclosureIndicator" indentationWidth="10" reuseIdentifier="UITableViewCell" textLabel="6db-P0-6Ms" style="IBUITableViewCellStyleDefault" id="vUr-WV-qur">
<rect key="frame" x="0.0" y="102" width="600" height="44"/> <rect key="frame" x="0.0" y="102" width="375" height="44"/>
<autoresizingMask key="autoresizingMask"/> <autoresizingMask key="autoresizingMask"/>
<tableViewCellContentView key="contentView" opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center" tableViewCell="vUr-WV-qur" id="Vr0-hE-cn9"> <tableViewCellContentView key="contentView" opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center" tableViewCell="vUr-WV-qur" id="Vr0-hE-cn9">
<rect key="frame" x="0.0" y="0.0" width="567" height="43.5"/> <rect key="frame" x="0.0" y="0.0" width="342" height="43.5"/>
<autoresizingMask key="autoresizingMask"/> <autoresizingMask key="autoresizingMask"/>
<subviews> <subviews>
<label opaque="NO" multipleTouchEnabled="YES" contentMode="left" text="Title" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" id="6db-P0-6Ms"> <label opaque="NO" multipleTouchEnabled="YES" contentMode="left" text="Title" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" id="6db-P0-6Ms">
<rect key="frame" x="15" y="0.0" width="550" height="43.5"/> <rect key="frame" x="15" y="0.0" width="325" height="43.5"/>
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMaxY="YES"/> <autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMaxY="YES"/>
<fontDescription key="fontDescription" name="HelveticaNeue-Light" family="Helvetica Neue" pointSize="18"/> <fontDescription key="fontDescription" name="HelveticaNeue-Light" family="Helvetica Neue" pointSize="18"/>
<color key="textColor" red="0.17254901959999999" green="0.24313725489999999" blue="0.31372549020000001" alpha="1" colorSpace="custom" customColorSpace="sRGB"/> <color key="textColor" red="0.13079629838466644" green="0.184075728058815" blue="0.24594299495220184" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
<nil key="highlightedColor"/> <nil key="highlightedColor"/>
</label> </label>
</subviews> </subviews>
@@ -981,7 +967,7 @@
</connections> </connections>
</tableView> </tableView>
</subviews> </subviews>
<color key="backgroundColor" white="1" alpha="1" colorSpace="calibratedWhite"/> <color key="backgroundColor" red="1" green="1" blue="1" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
<constraints> <constraints>
<constraint firstItem="WGY-kX-mAx" firstAttribute="top" secondItem="dgu-PC-LiB" secondAttribute="bottom" id="0pS-cU-ibk"/> <constraint firstItem="WGY-kX-mAx" firstAttribute="top" secondItem="dgu-PC-LiB" secondAttribute="bottom" id="0pS-cU-ibk"/>
<constraint firstAttribute="trailing" secondItem="WGY-kX-mAx" secondAttribute="trailing" id="NeY-g5-CaB"/> <constraint firstAttribute="trailing" secondItem="WGY-kX-mAx" secondAttribute="trailing" id="NeY-g5-CaB"/>
@@ -1006,30 +992,30 @@
<objects> <objects>
<tableViewController id="tIs-pN-OgO" customClass="FetchingResultsViewController" customModule="CoreStoreDemo" customModuleProvider="target" sceneMemberID="viewController"> <tableViewController id="tIs-pN-OgO" customClass="FetchingResultsViewController" customModule="CoreStoreDemo" customModuleProvider="target" sceneMemberID="viewController">
<tableView key="view" clipsSubviews="YES" contentMode="scaleToFill" alwaysBounceVertical="YES" dataMode="prototypes" style="plain" separatorStyle="default" rowHeight="60" sectionHeaderHeight="36" sectionFooterHeight="22" id="tVl-tT-UDk"> <tableView key="view" clipsSubviews="YES" contentMode="scaleToFill" alwaysBounceVertical="YES" dataMode="prototypes" style="plain" separatorStyle="default" rowHeight="60" sectionHeaderHeight="36" sectionFooterHeight="22" id="tVl-tT-UDk">
<rect key="frame" x="0.0" y="0.0" width="600" height="600"/> <rect key="frame" x="0.0" y="0.0" width="375" height="667"/>
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/> <autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
<color key="backgroundColor" red="0.20392156859999999" green="0.28627450980000002" blue="0.36862745099999999" alpha="1" colorSpace="custom" customColorSpace="sRGB"/> <color key="backgroundColor" red="0.15542715787887573" green="0.2203737199306488" blue="0.2959403395652771" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
<color key="separatorColor" red="0.20392156859999999" green="0.28627450980000002" blue="0.36862745099999999" alpha="1" colorSpace="custom" customColorSpace="sRGB"/> <color key="separatorColor" red="0.15542715787887573" green="0.2203737199306488" blue="0.2959403395652771" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
<prototypes> <prototypes>
<tableViewCell contentMode="scaleToFill" selectionStyle="none" indentationWidth="10" reuseIdentifier="UITableViewCell" textLabel="RgX-yK-1L2" detailTextLabel="QZ4-A2-x4h" style="IBUITableViewCellStyleSubtitle" id="uBt-Iy-nWP"> <tableViewCell contentMode="scaleToFill" selectionStyle="none" indentationWidth="10" reuseIdentifier="UITableViewCell" textLabel="RgX-yK-1L2" detailTextLabel="QZ4-A2-x4h" style="IBUITableViewCellStyleSubtitle" id="uBt-Iy-nWP">
<rect key="frame" x="0.0" y="100" width="600" height="60"/> <rect key="frame" x="0.0" y="36" width="375" height="60"/>
<autoresizingMask key="autoresizingMask"/> <autoresizingMask key="autoresizingMask"/>
<tableViewCellContentView key="contentView" opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center" tableViewCell="uBt-Iy-nWP" id="6SD-ur-9zp"> <tableViewCellContentView key="contentView" opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center" tableViewCell="uBt-Iy-nWP" id="6SD-ur-9zp">
<rect key="frame" x="0.0" y="0.0" width="600" height="59.5"/> <rect key="frame" x="0.0" y="0.0" width="375" height="59.5"/>
<autoresizingMask key="autoresizingMask"/> <autoresizingMask key="autoresizingMask"/>
<subviews> <subviews>
<label opaque="NO" multipleTouchEnabled="YES" contentMode="left" text="name" lineBreakMode="wordWrap" numberOfLines="0" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" id="RgX-yK-1L2"> <label opaque="NO" multipleTouchEnabled="YES" contentMode="left" text="name" lineBreakMode="wordWrap" numberOfLines="0" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" id="RgX-yK-1L2">
<rect key="frame" x="15" y="11" width="48.5" height="24"/> <rect key="frame" x="16" y="11" width="48.5" height="24"/>
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMaxY="YES"/> <autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMaxY="YES"/>
<fontDescription key="fontDescription" name="HelveticaNeue-Light" family="Helvetica Neue" pointSize="20"/> <fontDescription key="fontDescription" name="HelveticaNeue-Light" family="Helvetica Neue" pointSize="20"/>
<color key="textColor" red="0.17254901959999999" green="0.24313725489999999" blue="0.31372549020000001" alpha="1" colorSpace="custom" customColorSpace="sRGB"/> <color key="textColor" red="0.13079629838466644" green="0.184075728058815" blue="0.24594299495220184" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
<nil key="highlightedColor"/> <nil key="highlightedColor"/>
</label> </label>
<label opaque="NO" multipleTouchEnabled="YES" contentMode="left" text="offset" lineBreakMode="wordWrap" numberOfLines="0" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" id="QZ4-A2-x4h"> <label opaque="NO" multipleTouchEnabled="YES" contentMode="left" text="offset" lineBreakMode="wordWrap" numberOfLines="0" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" id="QZ4-A2-x4h">
<rect key="frame" x="15" y="35" width="31" height="13.5"/> <rect key="frame" x="16" y="35" width="31" height="13.5"/>
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMaxY="YES"/> <autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMaxY="YES"/>
<fontDescription key="fontDescription" type="system" pointSize="11"/> <fontDescription key="fontDescription" type="system" pointSize="11"/>
<color key="textColor" red="0.17254901959999999" green="0.24313725489999999" blue="0.31372549020000001" alpha="1" colorSpace="custom" customColorSpace="sRGB"/> <color key="textColor" red="0.13079629838466644" green="0.184075728058815" blue="0.24594299495220184" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
<nil key="highlightedColor"/> <nil key="highlightedColor"/>
</label> </label>
</subviews> </subviews>
@@ -1052,30 +1038,30 @@
<objects> <objects>
<tableViewController id="o9D-Xm-13g" customClass="QueryingResultsViewController" customModule="CoreStoreDemo" customModuleProvider="target" sceneMemberID="viewController"> <tableViewController id="o9D-Xm-13g" customClass="QueryingResultsViewController" customModule="CoreStoreDemo" customModuleProvider="target" sceneMemberID="viewController">
<tableView key="view" clipsSubviews="YES" contentMode="scaleToFill" alwaysBounceVertical="YES" dataMode="prototypes" style="plain" separatorStyle="default" rowHeight="60" sectionHeaderHeight="36" sectionFooterHeight="22" id="bMh-zR-xwu"> <tableView key="view" clipsSubviews="YES" contentMode="scaleToFill" alwaysBounceVertical="YES" dataMode="prototypes" style="plain" separatorStyle="default" rowHeight="60" sectionHeaderHeight="36" sectionFooterHeight="22" id="bMh-zR-xwu">
<rect key="frame" x="0.0" y="0.0" width="600" height="600"/> <rect key="frame" x="0.0" y="0.0" width="375" height="667"/>
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/> <autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
<color key="backgroundColor" red="0.20392156859999999" green="0.28627450980000002" blue="0.36862745099999999" alpha="1" colorSpace="custom" customColorSpace="sRGB"/> <color key="backgroundColor" red="0.15542715787887573" green="0.2203737199306488" blue="0.2959403395652771" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
<color key="separatorColor" red="0.20392156859999999" green="0.28627450980000002" blue="0.36862745099999999" alpha="1" colorSpace="custom" customColorSpace="sRGB"/> <color key="separatorColor" red="0.15542715787887573" green="0.2203737199306488" blue="0.2959403395652771" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
<prototypes> <prototypes>
<tableViewCell contentMode="scaleToFill" selectionStyle="none" indentationWidth="10" reuseIdentifier="UITableViewCell" textLabel="Syt-QJ-KXg" detailTextLabel="yHS-dP-IKS" style="IBUITableViewCellStyleSubtitle" id="q7Q-aF-Ftl"> <tableViewCell contentMode="scaleToFill" selectionStyle="none" indentationWidth="10" reuseIdentifier="UITableViewCell" textLabel="Syt-QJ-KXg" detailTextLabel="yHS-dP-IKS" style="IBUITableViewCellStyleSubtitle" id="q7Q-aF-Ftl">
<rect key="frame" x="0.0" y="100" width="600" height="60"/> <rect key="frame" x="0.0" y="36" width="375" height="60"/>
<autoresizingMask key="autoresizingMask"/> <autoresizingMask key="autoresizingMask"/>
<tableViewCellContentView key="contentView" opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center" tableViewCell="q7Q-aF-Ftl" id="fc3-eg-yes"> <tableViewCellContentView key="contentView" opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center" tableViewCell="q7Q-aF-Ftl" id="fc3-eg-yes">
<rect key="frame" x="0.0" y="0.0" width="600" height="59.5"/> <rect key="frame" x="0.0" y="0.0" width="375" height="59.5"/>
<autoresizingMask key="autoresizingMask"/> <autoresizingMask key="autoresizingMask"/>
<subviews> <subviews>
<label opaque="NO" multipleTouchEnabled="YES" contentMode="left" text="name" lineBreakMode="wordWrap" numberOfLines="0" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" id="Syt-QJ-KXg"> <label opaque="NO" multipleTouchEnabled="YES" contentMode="left" text="name" lineBreakMode="wordWrap" numberOfLines="0" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" id="Syt-QJ-KXg">
<rect key="frame" x="15" y="11" width="48.5" height="24"/> <rect key="frame" x="16" y="11" width="48.5" height="24"/>
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMaxY="YES"/> <autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMaxY="YES"/>
<fontDescription key="fontDescription" name="HelveticaNeue-Light" family="Helvetica Neue" pointSize="20"/> <fontDescription key="fontDescription" name="HelveticaNeue-Light" family="Helvetica Neue" pointSize="20"/>
<color key="textColor" red="0.17254901959999999" green="0.24313725489999999" blue="0.31372549020000001" alpha="1" colorSpace="custom" customColorSpace="sRGB"/> <color key="textColor" red="0.13079629838466644" green="0.184075728058815" blue="0.24594299495220184" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
<nil key="highlightedColor"/> <nil key="highlightedColor"/>
</label> </label>
<label opaque="NO" multipleTouchEnabled="YES" contentMode="left" text="offset" lineBreakMode="wordWrap" numberOfLines="0" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" id="yHS-dP-IKS"> <label opaque="NO" multipleTouchEnabled="YES" contentMode="left" text="offset" lineBreakMode="wordWrap" numberOfLines="0" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" id="yHS-dP-IKS">
<rect key="frame" x="15" y="35" width="31" height="13.5"/> <rect key="frame" x="16" y="35" width="31" height="13.5"/>
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMaxY="YES"/> <autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMaxY="YES"/>
<fontDescription key="fontDescription" type="system" pointSize="11"/> <fontDescription key="fontDescription" type="system" pointSize="11"/>
<color key="textColor" red="0.17254901959999999" green="0.24313725489999999" blue="0.31372549020000001" alpha="1" colorSpace="custom" customColorSpace="sRGB"/> <color key="textColor" red="0.13079629838466644" green="0.184075728058815" blue="0.24594299495220184" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
<nil key="highlightedColor"/> <nil key="highlightedColor"/>
</label> </label>
</subviews> </subviews>

View File

@@ -1,36 +1,25 @@
<?xml version="1.0" encoding="UTF-8" standalone="yes"?> <?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"> <model type="com.apple.IDECoreDataModeler.DataModel" documentVersion="1.0" lastSavedToolsVersion="12141" systemVersion="16F73" minimumToolsVersion="Xcode 7.3" sourceLanguage="Objective-C" userDefinedModelVersionIdentifier="">
<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"> <entity name="Place" representedClassName="CoreStoreDemo.Place" syncable="YES">
<attribute name="latitude" optional="YES" attributeType="Double" defaultValueString="0.0" syncable="YES"/> <attribute name="latitude" optional="YES" attributeType="Double" defaultValueString="0.0" usesScalarValueType="NO" syncable="YES"/>
<attribute name="longitude" optional="YES" attributeType="Double" defaultValueString="0.0" syncable="YES"/> <attribute name="longitude" optional="YES" attributeType="Double" defaultValueString="0.0" usesScalarValueType="NO" syncable="YES"/>
<attribute name="subtitle" optional="YES" attributeType="String" syncable="YES"/> <attribute name="subtitle" optional="YES" attributeType="String" syncable="YES"/>
<attribute name="title" optional="YES" attributeType="String" syncable="YES"/> <attribute name="title" optional="YES" attributeType="String" syncable="YES"/>
</entity> </entity>
<entity name="TimeZone" representedClassName="CoreStoreDemo.TimeZone" syncable="YES"> <entity name="TimeZone" representedClassName="CoreStoreDemo.TimeZone" syncable="YES">
<attribute name="abbreviation" optional="YES" attributeType="String" 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="daylightSavingTimeOffset" optional="YES" attributeType="Double" defaultValueString="0.0" usesScalarValueType="NO" syncable="YES"/>
<attribute name="hasDaylightSavingTime" optional="YES" attributeType="Boolean" syncable="YES"/> <attribute name="hasDaylightSavingTime" optional="YES" attributeType="Boolean" usesScalarValueType="NO" syncable="YES"/>
<attribute name="name" optional="YES" attributeType="String" syncable="YES"/> <attribute name="name" optional="YES" attributeType="String" syncable="YES"/>
<attribute name="secondsFromGMT" optional="YES" attributeType="Integer 32" defaultValueString="0.0" syncable="YES"/> <attribute name="secondsFromGMT" optional="YES" attributeType="Integer 32" defaultValueString="0.0" usesScalarValueType="NO" syncable="YES"/>
</entity> </entity>
<configuration name="FetchingAndQueryingDemo"> <configuration name="FetchingAndQueryingDemo">
<memberEntity name="TimeZone"/> <memberEntity name="TimeZone"/>
</configuration> </configuration>
<configuration name="ObservingDemo">
<memberEntity name="Palette"/>
</configuration>
<configuration name="TransactionsDemo"> <configuration name="TransactionsDemo">
<memberEntity name="Place"/> <memberEntity name="Place"/>
</configuration> </configuration>
<elements> <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="Place" positionX="261" positionY="225" width="128" height="105"/>
<element name="TimeZone" positionX="297" positionY="270" width="128" height="120"/> <element name="TimeZone" positionX="297" positionY="270" width="128" height="120"/>
</elements> </elements>

View File

@@ -3,7 +3,7 @@
// CoreStoreDemo // CoreStoreDemo
// //
// Created by John Rommel Estropia on 2015/06/12. // Created by John Rommel Estropia on 2015/06/12.
// Copyright © 2015 John Rommel Estropia. All rights reserved. // Copyright © 2018 John Rommel Estropia. All rights reserved.
// //
import UIKit import UIKit
@@ -19,29 +19,27 @@ private struct Static {
SQLiteStore( SQLiteStore(
fileName: "TimeZoneDemo.sqlite", fileName: "TimeZoneDemo.sqlite",
configuration: "FetchingAndQueryingDemo", configuration: "FetchingAndQueryingDemo",
localStorageOptions: .RecreateStoreOnModelMismatch localStorageOptions: .recreateStoreOnModelMismatch
) )
) )
_ = try? dataStack.perform(
dataStack.beginSynchronous { (transaction) -> Void in synchronous: { (transaction) in
transaction.deleteAll(From(TimeZone))
for name in NSTimeZone.knownTimeZoneNames() {
let rawTimeZone = NSTimeZone(name: name)! try transaction.deleteAll(From<TimeZone>())
let cachedTimeZone = transaction.create(Into(TimeZone))
cachedTimeZone.name = rawTimeZone.name for name in NSTimeZone.knownTimeZoneNames {
cachedTimeZone.abbreviation = rawTimeZone.abbreviation ?? ""
cachedTimeZone.secondsFromGMT = Int32(rawTimeZone.secondsFromGMT) let rawTimeZone = NSTimeZone(name: name)!
cachedTimeZone.hasDaylightSavingTime = rawTimeZone.daylightSavingTime let cachedTimeZone = transaction.create(Into<TimeZone>())
cachedTimeZone.daylightSavingTimeOffset = rawTimeZone.daylightSavingTimeOffset
cachedTimeZone.name = rawTimeZone.name
cachedTimeZone.abbreviation = rawTimeZone.abbreviation ?? ""
cachedTimeZone.secondsFromGMT = Int32(rawTimeZone.secondsFromGMT)
cachedTimeZone.hasDaylightSavingTime = rawTimeZone.isDaylightSavingTime
cachedTimeZone.daylightSavingTimeOffset = rawTimeZone.daylightSavingTimeOffset
}
} }
)
transaction.commitAndWait()
}
return dataStack return dataStack
}() }()
} }
@@ -53,7 +51,7 @@ class FetchingAndQueryingDemoViewController: UIViewController, UITableViewDataSo
// MARK: UIViewController // MARK: UIViewController
override func viewDidAppear(animated: Bool) { override func viewDidAppear(_ animated: Bool) {
super.viewDidAppear(animated) super.viewDidAppear(animated)
@@ -67,27 +65,27 @@ class FetchingAndQueryingDemoViewController: UIViewController, UITableViewDataSo
let alert = UIAlertController( let alert = UIAlertController(
title: "Fetch and Query Demo", 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.", message: "This demo shows how to execute fetches and queries.\n\nEach menu item executes and displays a preconfigured fetch/query.",
preferredStyle: .Alert preferredStyle: .alert
) )
alert.addAction(UIAlertAction(title: "OK", style: .Cancel, handler: nil)) alert.addAction(UIAlertAction(title: "OK", style: .cancel, handler: nil))
self.presentViewController(alert, animated: true, completion: nil) self.present(alert, animated: true, completion: nil)
} }
override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) { override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
super.prepareForSegue(segue, sender: sender) super.prepare(for: segue, sender: sender)
if let indexPath = sender as? NSIndexPath { if let indexPath = sender as? IndexPath {
switch segue.destinationViewController { switch segue.destination {
case let controller as FetchingResultsViewController: case let controller as FetchingResultsViewController:
let item = self.fetchingItems[indexPath.row] let item = self.fetchingItems[indexPath.row]
controller.setTimeZones(item.fetch(), title: item.title) controller.set(timeZones: item.fetch(), title: item.title)
case let controller as QueryingResultsViewController: case let controller as QueryingResultsViewController:
let item = self.queryingItems[indexPath.row] let item = self.queryingItems[indexPath.row]
controller.setValue(item.query(), title: item.title) controller.set(value: item.query(), title: item.title)
default: default:
break break
@@ -98,14 +96,14 @@ class FetchingAndQueryingDemoViewController: UIViewController, UITableViewDataSo
// MARK: UITableViewDataSource // MARK: UITableViewDataSource
func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int { func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
switch self.segmentedControl?.selectedSegmentIndex { switch self.segmentedControl?.selectedSegmentIndex {
case Section.Fetching.rawValue?: case Section.fetching.rawValue?:
return self.fetchingItems.count return self.fetchingItems.count
case Section.Querying.rawValue?: case Section.querying.rawValue?:
return self.queryingItems.count return self.queryingItems.count
default: default:
@@ -113,16 +111,16 @@ class FetchingAndQueryingDemoViewController: UIViewController, UITableViewDataSo
} }
} }
func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell { func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCellWithIdentifier("UITableViewCell")! let cell = tableView.dequeueReusableCell(withIdentifier: "UITableViewCell")!
switch self.segmentedControl?.selectedSegmentIndex { switch self.segmentedControl?.selectedSegmentIndex {
case Section.Fetching.rawValue?: case Section.fetching.rawValue?:
cell.textLabel?.text = self.fetchingItems[indexPath.row].title cell.textLabel?.text = self.fetchingItems[indexPath.row].title
case Section.Querying.rawValue?: case Section.querying.rawValue?:
cell.textLabel?.text = self.queryingItems[indexPath.row].title cell.textLabel?.text = self.queryingItems[indexPath.row].title
default: default:
@@ -135,17 +133,17 @@ class FetchingAndQueryingDemoViewController: UIViewController, UITableViewDataSo
// MARK: UITableViewDelegate // MARK: UITableViewDelegate
func tableView(tableView: UITableView, didSelectRowAtIndexPath indexPath: NSIndexPath) { func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
tableView.deselectRowAtIndexPath(indexPath, animated: true) tableView.deselectRow(at: indexPath, animated: true)
switch self.segmentedControl?.selectedSegmentIndex { switch self.segmentedControl?.selectedSegmentIndex {
case Section.Fetching.rawValue?: case Section.fetching.rawValue?:
self.performSegueWithIdentifier("FetchingResultsViewController", sender: indexPath) self.performSegue(withIdentifier: "FetchingResultsViewController", sender: indexPath)
case Section.Querying.rawValue?: case Section.querying.rawValue?:
self.performSegueWithIdentifier("QueryingResultsViewController", sender: indexPath) self.performSegue(withIdentifier: "QueryingResultsViewController", sender: indexPath)
default: default:
break break
@@ -157,8 +155,8 @@ class FetchingAndQueryingDemoViewController: UIViewController, UITableViewDataSo
private enum Section: Int { private enum Section: Int {
case Fetching case fetching
case Querying case querying
} }
private let fetchingItems = [ private let fetchingItems = [
@@ -166,117 +164,145 @@ class FetchingAndQueryingDemoViewController: UIViewController, UITableViewDataSo
title: "All Time Zones", title: "All Time Zones",
fetch: { () -> [TimeZone] in fetch: { () -> [TimeZone] in
return Static.timeZonesStack.fetchAll( return try! Static.timeZonesStack.fetchAll(
From(TimeZone), From<TimeZone>()
OrderBy(.Ascending("name")) .orderBy(.ascending(\.name))
)! )
} }
), ),
( (
title: "Time Zones in Asia", title: "Time Zones in Asia",
fetch: { () -> [TimeZone] in fetch: { () -> [TimeZone] in
return Static.timeZonesStack.fetchAll( return try! Static.timeZonesStack.fetchAll(
From(TimeZone), From<TimeZone>()
Where("%K BEGINSWITH[c] %@", "name", "Asia"), .where(
OrderBy(.Ascending("secondsFromGMT")) format: "%K BEGINSWITH[c] %@",
)! #keyPath(TimeZone.name),
"Asia"
)
.orderBy(.ascending(\.secondsFromGMT))
)
} }
), ),
( (
title: "Time Zones in America and Europe", title: "Time Zones in America and Europe",
fetch: { () -> [TimeZone] in fetch: { () -> [TimeZone] in
return Static.timeZonesStack.fetchAll( return try! Static.timeZonesStack.fetchAll(
From(TimeZone), From<TimeZone>()
Where("%K BEGINSWITH[c] %@", "name", "America") .where(
|| Where("%K BEGINSWITH[c] %@", "name", "Europe"), format: "%K BEGINSWITH[c] %@ OR %K BEGINSWITH[c] %@",
OrderBy(.Ascending("secondsFromGMT")) #keyPath(TimeZone.name),
)! "America",
#keyPath(TimeZone.name),
"Europe"
)
.orderBy(.ascending(\.secondsFromGMT))
)
} }
), ),
( (
title: "All Time Zones Except America", title: "All Time Zones Except America",
fetch: { () -> [TimeZone] in fetch: { () -> [TimeZone] in
return Static.timeZonesStack.fetchAll( return try! Static.timeZonesStack.fetchAll(
From(TimeZone), From<TimeZone>()
!Where("%K BEGINSWITH[c] %@", "name", "America"), .where(
OrderBy(.Ascending("secondsFromGMT")) format: "%K BEGINSWITH[c] %@",
)! #keyPath(TimeZone.name),
"America"
)
.orderBy(.ascending(\.secondsFromGMT))
)
} }
), ),
( (
title: "Time Zones with Summer Time", title: "Time Zones with Summer Time",
fetch: { () -> [TimeZone] in fetch: { () -> [TimeZone] in
return Static.timeZonesStack.fetchAll( return try! Static.timeZonesStack.fetchAll(
From(TimeZone), From<TimeZone>()
Where("hasDaylightSavingTime", isEqualTo: true), .where(\.hasDaylightSavingTime == true)
OrderBy(.Ascending("name")) .orderBy(.ascending(\.name))
)! )
} }
) )
] ]
private let queryingItems = [ private let queryingItems: [(title: String, query: () -> Any)] = [
( (
title: "Number of Time Zones", title: "Number of Time Zones",
query: { () -> AnyObject in query: { () -> Any in
return Static.timeZonesStack.queryValue( return try! Static.timeZonesStack.queryValue(
From(TimeZone), From<TimeZone>()
Select<NSNumber>(.Count("name")) .select(NSNumber.self, .count(\.name))
)! )!
} }
), ),
( (
title: "Abbreviation For Tokyo's Time Zone", title: "Abbreviation For Tokyo's Time Zone",
query: { () -> AnyObject in query: { () -> Any in
return Static.timeZonesStack.queryValue( return try! Static.timeZonesStack.queryValue(
From(TimeZone), From<TimeZone>()
Select<String>("abbreviation"), .select(String.self, .attribute(\.abbreviation))
Where("%K ENDSWITH[c] %@", "name", "Tokyo") .where(format: "%K ENDSWITH[c] %@", #keyPath(TimeZone.name), "Tokyo")
)! )!
} }
), ),
( (
title: "All Abbreviations", title: "All Abbreviations",
query: { () -> AnyObject in query: { () -> Any in
return Static.timeZonesStack.queryAttributes( return try! Static.timeZonesStack.queryAttributes(
From(TimeZone), From<TimeZone>()
Select<NSDictionary>("name", "abbreviation"), .select(
OrderBy(.Ascending("name")) NSDictionary.self,
)! .attribute(\.name),
.attribute(\.abbreviation)
)
.orderBy(.ascending(\.name))
)
} }
), ),
( (
title: "Number of Countries per Time Zone", title: "Number of Countries per Time Zone",
query: { () -> AnyObject in query: { () -> Any in
return Static.timeZonesStack.queryAttributes( return try! Static.timeZonesStack.queryAttributes(
From(TimeZone), From<TimeZone>()
Select<NSDictionary>(.Count("abbreviation"), "abbreviation"), .select(
GroupBy("abbreviation"), NSDictionary.self,
OrderBy(.Ascending("secondsFromGMT"), .Ascending("name")) .count(\.abbreviation),
)! .attribute(\.abbreviation)
)
.groupBy(\.abbreviation)
.orderBy(
.ascending(\.secondsFromGMT),
.ascending(\.name)
)
)
} }
), ),
( (
title: "Number of Countries with Summer Time", title: "Number of Countries with Summer Time",
query: { () -> AnyObject in query: { () -> Any in
return Static.timeZonesStack.queryAttributes( return try! Static.timeZonesStack.queryAttributes(
From(TimeZone), From<TimeZone>()
Select<NSDictionary>( .select(
.Count("hasDaylightSavingTime", As: "numberOfCountries"), NSDictionary.self,
"hasDaylightSavingTime" .count(\.hasDaylightSavingTime, as: "numberOfCountries"),
), .attribute(\.hasDaylightSavingTime)
GroupBy("hasDaylightSavingTime"), )
OrderBy(.Descending("hasDaylightSavingTime")) .groupBy(\.hasDaylightSavingTime)
)! .orderBy(
.descending(\.hasDaylightSavingTime),
.ascending(\.name)
)
)
} }
) )
] ]
@@ -286,7 +312,7 @@ class FetchingAndQueryingDemoViewController: UIViewController, UITableViewDataSo
@IBOutlet dynamic weak var segmentedControl: UISegmentedControl? @IBOutlet dynamic weak var segmentedControl: UISegmentedControl?
@IBOutlet dynamic weak var tableView: UITableView? @IBOutlet dynamic weak var tableView: UITableView?
@IBAction dynamic func segmentedControlValueChanged(sender: AnyObject?) { @IBAction dynamic func segmentedControlValueChanged(_ sender: AnyObject?) {
self.tableView?.reloadData() self.tableView?.reloadData()
} }

View File

@@ -3,7 +3,7 @@
// CoreStoreDemo // CoreStoreDemo
// //
// Created by John Rommel Estropia on 2015/06/17. // Created by John Rommel Estropia on 2015/06/17.
// Copyright © 2015 John Rommel Estropia. All rights reserved. // Copyright © 2018 John Rommel Estropia. All rights reserved.
// //
import UIKit import UIKit
@@ -14,7 +14,7 @@ class FetchingResultsViewController: UITableViewController {
// MARK: Public // MARK: Public
func setTimeZones(timeZones: [TimeZone]?, title: String) { func set(timeZones: [TimeZone]?, title: String) {
self.timeZones += timeZones ?? [] self.timeZones += timeZones ?? []
self.sectionTitle = title self.sectionTitle = title
@@ -36,14 +36,14 @@ class FetchingResultsViewController: UITableViewController {
// MARK: UITableViewDataSource // MARK: UITableViewDataSource
override func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int { override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return self.timeZones.count return self.timeZones.count
} }
override func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell { override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCellWithIdentifier("UITableViewCell", forIndexPath: indexPath) let cell = tableView.dequeueReusableCell(withIdentifier: "UITableViewCell", for: indexPath)
let timeZone = self.timeZones[indexPath.row] let timeZone = self.timeZones[indexPath.row]
cell.textLabel?.text = timeZone.name cell.textLabel?.text = timeZone.name
@@ -55,7 +55,7 @@ class FetchingResultsViewController: UITableViewController {
// MARK: UITableViewDelegate // MARK: UITableViewDelegate
override func tableView(tableView: UITableView, titleForHeaderInSection section: Int) -> String? { override func tableView(_ tableView: UITableView, titleForHeaderInSection section: Int) -> String? {
return self.sectionTitle return self.sectionTitle
} }

View File

@@ -3,7 +3,7 @@
// CoreStoreDemo // CoreStoreDemo
// //
// Created by John Rommel Estropia on 2015/06/17. // Created by John Rommel Estropia on 2015/06/17.
// Copyright © 2015 John Rommel Estropia. All rights reserved. // Copyright © 2018 John Rommel Estropia. All rights reserved.
// //
import UIKit import UIKit
@@ -12,23 +12,23 @@ class QueryingResultsViewController: UITableViewController {
// MARK: Public // MARK: Public
func setValue(value: AnyObject?, title: String) { func set(value: Any?, title: String) {
switch value { switch value {
case (let array as [AnyObject])?: case (let array as [Any])?:
self.values = array.map { (item: AnyObject) -> (title: String, detail: String) in self.values = array.map { (item: Any) -> (title: String, detail: String) in
( (
title: item.description, title: String(describing: item),
detail: String(reflecting: item.dynamicType) detail: String(reflecting: type(of: item))
) )
} }
case let item?: case let item?:
self.values = [ self.values = [
( (
title: item.description, title: String(describing: item),
detail: String(reflecting: item.dynamicType) detail: String(reflecting: type(of: item))
) )
] ]
@@ -55,14 +55,14 @@ class QueryingResultsViewController: UITableViewController {
// MARK: UITableViewDataSource // MARK: UITableViewDataSource
override func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int { override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return self.values.count return self.values.count
} }
override func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell { override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCellWithIdentifier("UITableViewCell", forIndexPath: indexPath) let cell = tableView.dequeueReusableCell(withIdentifier: "UITableViewCell", for: indexPath)
let value = self.values[indexPath.row] let value = self.values[indexPath.row]
@@ -75,7 +75,7 @@ class QueryingResultsViewController: UITableViewController {
// MARK: UITableViewDelegate // MARK: UITableViewDelegate
override func tableView(tableView: UITableView, titleForHeaderInSection section: Int) -> String? { override func tableView(_ tableView: UITableView, titleForHeaderInSection section: Int) -> String? {
return self.sectionTitle return self.sectionTitle
} }

View File

@@ -3,7 +3,7 @@
// CoreStoreDemo // CoreStoreDemo
// //
// Created by John Rommel Estropia on 2015/06/15. // Created by John Rommel Estropia on 2015/06/15.
// Copyright © 2015 John Rommel Estropia. All rights reserved. // Copyright © 2018 John Rommel Estropia. All rights reserved.
// //
import Foundation import Foundation

View File

@@ -1,5 +1,15 @@
{ {
"images" : [ "images" : [
{
"idiom" : "iphone",
"size" : "20x20",
"scale" : "2x"
},
{
"idiom" : "iphone",
"size" : "20x20",
"scale" : "3x"
},
{ {
"idiom" : "iphone", "idiom" : "iphone",
"size" : "29x29", "size" : "29x29",
@@ -32,6 +42,36 @@
"filename" : "Icon-60@3x-1.png", "filename" : "Icon-60@3x-1.png",
"scale" : "3x" "scale" : "3x"
}, },
{
"idiom" : "ipad",
"size" : "20x20",
"scale" : "1x"
},
{
"idiom" : "ipad",
"size" : "20x20",
"scale" : "2x"
},
{
"idiom" : "ipad",
"size" : "29x29",
"scale" : "1x"
},
{
"idiom" : "ipad",
"size" : "29x29",
"scale" : "2x"
},
{
"idiom" : "ipad",
"size" : "40x40",
"scale" : "1x"
},
{
"idiom" : "ipad",
"size" : "40x40",
"scale" : "2x"
},
{ {
"size" : "76x76", "size" : "76x76",
"idiom" : "ipad", "idiom" : "ipad",
@@ -44,6 +84,21 @@
"filename" : "Icon-76@2x.png", "filename" : "Icon-76@2x.png",
"scale" : "2x" "scale" : "2x"
}, },
{
"idiom" : "ipad",
"size" : "83.5x83.5",
"scale" : "2x"
},
{
"idiom" : "ios-marketing",
"size" : "1024x1024",
"scale" : "1x"
},
{
"idiom" : "car",
"size" : "60x60",
"scale" : "2x"
},
{ {
"size" : "60x60", "size" : "60x60",
"idiom" : "car", "idiom" : "car",

View File

@@ -17,11 +17,11 @@
<key>CFBundlePackageType</key> <key>CFBundlePackageType</key>
<string>APPL</string> <string>APPL</string>
<key>CFBundleShortVersionString</key> <key>CFBundleShortVersionString</key>
<string>1.0.1</string> <string>5.1.0</string>
<key>CFBundleSignature</key> <key>CFBundleSignature</key>
<string>????</string> <string>????</string>
<key>CFBundleVersion</key> <key>CFBundleVersion</key>
<string>1</string> <string>4</string>
<key>LSRequiresIPhoneOS</key> <key>LSRequiresIPhoneOS</key>
<true/> <true/>
<key>UILaunchStoryboardName</key> <key>UILaunchStoryboardName</key>

View File

@@ -3,64 +3,80 @@
// CoreStoreDemo // CoreStoreDemo
// //
// Created by John Rommel Estropia on 2015/05/02. // Created by John Rommel Estropia on 2015/05/02.
// Copyright © 2015 John Rommel Estropia. All rights reserved. // Copyright © 2018 John Rommel Estropia. All rights reserved.
// //
import UIKit import UIKit
import CoreStore import CoreStore
private struct Static { struct ColorsDemo {
enum Filter: String { enum Filter: String {
case All = "All Colors" case all = "All Colors"
case Light = "Light Colors" case light = "Light Colors"
case Dark = "Dark Colors" case dark = "Dark Colors"
func next() -> Filter { func next() -> Filter {
switch self { switch self {
case All: return .Light case .all: return .light
case Light: return .Dark case .light: return .dark
case Dark: return .All case .dark: return .all
} }
} }
func whereClause() -> Where { func whereClause() -> Where<Palette> {
switch self { switch self {
case .All: return Where(true) case .all: return .init()
case .Light: return Where("brightness >= 0.9") case .light: return (\Palette.brightness >= 0.9)
case .Dark: return Where("brightness <= 0.4") case .dark: return (\Palette.brightness <= 0.4)
} }
} }
} }
static var filter = Filter.All { static var filter = Filter.all {
didSet { didSet {
self.palettes.refetch(self.filter.whereClause()) self.palettes.refetch(
self.filter.whereClause(),
OrderBy<Palette>(.ascending(\.hue))
)
} }
} }
static let palettes: ListMonitor<Palette> = { static let stack: DataStack = {
try! CoreStore.addStorageAndWait( return DataStack(
SQLiteStore( CoreStoreSchema(
fileName: "ColorsDemo.sqlite", modelVersion: "ColorsDemo",
configuration: "ObservingDemo", entities: [
localStorageOptions: .RecreateStoreOnModelMismatch Entity<Palette>("Palette"),
],
versionLock: [
"Palette": [0x8c25aa53c7c90a28, 0xa243a34d25f1a3a7, 0x56565b6935b6055a, 0x4f988bb257bf274f]
]
) )
) )
}()
static let palettes: ListMonitor<Palette> = {
return CoreStore.monitorSectionedList( try! ColorsDemo.stack.addStorageAndWait(
From(Palette), SQLiteStore(
SectionBy("colorName"), fileName: "ColorsDemo.sqlite",
OrderBy(.Ascending("hue")) localStorageOptions: .recreateStoreOnModelMismatch
)
)
return ColorsDemo.stack.monitorSectionedList(
From<Palette>()
.sectionBy(\.colorName)
.orderBy(.ascending(\.hue))
) )
}() }()
} }
@@ -74,7 +90,7 @@ class ListObserverDemoViewController: UITableViewController, ListSectionObserver
deinit { deinit {
Static.palettes.removeObserver(self) ColorsDemo.palettes.removeObserver(self)
} }
@@ -86,40 +102,45 @@ class ListObserverDemoViewController: UITableViewController, ListSectionObserver
let navigationItem = self.navigationItem let navigationItem = self.navigationItem
navigationItem.leftBarButtonItems = [ navigationItem.leftBarButtonItems = [
self.editButtonItem(), self.editButtonItem,
UIBarButtonItem( UIBarButtonItem(
barButtonSystemItem: .Trash, barButtonSystemItem: .trash,
target: self, target: self,
action: #selector(self.resetBarButtonItemTouched(_:)) action: #selector(self.resetBarButtonItemTouched(_:))
) )
] ]
let filterBarButton = UIBarButtonItem( let filterBarButton = UIBarButtonItem(
title: Static.filter.rawValue, title: ColorsDemo.filter.rawValue,
style: .Plain, style: .plain,
target: self, target: self,
action: #selector(self.filterBarButtonItemTouched(_:)) action: #selector(self.filterBarButtonItemTouched(_:))
) )
navigationItem.rightBarButtonItems = [ navigationItem.rightBarButtonItems = [
UIBarButtonItem( UIBarButtonItem(
barButtonSystemItem: .Add, barButtonSystemItem: .add,
target: self, target: self,
action: #selector(self.addBarButtonItemTouched(_:)) action: #selector(self.addBarButtonItemTouched(_:))
), ),
UIBarButtonItem(
barButtonSystemItem: .refresh,
target: self,
action: #selector(self.shuffleBarButtonItemTouched(_:))
),
filterBarButton filterBarButton
] ]
self.filterBarButton = filterBarButton self.filterBarButton = filterBarButton
Static.palettes.addObserver(self) ColorsDemo.palettes.addObserver(self)
self.setTableEnabled(!Static.palettes.isPendingRefetch) self.setTable(enabled: !ColorsDemo.palettes.isPendingRefetch)
} }
override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) { override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
super.prepareForSegue(segue, sender: sender) super.prepare(for: segue, sender: sender)
switch (segue.identifier, segue.destinationViewController, sender) { switch (segue.identifier, segue.destination, sender) {
case ("ObjectObserverDemoViewController"?, let destinationViewController as ObjectObserverDemoViewController, let palette as Palette): case ("ObjectObserverDemoViewController"?, let destinationViewController as ObjectObserverDemoViewController, let palette as Palette):
destinationViewController.palette = palette destinationViewController.palette = palette
@@ -132,21 +153,21 @@ class ListObserverDemoViewController: UITableViewController, ListSectionObserver
// MARK: UITableViewDataSource // MARK: UITableViewDataSource
override func numberOfSectionsInTableView(tableView: UITableView) -> Int { override func numberOfSections(in tableView: UITableView) -> Int {
return Static.palettes.numberOfSections() return ColorsDemo.palettes.numberOfSections()
} }
override func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int { override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return Static.palettes.numberOfObjectsInSection(section) return ColorsDemo.palettes.numberOfObjects(in: section)
} }
override func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell { override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCellWithIdentifier("PaletteTableViewCell") as! PaletteTableViewCell let cell = tableView.dequeueReusableCell(withIdentifier: "PaletteTableViewCell") as! PaletteTableViewCell
let palette = Static.palettes[indexPath] let palette = ColorsDemo.palettes[indexPath]
cell.colorView?.backgroundColor = palette.color cell.colorView?.backgroundColor = palette.color
cell.label?.text = palette.colorText cell.label?.text = palette.colorText
@@ -156,103 +177,105 @@ class ListObserverDemoViewController: UITableViewController, ListSectionObserver
// MARK: UITableViewDelegate // MARK: UITableViewDelegate
override func tableView(tableView: UITableView, didSelectRowAtIndexPath indexPath: NSIndexPath) { override func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
tableView.deselectRowAtIndexPath(indexPath, animated: true) tableView.deselectRow(at: indexPath, animated: true)
self.performSegueWithIdentifier( self.performSegue(
"ObjectObserverDemoViewController", withIdentifier: "ObjectObserverDemoViewController",
sender: Static.palettes[indexPath] sender: ColorsDemo.palettes[indexPath]
) )
} }
override func tableView(tableView: UITableView, commitEditingStyle editingStyle: UITableViewCellEditingStyle, forRowAtIndexPath indexPath: NSIndexPath) { override func tableView(_ tableView: UITableView, commit editingStyle: UITableViewCellEditingStyle, forRowAt indexPath: IndexPath) {
switch editingStyle { switch editingStyle {
case .Delete: case .delete:
let palette = Static.palettes[indexPath] let palette = ColorsDemo.palettes[indexPath]
CoreStore.beginAsynchronous{ (transaction) -> Void in ColorsDemo.stack.perform(
asynchronous: { (transaction) in
transaction.delete(palette)
transaction.commit { (result) -> Void in } transaction.delete(palette)
} },
completion: { _ in }
)
default: default:
break break
} }
} }
override func tableView(tableView: UITableView, titleForHeaderInSection section: Int) -> String? { override func tableView(_ tableView: UITableView, titleForHeaderInSection section: Int) -> String? {
return Static.palettes.sectionInfoAtIndex(section).name return ColorsDemo.palettes.sectionInfo(at: section).name
} }
// MARK: ListObserver // MARK: ListObserver
func listMonitorWillChange(monitor: ListMonitor<Palette>) { func listMonitorWillChange(_ monitor: ListMonitor<Palette>) {
self.tableView.beginUpdates() self.tableView.beginUpdates()
} }
func listMonitorDidChange(monitor: ListMonitor<Palette>) { func listMonitorDidChange(_ monitor: ListMonitor<Palette>) {
self.tableView.endUpdates() self.tableView.endUpdates()
} }
func listMonitorWillRefetch(monitor: ListMonitor<Palette>) { func listMonitorWillRefetch(_ monitor: ListMonitor<Palette>) {
self.setTableEnabled(false) self.setTable(enabled: false)
} }
func listMonitorDidRefetch(monitor: ListMonitor<Palette>) { func listMonitorDidRefetch(_ monitor: ListMonitor<Palette>) {
self.filterBarButton?.title = Static.filter.rawValue self.filterBarButton?.title = ColorsDemo.filter.rawValue
self.tableView.reloadData() self.tableView.reloadData()
self.setTableEnabled(true) self.setTable(enabled: true)
} }
// MARK: ListObjectObserver // MARK: ListObjectObserver
func listMonitor(monitor: ListMonitor<Palette>, didInsertObject object: Palette, toIndexPath indexPath: NSIndexPath) { func listMonitor(_ monitor: ListMonitor<Palette>, didInsertObject object: Palette, toIndexPath indexPath: IndexPath) {
self.tableView.insertRowsAtIndexPaths([indexPath], withRowAnimation: .Automatic) self.tableView.insertRows(at: [indexPath], with: .automatic)
} }
func listMonitor(monitor: ListMonitor<Palette>, didDeleteObject object: Palette, fromIndexPath indexPath: NSIndexPath) { func listMonitor(_ monitor: ListMonitor<Palette>, didDeleteObject object: Palette, fromIndexPath indexPath: IndexPath) {
self.tableView.deleteRowsAtIndexPaths([indexPath], withRowAnimation: .Automatic) self.tableView.deleteRows(at: [indexPath], with: .automatic)
} }
func listMonitor(monitor: ListMonitor<Palette>, didUpdateObject object: Palette, atIndexPath indexPath: NSIndexPath) { func listMonitor(_ monitor: ListMonitor<Palette>, didUpdateObject object: Palette, atIndexPath indexPath: IndexPath) {
if let cell = self.tableView.cellForRowAtIndexPath(indexPath) as? PaletteTableViewCell { if let cell = self.tableView.cellForRow(at: indexPath) as? PaletteTableViewCell {
let palette = Static.palettes[indexPath] let palette = ColorsDemo.palettes[indexPath]
cell.colorView?.backgroundColor = palette.color cell.colorView?.backgroundColor = palette.color
cell.label?.text = palette.colorText cell.label?.text = palette.colorText
} }
} }
func listMonitor(monitor: ListMonitor<Palette>, didMoveObject object: Palette, fromIndexPath: NSIndexPath, toIndexPath: NSIndexPath) { func listMonitor(_ monitor: ListMonitor<Palette>, didMoveObject object: Palette, fromIndexPath: IndexPath, toIndexPath: IndexPath) {
self.tableView.deleteRowsAtIndexPaths([fromIndexPath], withRowAnimation: .Automatic) self.tableView.deleteRows(at: [fromIndexPath], with: .automatic)
self.tableView.insertRowsAtIndexPaths([toIndexPath], withRowAnimation: .Automatic) self.tableView.insertRows(at: [toIndexPath], with: .automatic)
} }
// MARK: ListSectionObserver // MARK: ListSectionObserver
func listMonitor(monitor: ListMonitor<Palette>, didInsertSection sectionInfo: NSFetchedResultsSectionInfo, toSectionIndex sectionIndex: Int) { func listMonitor(_ monitor: ListMonitor<Palette>, didInsertSection sectionInfo: NSFetchedResultsSectionInfo, toSectionIndex sectionIndex: Int) {
self.tableView.insertSections(NSIndexSet(index: sectionIndex), withRowAnimation: .Automatic) self.tableView.insertSections(IndexSet(integer: sectionIndex), with: .automatic)
} }
func listMonitor(monitor: ListMonitor<Palette>, didDeleteSection sectionInfo: NSFetchedResultsSectionInfo, fromSectionIndex sectionIndex: Int) { func listMonitor(_ monitor: ListMonitor<Palette>, didDeleteSection sectionInfo: NSFetchedResultsSectionInfo, fromSectionIndex sectionIndex: Int) {
self.tableView.deleteSections(NSIndexSet(index: sectionIndex), withRowAnimation: .Automatic) self.tableView.deleteSections(IndexSet(integer: sectionIndex), with: .automatic)
} }
@@ -260,43 +283,61 @@ class ListObserverDemoViewController: UITableViewController, ListSectionObserver
private var filterBarButton: UIBarButtonItem? private var filterBarButton: UIBarButtonItem?
@IBAction private dynamic func resetBarButtonItemTouched(sender: AnyObject?) { @IBAction private dynamic func resetBarButtonItemTouched(_ sender: AnyObject?) {
CoreStore.beginAsynchronous { (transaction) -> Void in ColorsDemo.stack.perform(
asynchronous: { (transaction) in
transaction.deleteAll(From(Palette))
transaction.commit() try transaction.deleteAll(From<Palette>())
} },
completion: { _ in }
)
} }
@IBAction private dynamic func filterBarButtonItemTouched(sender: AnyObject?) { @IBAction private dynamic func filterBarButtonItemTouched(_ sender: AnyObject?) {
Static.filter = Static.filter.next() ColorsDemo.filter = ColorsDemo.filter.next()
} }
@IBAction private dynamic func addBarButtonItemTouched(sender: AnyObject?) { @IBAction private dynamic func addBarButtonItemTouched(_ sender: AnyObject?) {
CoreStore.beginAsynchronous { (transaction) -> Void in ColorsDemo.stack.perform(
asynchronous: { (transaction) in
let palette = transaction.create(Into(Palette))
palette.setInitialValues() let palette = transaction.create(Into<Palette>())
palette.setInitialValues(in: transaction)
transaction.commit() },
} completion: { _ in }
)
}
@IBAction private dynamic func shuffleBarButtonItemTouched(_ sender: AnyObject?) {
ColorsDemo.stack.perform(
asynchronous: { (transaction) in
for palette in try transaction.fetchAll(From<Palette>()) {
palette.hue .= Palette.randomHue()
palette.colorName .= nil
}
},
completion: { _ in }
)
} }
private func setTableEnabled(enabled: Bool) { private func setTable(enabled: Bool) {
UIView.animateWithDuration( UIView.animate(
0.2, withDuration: 0.2,
delay: 0, delay: 0,
options: .BeginFromCurrentState, options: .beginFromCurrentState,
animations: { () -> Void in animations: { () -> Void in
if let tableView = self.tableView { if let tableView = self.tableView {
tableView.alpha = enabled ? 1.0 : 0.5 tableView.alpha = enabled ? 1.0 : 0.5
tableView.userInteractionEnabled = enabled tableView.isUserInteractionEnabled = enabled
} }
}, },
completion: nil completion: nil

View File

@@ -3,7 +3,7 @@
// CoreStoreDemo // CoreStoreDemo
// //
// Created by John Rommel Estropia on 2015/05/06. // Created by John Rommel Estropia on 2015/05/06.
// Copyright © 2015 John Rommel Estropia. All rights reserved. // Copyright © 2018 John Rommel Estropia. All rights reserved.
// //
import UIKit import UIKit
@@ -29,7 +29,7 @@ class ObjectObserverDemoViewController: UIViewController, ObjectObserver {
if let palette = newValue { if let palette = newValue {
self.monitor = CoreStore.monitorObject(palette) self.monitor = ColorsDemo.stack.monitorObject(palette)
} }
else { else {
@@ -50,22 +50,22 @@ class ObjectObserverDemoViewController: UIViewController, ObjectObserver {
required init?(coder aDecoder: NSCoder) { required init?(coder aDecoder: NSCoder) {
if let palette = CoreStore.fetchOne(From(Palette), OrderBy(.Ascending("hue"))) { if let palette = try! ColorsDemo.stack.fetchOne(From<Palette>().orderBy(.ascending(\.hue))) {
self.monitor = CoreStore.monitorObject(palette) self.monitor = ColorsDemo.stack.monitorObject(palette)
} }
else { else {
CoreStore.beginSynchronous { (transaction) -> Void in _ = try? ColorsDemo.stack.perform(
synchronous: { (transaction) in
let palette = transaction.create(Into(Palette))
palette.setInitialValues() let palette = transaction.create(Into<Palette>())
palette.setInitialValues(in: transaction)
transaction.commitAndWait() }
} )
let palette = CoreStore.fetchOne(From(Palette), OrderBy(.Ascending("hue")))! let palette = try! ColorsDemo.stack.fetchOne(From<Palette>().orderBy(.ascending(\.hue)))!
self.monitor = CoreStore.monitorObject(palette) self.monitor = ColorsDemo.stack.monitorObject(palette)
} }
super.init(coder: aDecoder) super.init(coder: aDecoder)
@@ -85,24 +85,24 @@ class ObjectObserverDemoViewController: UIViewController, ObjectObserver {
// MARK: ObjectObserver // MARK: ObjectObserver
func objectMonitor(monitor: ObjectMonitor<Palette>, didUpdateObject object: Palette, changedPersistentKeys: Set<KeyPath>) { func objectMonitor(_ monitor: ObjectMonitor<Palette>, didUpdateObject object: Palette, changedPersistentKeys: Set<KeyPathString>) {
self.reloadPaletteInfo(object, changedKeys: changedPersistentKeys) self.reloadPaletteInfo(object, changedKeys: changedPersistentKeys)
} }
func objectMonitor(monitor: ObjectMonitor<Palette>, didDeleteObject object: Palette) { func objectMonitor(_ monitor: ObjectMonitor<Palette>, didDeleteObject object: Palette) {
self.navigationItem.rightBarButtonItem?.enabled = false self.navigationItem.rightBarButtonItem?.isEnabled = false
self.colorNameLabel?.alpha = 0.3 self.colorNameLabel?.alpha = 0.3
self.colorView?.alpha = 0.3 self.colorView?.alpha = 0.3
self.hsbLabel?.text = "Deleted" self.hsbLabel?.text = "Deleted"
self.hsbLabel?.textColor = UIColor.redColor() self.hsbLabel?.textColor = UIColor.red
self.hueSlider?.enabled = false self.hueSlider?.isEnabled = false
self.saturationSlider?.enabled = false self.saturationSlider?.isEnabled = false
self.brightnessSlider?.enabled = false self.brightnessSlider?.isEnabled = false
} }
@@ -118,57 +118,65 @@ class ObjectObserverDemoViewController: UIViewController, ObjectObserver {
@IBOutlet weak var saturationSlider: UISlider? @IBOutlet weak var saturationSlider: UISlider?
@IBOutlet weak var brightnessSlider: UISlider? @IBOutlet weak var brightnessSlider: UISlider?
@IBAction dynamic func hueSliderValueDidChange(sender: AnyObject?) { @IBAction dynamic func hueSliderValueDidChange(_ sender: AnyObject?) {
let hue = self.hueSlider?.value ?? 0 let hue = self.hueSlider?.value ?? 0
CoreStore.beginAsynchronous { [weak self] (transaction) -> Void in ColorsDemo.stack.perform(
asynchronous: { [weak self] (transaction) in
if let palette = transaction.edit(self?.monitor?.object) {
palette.hue = Int32(hue) if let palette = transaction.edit(self?.monitor?.object) {
transaction.commit()
} palette.hue .= Int(hue)
} }
},
completion: { _ in }
)
} }
@IBAction dynamic func saturationSliderValueDidChange(sender: AnyObject?) { @IBAction dynamic func saturationSliderValueDidChange(_ sender: AnyObject?) {
let saturation = self.saturationSlider?.value ?? 0 let saturation = self.saturationSlider?.value ?? 0
CoreStore.beginAsynchronous { [weak self] (transaction) -> Void in ColorsDemo.stack.perform(
asynchronous: { [weak self] (transaction) in
if let palette = transaction.edit(self?.monitor?.object) {
palette.saturation = saturation if let palette = transaction.edit(self?.monitor?.object) {
transaction.commit()
} palette.saturation .= saturation
} }
},
completion: { _ in }
)
} }
@IBAction dynamic func brightnessSliderValueDidChange(sender: AnyObject?) { @IBAction dynamic func brightnessSliderValueDidChange(_ sender: AnyObject?) {
let brightness = self.brightnessSlider?.value ?? 0 let brightness = self.brightnessSlider?.value ?? 0
CoreStore.beginAsynchronous { [weak self] (transaction) -> Void in ColorsDemo.stack.perform(
asynchronous: { [weak self] (transaction) in
if let palette = transaction.edit(self?.monitor?.object) {
palette.brightness = brightness if let palette = transaction.edit(self?.monitor?.object) {
transaction.commit()
} palette.brightness .= brightness
} }
},
completion: { _ in }
)
} }
@IBAction dynamic func deleteBarButtonTapped(sender: AnyObject?) { @IBAction dynamic func deleteBarButtonTapped(_ sender: AnyObject?) {
CoreStore.beginAsynchronous { [weak self] (transaction) -> Void in ColorsDemo.stack.perform(
asynchronous: { [weak self] (transaction) in
transaction.delete(self?.monitor?.object)
transaction.commit() transaction.delete(self?.monitor?.object)
} },
completion: { _ in }
)
} }
func reloadPaletteInfo(palette: Palette, changedKeys: Set<String>?) { func reloadPaletteInfo(_ palette: Palette, changedKeys: Set<String>?) {
self.colorNameLabel?.text = palette.colorName self.colorNameLabel?.text = palette.colorName.value
let color = palette.color let color = palette.color
self.colorNameLabel?.textColor = color self.colorNameLabel?.textColor = color
@@ -176,17 +184,17 @@ class ObjectObserverDemoViewController: UIViewController, ObjectObserver {
self.hsbLabel?.text = palette.colorText self.hsbLabel?.text = palette.colorText
if changedKeys == nil || changedKeys?.contains("hue") == true { if changedKeys == nil || changedKeys?.contains(String(keyPath: \Palette.hue)) == true {
self.hueSlider?.value = Float(palette.hue) self.hueSlider?.value = Float(palette.hue.value)
} }
if changedKeys == nil || changedKeys?.contains("saturation") == true { if changedKeys == nil || changedKeys?.contains(String(keyPath: \Palette.saturation)) == true {
self.saturationSlider?.value = palette.saturation self.saturationSlider?.value = palette.saturation.value
} }
if changedKeys == nil || changedKeys?.contains("brightness") == true { if changedKeys == nil || changedKeys?.contains(String(keyPath: \Palette.brightness)) == true {
self.brightnessSlider?.value = palette.brightness self.brightnessSlider?.value = palette.brightness.value
} }
} }
} }

View File

@@ -3,7 +3,7 @@
// CoreStoreDemo // CoreStoreDemo
// //
// Created by John Rommel Estropia on 2015/05/24. // Created by John Rommel Estropia on 2015/05/24.
// Copyright © 2015 John Rommel Estropia. All rights reserved. // Copyright © 2018 John Rommel Estropia. All rights reserved.
// //
import UIKit import UIKit
@@ -15,16 +15,16 @@ class ObserversViewController: UIViewController {
// MARK: UIViewController // MARK: UIViewController
override func viewDidAppear(animated: Bool) { override func viewDidAppear(_ animated: Bool) {
super.viewDidAppear(animated) super.viewDidAppear(animated)
let alert = UIAlertController( let alert = UIAlertController(
title: "Observers Demo", 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\".", 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 preferredStyle: .alert
) )
alert.addAction(UIAlertAction(title: "OK", style: .Cancel, handler: nil)) alert.addAction(UIAlertAction(title: "OK", style: .cancel, handler: nil))
self.presentViewController(alert, animated: true, completion: nil) self.present(alert, animated: true, completion: nil)
} }
} }

View File

@@ -3,7 +3,7 @@
// CoreStoreDemo // CoreStoreDemo
// //
// Created by John Rommel Estropia on 2015/05/05. // Created by John Rommel Estropia on 2015/05/05.
// Copyright © 2015 John Rommel Estropia. All rights reserved. // Copyright © 2018 John Rommel Estropia. All rights reserved.
// //
import Foundation import Foundation
@@ -14,64 +14,70 @@ import CoreStore
// MARK: - Palette // MARK: - Palette
class Palette: NSManagedObject { final class Palette: CoreStoreObject {
@NSManaged var hue: Int32
@NSManaged var saturation: Float
@NSManaged var brightness: Float
@objc dynamic var colorName: String { let hue = Value.Required<Int>("hue", initial: 0)
let saturation = Value.Required<Float>("saturation", initial: 0)
let brightness = Value.Required<Float>("brightness", initial: 0)
let colorName = Value.Optional<String>(
"colorName",
isTransient: true,
customGetter: Palette.getColorName
)
static func randomHue() -> Int {
return Int(arc4random_uniform(360))
}
private static func getColorName(_ partialObject: PartialObject<Palette>) -> String? {
get { if let colorName = partialObject.primitiveValue(for: { $0.colorName }) {
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 return colorName
} }
set {
let colorName: String
switch partialObject.value(for: { $0.hue }) % 360 {
self.setValue(newValue, forKVCKey: "colorName") 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"
} }
partialObject.setPrimitiveValue(colorName, for: { $0.colorName })
return colorName
} }
}
extension Palette {
var color: UIColor { var color: UIColor {
return UIColor( return UIColor(
hue: CGFloat(self.hue) / 360.0, hue: CGFloat(self.hue.value) / 360.0,
saturation: CGFloat(self.saturation), saturation: CGFloat(self.saturation.value),
brightness: CGFloat(self.brightness), brightness: CGFloat(self.brightness.value),
alpha: 1.0 alpha: 1.0
) )
} }
var colorText: String { var colorText: String {
return "H: \(self.hue)˚, S: \(round(self.saturation * 100.0))%, B: \(round(self.brightness * 100.0))%" return "H: \(self.hue.value)˚, S: \(round(self.saturation.value * 100.0))%, B: \(round(self.brightness.value * 100.0))%"
} }
func setInitialValues() { func setInitialValues(in transaction: BaseDataTransaction) {
self.hue = Int32(arc4random_uniform(360)) self.hue .= Palette.randomHue()
self.saturation = 1.0 self.saturation .= Float(1.0)
self.brightness = Float(arc4random_uniform(70) + 30) / 100.0 self.brightness .= Float(arc4random_uniform(70) + 30) / 100.0
} }
} }

View File

@@ -3,7 +3,7 @@
// CoreStoreDemo // CoreStoreDemo
// //
// Created by John Rommel Estropia on 2015/05/05. // Created by John Rommel Estropia on 2015/05/05.
// Copyright © 2015 John Rommel Estropia. All rights reserved. // Copyright © 2018 John Rommel Estropia. All rights reserved.
// //
import UIKit import UIKit

View File

@@ -3,12 +3,11 @@
// CoreStoreDemo // CoreStoreDemo
// //
// Created by John Rommel Estropia on 2015/06/05. // Created by John Rommel Estropia on 2015/06/05.
// Copyright © 2015 John Rommel Estropia. All rights reserved. // Copyright © 2018 John Rommel Estropia. All rights reserved.
// //
import UIKit import UIKit
import CoreStore import CoreStore
import GCDKit
// MARK: - CustomLoggerViewController // MARK: - CustomLoggerViewController
@@ -17,11 +16,6 @@ class CustomLoggerViewController: UIViewController, CoreStoreLogger {
// MARK: NSObject // MARK: NSObject
deinit {
CoreStore.logger = DefaultLogger()
}
let dataStack = DataStack() let dataStack = DataStack()
// MARK: UIViewController // MARK: UIViewController
@@ -31,50 +25,58 @@ class CustomLoggerViewController: UIViewController, CoreStoreLogger {
super.viewDidLoad() super.viewDidLoad()
try! self.dataStack.addStorageAndWait(SQLiteStore(fileName: "emptyStore.sqlite")) try! self.dataStack.addStorageAndWait(SQLiteStore(fileName: "emptyStore.sqlite"))
CoreStore.logger = self
} }
override func viewDidAppear(animated: Bool) { override func viewDidAppear(_ animated: Bool) {
super.viewDidAppear(animated) super.viewDidAppear(animated)
CoreStore.logger = self
let alert = UIAlertController( let alert = UIAlertController(
title: "Logger Demo", 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.", 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 preferredStyle: .alert
) )
alert.addAction(UIAlertAction(title: "OK", style: .Cancel, handler: nil)) alert.addAction(UIAlertAction(title: "OK", style: .cancel, handler: nil))
self.presentViewController(alert, animated: true, completion: nil) self.present(alert, animated: true, completion: nil)
}
override func viewDidDisappear(_ animated: Bool) {
super.viewDidDisappear(animated)
CoreStore.logger = DefaultLogger()
} }
// MARK: CoreStoreLogger // MARK: CoreStoreLogger
func log(level level: LogLevel, message: String, fileName: StaticString, lineNumber: Int, functionName: StaticString) { func log(level: LogLevel, message: String, fileName: StaticString, lineNumber: Int, functionName: StaticString) {
GCDQueue.Main.async { [weak self] in DispatchQueue.main.async { [weak self] in
let levelString: String let levelString: String
switch level { switch level {
case .Trace: levelString = "Trace" case .trace: levelString = "Trace"
case .Notice: levelString = "Notice" case .notice: levelString = "Notice"
case .Warning: levelString = "Warning" case .warning: levelString = "Warning"
case .Fatal: levelString = "Fatal" case .fatal: levelString = "Fatal"
} }
self?.textView?.insertText("\((fileName.stringValue as NSString).lastPathComponent):\(lineNumber) \(functionName)\n ↪︎ [Log:\(levelString)] \(message)\n\n") self?.textView?.insertText("\((String(describing: fileName) as NSString).lastPathComponent):\(lineNumber) \(functionName)\n ↪︎ [Log:\(levelString)] \(message)\n\n")
} }
} }
func log(error error: CoreStoreError, message: String, fileName: StaticString, lineNumber: Int, functionName: StaticString) { func log(error: CoreStoreError, message: String, fileName: StaticString, lineNumber: Int, functionName: StaticString) {
GCDQueue.Main.async { [weak self] in DispatchQueue.main.async { [weak self] in
self?.textView?.insertText("\((fileName.stringValue as NSString).lastPathComponent):\(lineNumber) \(functionName)\n ↪︎ [Error] \(message): \(error)\n\n") self?.textView?.insertText("\((String(describing: fileName) 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) { func assert(_ condition: @autoclosure () -> Bool, message: @autoclosure () -> String, fileName: StaticString, lineNumber: Int, functionName: StaticString) {
if condition() { if condition() {
@@ -82,9 +84,9 @@ class CustomLoggerViewController: UIViewController, CoreStoreLogger {
} }
let messageString = message() let messageString = message()
GCDQueue.Main.async { [weak self] in DispatchQueue.main.async { [weak self] in
self?.textView?.insertText("\((fileName.stringValue as NSString).lastPathComponent):\(lineNumber) \(functionName)\n ↪︎ [Assert] \(messageString)\n\n") self?.textView?.insertText("\((String(describing: fileName) as NSString).lastPathComponent):\(lineNumber) \(functionName)\n ↪︎ [Assert] \(messageString)\n\n")
} }
} }
@@ -94,15 +96,14 @@ class CustomLoggerViewController: UIViewController, CoreStoreLogger {
@IBOutlet dynamic weak var textView: UITextView? @IBOutlet dynamic weak var textView: UITextView?
@IBOutlet dynamic weak var segmentedControl: UISegmentedControl? @IBOutlet dynamic weak var segmentedControl: UISegmentedControl?
@IBAction dynamic func segmentedControlValueChanged(sender: AnyObject?) { @IBAction dynamic func segmentedControlValueChanged(_ sender: AnyObject?) {
switch self.segmentedControl?.selectedSegmentIndex { switch self.segmentedControl?.selectedSegmentIndex {
case 0?: case 0?:
self.dataStack.beginAsynchronous { (transaction) -> Void in let request = NSFetchRequest<NSFetchRequestResult>()
Where<NSManagedObject>(true).applyToFetchRequest(request)
transaction.create(Into(Palette)) Where<NSManagedObject>(false).applyToFetchRequest(request)
}
case 1?: case 1?:
_ = try? dataStack.addStorageAndWait( _ = try? dataStack.addStorageAndWait(
@@ -113,10 +114,9 @@ class CustomLoggerViewController: UIViewController, CoreStoreLogger {
) )
case 2?: case 2?:
self.dataStack.beginAsynchronous { (transaction) -> Void in DispatchQueue.global(qos: .background).async {
transaction.commit() _ = try! self.dataStack.fetchOne(From<Place>())
transaction.commit()
} }
default: default:

View File

@@ -3,7 +3,7 @@
// CoreStoreDemo // CoreStoreDemo
// //
// Created by John Rommel Estropia on 2015/06/21. // Created by John Rommel Estropia on 2015/06/21.
// Copyright © 2015 John Rommel Estropia. All rights reserved. // Copyright © 2018 John Rommel Estropia. All rights reserved.
// //
import UIKit import UIKit
@@ -12,7 +12,7 @@ import CoreStore
// MARK: - MigrationsDemoViewController // MARK: - MigrationsDemoViewController
class MigrationsDemoViewController: UIViewController { class MigrationsDemoViewController: UIViewController, ListObserver, UITableViewDataSource, UITableViewDelegate {
// MARK: UIViewController // MARK: UIViewController
@@ -22,31 +22,31 @@ class MigrationsDemoViewController: UIViewController {
if let segmentedControl = self.segmentedControl { if let segmentedControl = self.segmentedControl {
for (index, model) in self.models.enumerate() { for (index, model) in self.models.enumerated() {
segmentedControl.setTitle( segmentedControl.setTitle(
model.label, model.label,
forSegmentAtIndex: index forSegmentAt: index
) )
} }
} }
self.setDataStack(nil, model: nil, scrollToSelection: false) self.set(dataStack: nil, model: nil, scrollToSelection: false)
} }
override func viewDidAppear(animated: Bool) { override func viewDidAppear(_ animated: Bool) {
super.viewDidAppear(animated) super.viewDidAppear(animated)
let alert = UIAlertController( let alert = UIAlertController(
title: "Migrations Demo", 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.", 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 preferredStyle: .alert
) )
alert.addAction(UIAlertAction(title: "OK", style: .Cancel, handler: nil)) alert.addAction(UIAlertAction(title: "OK", style: .cancel, handler: nil))
self.presentViewController(alert, animated: true, completion: nil) self.present(alert, animated: true, completion: nil)
let modelMetadata = withExtendedLifetime(DataStack(modelName: "MigrationDemo")) { let modelMetadata = withExtendedLifetime(DataStack(xcodeModelName: "MigrationDemo")) {
(dataStack: DataStack) -> ModelMetadata in (dataStack: DataStack) -> ModelMetadata in
let models = self.models let models = self.models
@@ -60,7 +60,7 @@ class MigrationsDemoViewController: UIViewController {
} }
for model in models { for model in models {
if model.version == storeVersion { if model.schemaHistory.currentModelVersion == storeVersion {
return model return model
} }
@@ -72,32 +72,121 @@ class MigrationsDemoViewController: UIViewController {
self.selectModelVersion(modelMetadata) self.selectModelVersion(modelMetadata)
} }
// MARK: ListObserver
func listMonitorWillChange(_ monitor: ListMonitor<NSManagedObject>) { }
func listMonitorDidChange(_ monitor: ListMonitor<NSManagedObject>) {
if self.lastSelectedIndexPath == nil,
let numberOfObjectsInSection = self.listMonitor?.numberOfObjects(in: 0),
numberOfObjectsInSection > 0 {
self.tableView?.reloadData()
self.setSelectedIndexPath(IndexPath(row: 0, section: 0), scrollToSelection: false)
}
else {
self.updateDisplay(reloadData: true, scrollToSelection: true, animated: true)
}
}
func listMonitorDidRefetch(_ monitor: ListMonitor<NSManagedObject>) {
self.listMonitorDidChange(monitor)
}
// MARK: UITableViewDataSource
@objc dynamic func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return self.listMonitor?.numberOfObjects(in: 0) ?? 0
}
@objc dynamic func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "OrganismTableViewCell", for: 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.perform(
asynchronous: { (transaction) in
let organism = transaction.edit(organism) as! OrganismProtocol
organism.mutate()
},
completion: { [weak self] _ in
self?.setEnabled(true)
}
)
}
return cell
}
// MARK: UITableViewDelegate
@objc dynamic func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
self.setSelectedIndexPath(indexPath, scrollToSelection: false)
}
// MARK: Private // MARK: Private
private typealias ModelMetadata = (label: String, version: String, entityType: AnyClass, migrationChain: MigrationChain) private typealias ModelMetadata = (label: String, entityType: NSManagedObject.Type, schemaHistory: SchemaHistory)
private let models: [ModelMetadata] = [ private let models: [ModelMetadata] = [
( (
label: "Model V1", label: "Model V1",
version: "MigrationDemo",
entityType: OrganismV1.self, entityType: OrganismV1.self,
migrationChain: ["MigrationDemoV3", "MigrationDemoV2", "MigrationDemo"] schemaHistory: SchemaHistory(
XcodeDataModelSchema.from(
modelName: "MigrationDemo",
migrationChain: ["MigrationDemoV3", "MigrationDemoV2", "MigrationDemo"]
),
migrationChain: ["MigrationDemoV3", "MigrationDemoV2", "MigrationDemo"]
)
), ),
( (
label: "Model V2", label: "Model V2",
version: "MigrationDemoV2",
entityType: OrganismV2.self, entityType: OrganismV2.self,
migrationChain: [ schemaHistory: SchemaHistory(
"MigrationDemo": "MigrationDemoV2", XcodeDataModelSchema.from(
"MigrationDemoV3": "MigrationDemoV2" modelName: "MigrationDemo",
] migrationChain: [
"MigrationDemo": "MigrationDemoV2",
"MigrationDemoV3": "MigrationDemoV2"
]
),
migrationChain: [
"MigrationDemo": "MigrationDemoV2",
"MigrationDemoV3": "MigrationDemoV2"
]
)
), ),
( (
label: "Model V3", label: "Model V3",
version: "MigrationDemoV3",
entityType: OrganismV3.self, entityType: OrganismV3.self,
migrationChain: ["MigrationDemo", "MigrationDemoV2", "MigrationDemoV3"] schemaHistory: SchemaHistory(
XcodeDataModelSchema.from(
modelName: "MigrationDemo",
migrationChain: ["MigrationDemo", "MigrationDemoV2", "MigrationDemoV3"]
),
migrationChain: ["MigrationDemo", "MigrationDemoV2", "MigrationDemoV3"]
)
) )
] ]
@@ -113,13 +202,13 @@ class MigrationsDemoViewController: UIViewController {
return self._dataStack return self._dataStack
} }
private var _lastSelectedIndexPath: NSIndexPath? private var _lastSelectedIndexPath: IndexPath?
private var lastSelectedIndexPath: NSIndexPath? { private var lastSelectedIndexPath: IndexPath? {
return self._lastSelectedIndexPath return self._lastSelectedIndexPath
} }
private func setSelectedIndexPath(indexPath: NSIndexPath, scrollToSelection: Bool) { private func setSelectedIndexPath(_ indexPath: IndexPath, scrollToSelection: Bool) {
self._lastSelectedIndexPath = indexPath self._lastSelectedIndexPath = indexPath
self.updateDisplay(reloadData: false, scrollToSelection: scrollToSelection, animated: true) self.updateDisplay(reloadData: false, scrollToSelection: scrollToSelection, animated: true)
@@ -132,7 +221,7 @@ class MigrationsDemoViewController: UIViewController {
@IBOutlet private dynamic weak var progressView: UIProgressView? @IBOutlet private dynamic weak var progressView: UIProgressView?
@IBOutlet private dynamic weak var tableView: UITableView? @IBOutlet private dynamic weak var tableView: UITableView?
@IBAction private dynamic func segmentedControlValueChanged(sender: AnyObject?) { @IBAction private dynamic func segmentedControlValueChanged(_ sender: AnyObject?) {
guard let index = self.segmentedControl?.selectedSegmentIndex else { guard let index = self.segmentedControl?.selectedSegmentIndex else {
@@ -142,23 +231,46 @@ class MigrationsDemoViewController: UIViewController {
self.selectModelVersion(self.models[index]) self.selectModelVersion(self.models[index])
} }
private func selectModelVersion(model: ModelMetadata) { private func selectModelVersion(_ model: ModelMetadata) {
if self.dataStack?.modelVersion == model.version { if self.dataStack?.modelVersion == model.schemaHistory.currentModelVersion {
return return
} }
self.setDataStack(nil, model: nil, scrollToSelection: false) // explicitly trigger NSPersistentStore cleanup by deallocating the stack self.set(dataStack: nil, model: nil, scrollToSelection: false) // explicitly trigger NSPersistentStore cleanup by deallocating the stack
let dataStack = DataStack( let dataStack = DataStack(schemaHistory: model.schemaHistory)
modelName: "MigrationDemo",
migrationChain: model.migrationChain
)
self.setEnabled(false) self.setEnabled(false)
let progress = dataStack.addStorage( let progress = dataStack.addStorage(
SQLiteStore(fileName: "MigrationDemo.sqlite"), SQLiteStore(
fileName: "MigrationDemo.sqlite",
migrationMappingProviders: [
CustomSchemaMappingProvider(
from: "MigrationDemoV3",
to: "MigrationDemoV2",
entityMappings: [
.transformEntity(
sourceEntity: "Organism",
destinationEntity: "Organism",
transformer: { (source, createDestination) in
let destination = createDestination()
destination.enumerateAttributes { (attribute, sourceAttribute) in
if let sourceAttribute = sourceAttribute {
destination[attribute] = source[sourceAttribute]
}
}
destination["numberOfFlippers"] = source["numberOfLimbs"]
}
)
]
)
]
),
completion: { [weak self] (result) -> Void in completion: { [weak self] (result) -> Void in
guard let `self` = self else { guard let `self` = self else {
@@ -166,18 +278,17 @@ class MigrationsDemoViewController: UIViewController {
return return
} }
guard case .Success = result else { guard case .success = result else {
self.setEnabled(true) self.setEnabled(true)
return return
} }
self.setDataStack(dataStack, model: model, scrollToSelection: true) self.set(dataStack: dataStack, model: model, scrollToSelection: true)
let count = dataStack.queryValue( let count = try! dataStack.queryValue(
From(model.entityType), From<NSManagedObject>(model.entityType)
Select<Int>(.Count("dna")) .select(Int.self, .count(#keyPath(OrganismV1.dna))))!
)
if count > 0 { if count > 0 {
self.setEnabled(true) self.setEnabled(true)
@@ -186,25 +297,26 @@ class MigrationsDemoViewController: UIViewController {
for i: Int64 in 0 ..< 20 { for i: Int64 in 0 ..< 20 {
dataStack.beginAsynchronous { (transaction) -> Void in dataStack.perform(
asynchronous: { (transaction) in
for j: Int64 in 0 ..< 500 {
let organism = transaction.create(Into(model.entityType)) as! OrganismProtocol for j: Int64 in 0 ..< 500 {
organism.dna = (i * 500) + j + 1
organism.mutate() let organism = transaction.create(Into(model.entityType)) as! OrganismProtocol
} organism.dna = (i * 500) + j + 1
organism.mutate()
transaction.commit() }
} },
completion: { _ in }
)
} }
dataStack.beginAsynchronous { [weak self] (transaction) -> Void in dataStack.perform(
asynchronous: { _ in },
transaction.commit { _ in completion: { [weak self] _ in
self?.setEnabled(true) self?.setEnabled(true)
} }
} )
} }
} }
) )
@@ -218,47 +330,57 @@ class MigrationsDemoViewController: UIViewController {
} }
} }
private func setEnabled(enabled: Bool) { private func setEnabled(_ enabled: Bool) {
UIView.animateWithDuration( UIView.animate(
0.2, withDuration: 0.2,
delay: 0, delay: 0,
options: .BeginFromCurrentState, options: .beginFromCurrentState,
animations: { () -> Void in animations: { () -> Void in
let navigationItem = self.navigationItem let navigationItem = self.navigationItem
navigationItem.leftBarButtonItem?.enabled = enabled navigationItem.leftBarButtonItem?.isEnabled = enabled
navigationItem.rightBarButtonItem?.enabled = enabled navigationItem.rightBarButtonItem?.isEnabled = enabled
navigationItem.hidesBackButton = !enabled navigationItem.hidesBackButton = !enabled
self.segmentedControl?.enabled = enabled self.segmentedControl?.isEnabled = enabled
if let tableView = self.tableView { if let tableView = self.tableView {
tableView.alpha = enabled ? 1.0 : 0.5 tableView.alpha = enabled ? 1.0 : 0.5
tableView.userInteractionEnabled = enabled tableView.isUserInteractionEnabled = enabled
} }
}, },
completion: nil completion: nil
) )
} }
private func setDataStack(dataStack: DataStack?, model: ModelMetadata?, scrollToSelection: Bool) { private func set(dataStack: DataStack?, model: ModelMetadata?, scrollToSelection: Bool) {
if let dataStack = dataStack, let model = model { if let dataStack = dataStack, let model = model {
self.segmentedControl?.selectedSegmentIndex = self.models.map { $0.version }.indexOf(model.version)! self.segmentedControl?.selectedSegmentIndex = self.models
.index(
where: { (arg) -> Bool in
let (_, _, schemaHistory) = arg
return schemaHistory.currentModelVersion == model.schemaHistory.currentModelVersion
}
)!
self._dataStack = dataStack self._dataStack = dataStack
let listMonitor = dataStack.monitorList(From(model.entityType), OrderBy(.Descending("dna"))) let listMonitor = dataStack.monitorList(
From(model.entityType),
OrderBy<NSManagedObject>(.descending(#keyPath(OrganismV1.dna)))
)
listMonitor.addObserver(self) listMonitor.addObserver(self)
self._listMonitor = listMonitor self._listMonitor = listMonitor
if self.lastSelectedIndexPath == nil { if self.lastSelectedIndexPath == nil {
if listMonitor.numberOfObjectsInSection(0) > 0 { if listMonitor.numberOfObjects(in: 0) > 0 {
self.setSelectedIndexPath(NSIndexPath(forRow: 0, inSection: 0), scrollToSelection: true) self.setSelectedIndexPath(IndexPath(row: 0, section: 0), scrollToSelection: true)
} }
} }
} }
@@ -272,14 +394,14 @@ class MigrationsDemoViewController: UIViewController {
self.updateDisplay(reloadData: true, scrollToSelection: scrollToSelection, animated: false) self.updateDisplay(reloadData: true, scrollToSelection: scrollToSelection, animated: false)
} }
private func reloadTableHeaderWithProgress(progress: NSProgress) { private func reloadTableHeaderWithProgress(_ progress: Progress) {
self.progressView?.setProgress(Float(progress.fractionCompleted), animated: true) self.progressView?.setProgress(Float(progress.fractionCompleted), animated: true)
self.titleLabel?.text = "Migrating: \(progress.localizedDescription)" self.titleLabel?.text = "Migrating: \(progress.localizedDescription ?? "")"
self.organismLabel?.text = "Progressive step \(progress.localizedAdditionalDescription)" self.organismLabel?.text = "Progressive step \(progress.localizedAdditionalDescription ?? "")"
} }
private func updateDisplay(reloadData reloadData: Bool, scrollToSelection: Bool, animated: Bool) { private func updateDisplay(reloadData: Bool, scrollToSelection: Bool, animated: Bool) {
var lines = [String]() var lines = [String]()
var organismType = "" var organismType = ""
@@ -287,14 +409,14 @@ class MigrationsDemoViewController: UIViewController {
for property in organism.entity.properties { for property in organism.entity.properties {
let value: AnyObject = organism.valueForKey(property.name) ?? NSNull() let value = organism.value(forKey: property.name) ?? NSNull()
lines.append("\(property.name): \(value)") lines.append("\(property.name): \(value)")
} }
organismType = organism.entity.managedObjectClassName organismType = organism.entity.managedObjectClassName
} }
self.titleLabel?.text = organismType self.titleLabel?.text = organismType
self.organismLabel?.text = lines.joinWithSeparator("\n") self.organismLabel?.text = lines.joined(separator: "\n")
self.progressView?.progress = 0 self.progressView?.progress = 0
self.headerContainer?.setNeedsLayout() self.headerContainer?.setNeedsLayout()
@@ -311,87 +433,13 @@ class MigrationsDemoViewController: UIViewController {
tableView.layoutIfNeeded() tableView.layoutIfNeeded()
if let indexPath = self.lastSelectedIndexPath where indexPath.row < tableView.numberOfRowsInSection(0) { if let indexPath = self.lastSelectedIndexPath,
indexPath.row < tableView.numberOfRows(inSection: 0) {
tableView.selectRowAtIndexPath(indexPath, tableView.selectRow(at: indexPath,
animated: scrollToSelection && animated, animated: scrollToSelection && animated,
scrollPosition: scrollToSelection ? .Middle : .None 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

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

View File

@@ -3,7 +3,7 @@
// CoreStoreDemo // CoreStoreDemo
// //
// Created by John Rommel Estropia on 2015/07/12. // Created by John Rommel Estropia on 2015/07/12.
// Copyright © 2015 John Rommel Estropia. All rights reserved. // Copyright © 2018 John Rommel Estropia. All rights reserved.
// //
import UIKit import UIKit
@@ -15,7 +15,7 @@ class OrganismTableViewCell: UITableViewCell {
var mutateButtonHandler: (() -> Void)? var mutateButtonHandler: (() -> Void)?
@IBAction dynamic func mutateButtonTouchUpInside(sender: UIButton?) { @IBAction dynamic func mutateButtonTouchUpInside(_ sender: UIButton?) {
self.mutateButtonHandler?() self.mutateButtonHandler?()
} }

View File

@@ -3,7 +3,7 @@
// CoreStoreDemo // CoreStoreDemo
// //
// Created by John Rommel Estropia on 2015/06/21. // Created by John Rommel Estropia on 2015/06/21.
// Copyright © 2015 John Rommel Estropia. All rights reserved. // Copyright © 2018 John Rommel Estropia. All rights reserved.
// //
import Foundation import Foundation

View File

@@ -3,7 +3,7 @@
// CoreStoreDemo // CoreStoreDemo
// //
// Created by John Rommel Estropia on 2015/06/21. // Created by John Rommel Estropia on 2015/06/21.
// Copyright © 2015 John Rommel Estropia. All rights reserved. // Copyright © 2018 John Rommel Estropia. All rights reserved.
// //
import Foundation import Foundation

View File

@@ -3,21 +3,27 @@
// CoreStoreDemo // CoreStoreDemo
// //
// Created by John Rommel Estropia on 2015/06/27. // Created by John Rommel Estropia on 2015/06/27.
// Copyright © 2015 John Rommel Estropia. All rights reserved. // Copyright © 2018 John Rommel Estropia. All rights reserved.
// //
import CoreData import CoreData
class OrganismV2ToV3MigrationPolicy: NSEntityMigrationPolicy { class OrganismV2ToV3MigrationPolicy: NSEntityMigrationPolicy {
override func createDestinationInstancesForSourceInstance(sInstance: NSManagedObject, entityMapping mapping: NSEntityMapping, manager: NSMigrationManager) throws { override func createDestinationInstances(forSource sInstance: NSManagedObject, in mapping: NSEntityMapping, manager: NSMigrationManager) throws {
try super.createDestinationInstancesForSourceInstance(sInstance, entityMapping: mapping, manager: manager) try super.createDestinationInstances(forSource: sInstance, in: mapping, manager: manager)
for dInstance in manager.destinationInstancesForEntityMappingNamed(mapping.name, sourceInstances: [sInstance]) { for dInstance in manager.destinationInstances(forEntityMappingName: mapping.name, sourceInstances: [sInstance]) {
dInstance.setValue(false, forKey: "hasVertebrae") dInstance.setValue(
dInstance.setValue(sInstance.valueForKey("numberOfFlippers"), forKey: "numberOfLimbs") false,
forKey: #keyPath(OrganismV3.hasVertebrae)
)
dInstance.setValue(
sInstance.value(forKey: #keyPath(OrganismV2.numberOfFlippers)),
forKey: #keyPath(OrganismV3.numberOfLimbs)
)
} }
} }
} }

View File

@@ -3,7 +3,7 @@
// CoreStoreDemo // CoreStoreDemo
// //
// Created by John Rommel Estropia on 2015/06/27. // Created by John Rommel Estropia on 2015/06/27.
// Copyright © 2015 John Rommel Estropia. All rights reserved. // Copyright © 2018 John Rommel Estropia. All rights reserved.
// //
import Foundation import Foundation

View File

@@ -1,4 +1,4 @@
<?xml version="1.0" standalone="no"?> <?xml version="1.0"?>
<!DOCTYPE database SYSTEM "file:///System/Library/DTDs/CoreData.dtd"> <!DOCTYPE database SYSTEM "file:///System/Library/DTDs/CoreData.dtd">
<database> <database>
@@ -10,7 +10,7 @@
<plist version="1.0"> <plist version="1.0">
<dict> <dict>
<key>NSPersistenceFrameworkVersion</key> <key>NSPersistenceFrameworkVersion</key>
<integer>526</integer> <integer>754</integer>
<key>NSStoreModelVersionHashes</key> <key>NSStoreModelVersionHashes</key>
<dict> <dict>
<key>XDDevAttributeMapping</key> <key>XDDevAttributeMapping</key>

View File

@@ -1,9 +1,9 @@
<?xml version="1.0" encoding="UTF-8" standalone="yes"?> <?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"> <model type="com.apple.IDECoreDataModeler.DataModel" documentVersion="1.0" lastSavedToolsVersion="11198.3" systemVersion="15F34" minimumToolsVersion="Xcode 4.3" sourceLanguage="Swift" userDefinedModelVersionIdentifier="">
<entity name="Organism" representedClassName="CoreStoreDemo.OrganismV1" syncable="YES"> <entity name="Organism" representedClassName="CoreStoreDemo.OrganismV1" syncable="YES">
<attribute name="dna" optional="YES" attributeType="Integer 64" syncable="YES"/> <attribute name="dna" optional="YES" attributeType="Integer 64" usesScalarValueType="NO" syncable="YES"/>
<attribute name="hasHead" optional="YES" attributeType="Boolean" syncable="YES"/> <attribute name="hasHead" optional="YES" attributeType="Boolean" usesScalarValueType="NO" syncable="YES"/>
<attribute name="hasTail" optional="YES" attributeType="Boolean" syncable="YES"/> <attribute name="hasTail" optional="YES" attributeType="Boolean" usesScalarValueType="NO" syncable="YES"/>
</entity> </entity>
<elements> <elements>
<element name="Organism" positionX="-36" positionY="9" width="128" height="90"/> <element name="Organism" positionX="-36" positionY="9" width="128" height="90"/>

View File

@@ -1,10 +1,10 @@
<?xml version="1.0" encoding="UTF-8" standalone="yes"?> <?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"> <model type="com.apple.IDECoreDataModeler.DataModel" documentVersion="1.0" lastSavedToolsVersion="11198.3" systemVersion="15F34" minimumToolsVersion="Xcode 4.3" sourceLanguage="Swift" userDefinedModelVersionIdentifier="">
<entity name="Organism" representedClassName="CoreStoreDemo.OrganismV2" syncable="YES"> <entity name="Organism" representedClassName="CoreStoreDemo.OrganismV2" syncable="YES">
<attribute name="dna" optional="YES" attributeType="Integer 64" syncable="YES"/> <attribute name="dna" optional="YES" attributeType="Integer 64" usesScalarValueType="NO" syncable="YES"/>
<attribute name="hasHead" attributeType="Boolean" syncable="YES"/> <attribute name="hasHead" attributeType="Boolean" usesScalarValueType="NO" syncable="YES"/>
<attribute name="hasTail" attributeType="Boolean" syncable="YES"/> <attribute name="hasTail" attributeType="Boolean" usesScalarValueType="NO" syncable="YES"/>
<attribute name="numberOfFlippers" attributeType="Integer 32" defaultValueString="0" syncable="YES"/> <attribute name="numberOfFlippers" attributeType="Integer 32" defaultValueString="0" usesScalarValueType="NO" syncable="YES"/>
</entity> </entity>
<elements> <elements>
<element name="Organism" positionX="-36" positionY="9" width="128" height="105"/> <element name="Organism" positionX="-36" positionY="9" width="128" height="105"/>

View File

@@ -1,11 +1,11 @@
<?xml version="1.0" encoding="UTF-8" standalone="yes"?> <?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"> <model type="com.apple.IDECoreDataModeler.DataModel" documentVersion="1.0" lastSavedToolsVersion="12141" systemVersion="16E195" minimumToolsVersion="Xcode 4.3" sourceLanguage="Swift" userDefinedModelVersionIdentifier="">
<entity name="Organism" representedClassName="CoreStoreDemo.OrganismV3" syncable="YES"> <entity name="Organism" representedClassName="CoreStoreDemo.OrganismV3" syncable="YES">
<attribute name="dna" optional="YES" attributeType="Integer 64" syncable="YES"/> <attribute name="dna" optional="YES" attributeType="Integer 64" usesScalarValueType="NO" syncable="YES"/>
<attribute name="hasHead" attributeType="Boolean" syncable="YES"/> <attribute name="hasHead" attributeType="Boolean" usesScalarValueType="NO" syncable="YES"/>
<attribute name="hasTail" attributeType="Boolean" syncable="YES"/> <attribute name="hasTail" attributeType="Boolean" usesScalarValueType="NO" syncable="YES"/>
<attribute name="hasVertebrae" attributeType="Boolean" syncable="YES"/> <attribute name="hasVertebrae" attributeType="Boolean" usesScalarValueType="NO" syncable="YES"/>
<attribute name="numberOfLimbs" attributeType="Integer 32" defaultValueString="0" syncable="YES"/> <attribute name="numberOfLimbs" attributeType="Integer 32" defaultValueString="0" usesScalarValueType="NO" elementID="numberOfFlippers" syncable="YES"/>
</entity> </entity>
<elements> <elements>
<element name="Organism" positionX="-36" positionY="9" width="128" height="120"/> <element name="Organism" positionX="-36" positionY="9" width="128" height="120"/>

View File

@@ -3,7 +3,7 @@
// CoreStoreDemo // CoreStoreDemo
// //
// Created by John Rommel Estropia on 2015/06/06. // Created by John Rommel Estropia on 2015/06/06.
// Copyright © 2015 John Rommel Estropia. All rights reserved. // Copyright © 2018 John Rommel Estropia. All rights reserved.
// //
import Foundation import Foundation

View File

@@ -3,7 +3,7 @@
// CoreStoreDemo // CoreStoreDemo
// //
// Created by John Rommel Estropia on 2015/06/06. // Created by John Rommel Estropia on 2015/06/06.
// Copyright © 2015 John Rommel Estropia. All rights reserved. // Copyright © 2018 John Rommel Estropia. All rights reserved.
// //
import Foundation import Foundation

View File

@@ -3,7 +3,7 @@
// CoreStoreDemo // CoreStoreDemo
// //
// Created by John Rommel Estropia on 2015/05/24. // Created by John Rommel Estropia on 2015/05/24.
// Copyright © 2015 John Rommel Estropia. All rights reserved. // Copyright © 2018 John Rommel Estropia. All rights reserved.
// //
import UIKit import UIKit
@@ -17,77 +17,76 @@ private struct Static {
static let facebookStack: DataStack = { static let facebookStack: DataStack = {
let dataStack = DataStack(modelName: "StackSetupDemo") let dataStack = DataStack(xcodeModelName: "StackSetupDemo")
try! dataStack.addStorageAndWait( try! dataStack.addStorageAndWait(
SQLiteStore( SQLiteStore(
fileName: "AccountsDemo_FB_Male.sqlite", fileName: "AccountsDemo_FB_Male.sqlite",
configuration: maleConfiguration, configuration: maleConfiguration,
localStorageOptions: .RecreateStoreOnModelMismatch localStorageOptions: .recreateStoreOnModelMismatch
) )
) )
try! dataStack.addStorageAndWait( try! dataStack.addStorageAndWait(
SQLiteStore( SQLiteStore(
fileName: "AccountsDemo_FB_Female.sqlite", fileName: "AccountsDemo_FB_Female.sqlite",
configuration: femaleConfiguration, configuration: femaleConfiguration,
localStorageOptions: .RecreateStoreOnModelMismatch localStorageOptions: .recreateStoreOnModelMismatch
) )
) )
dataStack.beginSynchronous { (transaction) -> Void in _ = try? dataStack.perform(
synchronous: { (transaction) in
transaction.deleteAll(From(UserAccount))
try transaction.deleteAll(From<UserAccount>())
let account1 = transaction.create(Into<MaleAccount>(maleConfiguration))
account1.accountType = "Facebook" let account1 = transaction.create(Into<MaleAccount>(maleConfiguration))
account1.name = "John Smith HCD" account1.accountType = "Facebook"
account1.friends = 42 account1.name = "John Smith HCD"
account1.friends = 42
let account2 = transaction.create(Into<FemaleAccount>(femaleConfiguration))
account2.accountType = "Facebook" let account2 = transaction.create(Into<FemaleAccount>(femaleConfiguration))
account2.name = "Jane Doe HCD" account2.accountType = "Facebook"
account2.friends = 314 account2.name = "Jane Doe HCD"
account2.friends = 314
transaction.commitAndWait() }
} )
return dataStack return dataStack
}() }()
static let twitterStack: DataStack = { static let twitterStack: DataStack = {
let dataStack = DataStack(modelName: "StackSetupDemo") let dataStack = DataStack(xcodeModelName: "StackSetupDemo")
try! dataStack.addStorageAndWait( try! dataStack.addStorageAndWait(
SQLiteStore( SQLiteStore(
fileName: "AccountsDemo_TW_Male.sqlite", fileName: "AccountsDemo_TW_Male.sqlite",
configuration: maleConfiguration, configuration: maleConfiguration,
localStorageOptions: .RecreateStoreOnModelMismatch localStorageOptions: .recreateStoreOnModelMismatch
) )
) )
try! dataStack.addStorageAndWait( try! dataStack.addStorageAndWait(
SQLiteStore( SQLiteStore(
fileName: "AccountsDemo_TW_Female.sqlite", fileName: "AccountsDemo_TW_Female.sqlite",
configuration: femaleConfiguration, configuration: femaleConfiguration,
localStorageOptions: .RecreateStoreOnModelMismatch localStorageOptions: .recreateStoreOnModelMismatch
) )
) )
dataStack.beginSynchronous { (transaction) -> Void in _ = try? dataStack.perform(
synchronous: { (transaction) in
transaction.deleteAll(From(UserAccount))
try transaction.deleteAll(From<UserAccount>())
let account1 = transaction.create(Into<MaleAccount>(maleConfiguration))
account1.accountType = "Twitter" let account1 = transaction.create(Into<MaleAccount>(maleConfiguration))
account1.name = "#johnsmith_hcd" account1.accountType = "Twitter"
account1.friends = 7 account1.name = "#johnsmith_hcd"
account1.friends = 7
let account2 = transaction.create(Into<FemaleAccount>(femaleConfiguration))
account2.accountType = "Twitter" let account2 = transaction.create(Into<FemaleAccount>(femaleConfiguration))
account2.name = "#janedoe_hcd" account2.accountType = "Twitter"
account2.friends = 100 account2.name = "#janedoe_hcd"
account2.friends = 100
transaction.commitAndWait() }
} )
return dataStack return dataStack
}() }()
} }
@@ -100,53 +99,53 @@ private struct Static {
class StackSetupDemoViewController: UITableViewController { class StackSetupDemoViewController: UITableViewController {
let accounts = [ let accounts = [
Static.facebookStack.fetchAll(From(UserAccount)) ?? [], try! Static.facebookStack.fetchAll(From<UserAccount>()),
Static.twitterStack.fetchAll(From(UserAccount)) ?? [] try! Static.twitterStack.fetchAll(From<UserAccount>())
] ]
// MARK: UIViewController // MARK: UIViewController
override func viewWillAppear(animated: Bool) { override func viewWillAppear(_ animated: Bool) {
super.viewWillAppear(animated) super.viewWillAppear(animated)
self.tableView.reloadData() self.tableView.reloadData()
let indexPath = NSIndexPath(forRow: 0, inSection: 0) let indexPath = IndexPath(row: 0, section: 0)
self.tableView.selectRowAtIndexPath(indexPath, animated: false, scrollPosition: .None) self.tableView.selectRow(at: indexPath, animated: false, scrollPosition: .none)
self.updateDetailsWithAccount(self.accounts[indexPath.section][indexPath.row]) self.updateDetails(account: self.accounts[indexPath.section][indexPath.row])
} }
override func viewDidAppear(animated: Bool) { override func viewDidAppear(_ animated: Bool) {
super.viewDidAppear(animated) super.viewDidAppear(animated)
let alert = UIAlertController( let alert = UIAlertController(
title: "Setup Demo", 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.", 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 preferredStyle: .alert
) )
alert.addAction(UIAlertAction(title: "OK", style: .Cancel, handler: nil)) alert.addAction(UIAlertAction(title: "OK", style: .cancel, handler: nil))
self.presentViewController(alert, animated: true, completion: nil) self.present(alert, animated: true, completion: nil)
} }
// MARK: UITableViewDataSource // MARK: UITableViewDataSource
override func numberOfSectionsInTableView(tableView: UITableView) -> Int { override func numberOfSections(in tableView: UITableView) -> Int {
return self.accounts.count return self.accounts.count
} }
override func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int { override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return self.accounts[section].count return self.accounts[section].count
} }
override func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell { override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCellWithIdentifier("UITableViewCell")! let cell = tableView.dequeueReusableCell(withIdentifier: "UITableViewCell")!
let account = self.accounts[indexPath.section][indexPath.row] let account = self.accounts[indexPath.section][indexPath.row]
cell.textLabel?.text = account.name cell.textLabel?.text = account.name
@@ -158,13 +157,13 @@ class StackSetupDemoViewController: UITableViewController {
// MARK: UITableViewDelegate // MARK: UITableViewDelegate
override func tableView(tableView: UITableView, didSelectRowAtIndexPath indexPath: NSIndexPath) { override func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
let account = self.accounts[indexPath.section][indexPath.row] let account = self.accounts[indexPath.section][indexPath.row]
self.updateDetailsWithAccount(account) self.updateDetails(account: account)
} }
override func tableView(tableView: UITableView, titleForHeaderInSection section: Int) -> String? { override func tableView(_ tableView: UITableView, titleForHeaderInSection section: Int) -> String? {
switch section { switch section {
@@ -188,7 +187,7 @@ class StackSetupDemoViewController: UITableViewController {
@IBOutlet private dynamic weak var nameLabel: UILabel? @IBOutlet private dynamic weak var nameLabel: UILabel?
@IBOutlet private dynamic weak var friendsLabel: UILabel? @IBOutlet private dynamic weak var friendsLabel: UILabel?
private func updateDetailsWithAccount(account: UserAccount) { private func updateDetails(account: UserAccount) {
self.accountTypeLabel?.text = account.accountType self.accountTypeLabel?.text = account.accountType
self.nameLabel?.text = account.name self.nameLabel?.text = account.name

View File

@@ -3,7 +3,7 @@
// CoreStoreDemo // CoreStoreDemo
// //
// Created by John Rommel Estropia on 2015/05/24. // Created by John Rommel Estropia on 2015/05/24.
// Copyright © 2015 John Rommel Estropia. All rights reserved. // Copyright © 2018 John Rommel Estropia. All rights reserved.
// //
import Foundation import Foundation

View File

@@ -3,7 +3,7 @@
// CoreStoreDemo // CoreStoreDemo
// //
// Created by John Rommel Estropia on 2015/05/24. // Created by John Rommel Estropia on 2015/05/24.
// Copyright © 2015 John Rommel Estropia. All rights reserved. // Copyright © 2018 John Rommel Estropia. All rights reserved.
// //
import Foundation import Foundation

View File

@@ -3,15 +3,15 @@
// CoreStoreDemo // CoreStoreDemo
// //
// Created by John Rommel Estropia on 2015/05/24. // Created by John Rommel Estropia on 2015/05/24.
// Copyright © 2015 John Rommel Estropia. All rights reserved. // Copyright © 2018 John Rommel Estropia. All rights reserved.
// //
import UIKit import UIKit
import Contacts
import CoreLocation import CoreLocation
import MapKit import MapKit
import AddressBookUI import AddressBookUI
import CoreStore import CoreStore
import GCDKit
private struct Static { private struct Static {
@@ -22,21 +22,21 @@ private struct Static {
SQLiteStore( SQLiteStore(
fileName: "PlaceDemo.sqlite", fileName: "PlaceDemo.sqlite",
configuration: "TransactionsDemo", configuration: "TransactionsDemo",
localStorageOptions: .RecreateStoreOnModelMismatch localStorageOptions: .recreateStoreOnModelMismatch
) )
) )
var place = CoreStore.fetchOne(From(Place)) var place = try! CoreStore.fetchOne(From<Place>())
if place == nil { if place == nil {
CoreStore.beginSynchronous { (transaction) -> Void in _ = try? CoreStore.perform(
synchronous: { (transaction) in
let place = transaction.create(Into(Place))
place.setInitialValues() let place = transaction.create(Into<Place>())
place.setInitialValues()
transaction.commitAndWait() }
} )
place = CoreStore.fetchOne(From(Place)) place = try! CoreStore.fetchOne(From<Place>())
} }
return CoreStore.monitorObject(place!) return CoreStore.monitorObject(place!)
@@ -71,33 +71,33 @@ class TransactionsDemoViewController: UIViewController, MKMapViewDelegate, Objec
Static.placeController.addObserver(self) Static.placeController.addObserver(self)
self.navigationItem.rightBarButtonItem = UIBarButtonItem( self.navigationItem.rightBarButtonItem = UIBarButtonItem(
barButtonSystemItem: .Refresh, barButtonSystemItem: .refresh,
target: self, target: self,
action: #selector(self.refreshButtonTapped(_:)) action: #selector(self.refreshButtonTapped(_:))
) )
} }
override func viewDidAppear(animated: Bool) { override func viewDidAppear(_ animated: Bool) {
super.viewDidAppear(animated) super.viewDidAppear(animated)
let alert = UIAlertController( let alert = UIAlertController(
title: "Transactions Demo", 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.", 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 preferredStyle: .alert
) )
alert.addAction(UIAlertAction(title: "OK", style: .Cancel, handler: nil)) alert.addAction(UIAlertAction(title: "OK", style: .cancel, handler: nil))
self.presentViewController(alert, animated: true, completion: nil) self.present(alert, animated: true, completion: nil)
} }
override func viewWillAppear(animated: Bool) { override func viewWillAppear(_ animated: Bool) {
super.viewWillAppear(animated) super.viewWillAppear(animated)
if let mapView = self.mapView, let place = Static.placeController.object { if let mapView = self.mapView, let place = Static.placeController.object {
mapView.addAnnotation(place) mapView.addAnnotation(place)
mapView.setCenterCoordinate(place.coordinate, animated: false) mapView.setCenter(place.coordinate, animated: false)
mapView.selectAnnotation(place, animated: false) mapView.selectAnnotation(place, animated: false)
} }
} }
@@ -105,14 +105,14 @@ class TransactionsDemoViewController: UIViewController, MKMapViewDelegate, Objec
// MARK: MKMapViewDelegate // MARK: MKMapViewDelegate
func mapView(mapView: MKMapView, viewForAnnotation annotation: MKAnnotation) -> MKAnnotationView? { func mapView(_ mapView: MKMapView, viewFor annotation: MKAnnotation) -> MKAnnotationView? {
let identifier = "MKAnnotationView" let identifier = "MKAnnotationView"
var annotationView: MKPinAnnotationView! = mapView.dequeueReusableAnnotationViewWithIdentifier(identifier) as? MKPinAnnotationView var annotationView: MKPinAnnotationView! = mapView.dequeueReusableAnnotationView(withIdentifier: identifier) as? MKPinAnnotationView
if annotationView == nil { if annotationView == nil {
annotationView = MKPinAnnotationView(annotation: annotation, reuseIdentifier: identifier) annotationView = MKPinAnnotationView(annotation: annotation, reuseIdentifier: identifier)
annotationView.enabled = true annotationView.isEnabled = true
annotationView.canShowCallout = true annotationView.canShowCallout = true
annotationView.animatesDrop = true annotationView.animatesDrop = true
} }
@@ -127,28 +127,28 @@ class TransactionsDemoViewController: UIViewController, MKMapViewDelegate, Objec
// MARK: ObjectObserver // MARK: ObjectObserver
func objectMonitor(monitor: ObjectMonitor<Place>, willUpdateObject object: Place) { func objectMonitor(_ monitor: ObjectMonitor<Place>, willUpdateObject object: Place) {
// none // none
} }
func objectMonitor(monitor: ObjectMonitor<Place>, didUpdateObject object: Place, changedPersistentKeys: Set<KeyPath>) { func objectMonitor(_ monitor: ObjectMonitor<Place>, didUpdateObject object: Place, changedPersistentKeys: Set<KeyPathString>) {
if let mapView = self.mapView { if let mapView = self.mapView {
mapView.removeAnnotations(mapView.annotations ?? []) mapView.removeAnnotations(mapView.annotations)
mapView.addAnnotation(object) mapView.addAnnotation(object)
mapView.setCenterCoordinate(object.coordinate, animated: true) mapView.setCenter(object.coordinate, animated: true)
mapView.selectAnnotation(object, animated: true) mapView.selectAnnotation(object, animated: true)
if changedPersistentKeys.contains("latitude") || changedPersistentKeys.contains("longitude") { if changedPersistentKeys.contains(#keyPath(Place.latitude)) || changedPersistentKeys.contains(#keyPath(Place.longitude)) {
self.geocodePlace(object) self.geocode(place: object)
} }
} }
} }
func objectMonitor(monitor: ObjectMonitor<Place>, didDeleteObject object: Place) { func objectMonitor(_ monitor: ObjectMonitor<Place>, didDeleteObject object: Place) {
// none // none
} }
@@ -160,34 +160,39 @@ class TransactionsDemoViewController: UIViewController, MKMapViewDelegate, Objec
@IBOutlet weak var mapView: MKMapView? @IBOutlet weak var mapView: MKMapView?
@IBAction dynamic func longPressGestureRecognized(sender: AnyObject?) { @IBAction dynamic func longPressGestureRecognized(_ sender: AnyObject?) {
if let mapView = self.mapView, let gesture = sender as? UILongPressGestureRecognizer where gesture.state == .Began { if let mapView = self.mapView,
let gesture = sender as? UILongPressGestureRecognizer,
gesture.state == .began {
let coordinate = mapView.convertPoint( let coordinate = mapView.convert(
gesture.locationInView(mapView), gesture.location(in: mapView),
toCoordinateFromView: mapView toCoordinateFrom: mapView
) )
CoreStore.beginAsynchronous { (transaction) -> Void in CoreStore.perform(
asynchronous: { (transaction) in
let place = transaction.edit(Static.placeController.object)
place?.coordinate = coordinate
},
completion: { _ in }
)
}
}
@IBAction dynamic func refreshButtonTapped(_ sender: AnyObject?) {
_ = try? CoreStore.perform(
synchronous: { (transaction) in
let place = transaction.edit(Static.placeController.object) let place = transaction.edit(Static.placeController.object)
place?.coordinate = coordinate place?.setInitialValues()
transaction.commit { (_) -> Void in }
} }
} )
} }
@IBAction dynamic func refreshButtonTapped(sender: AnyObject?) { func geocode(place: Place) {
CoreStore.beginSynchronous { (transaction) -> Void in
let place = transaction.edit(Static.placeController.object)
place?.setInitialValues()
transaction.commitAndWait()
}
}
func geocodePlace(place: Place) {
let transaction = CoreStore.beginUnsafe() let transaction = CoreStore.beginUnsafe()
@@ -199,11 +204,23 @@ class TransactionsDemoViewController: UIViewController, MKMapViewDelegate, Objec
CLLocation(latitude: place.latitude, longitude: place.longitude), CLLocation(latitude: place.latitude, longitude: place.longitude),
completionHandler: { [weak self] (placemarks, error) -> Void in completionHandler: { [weak self] (placemarks, error) -> Void in
if let placemark = placemarks?.first, let addressDictionary = placemark.addressDictionary { if let placemark = placemarks?.first, let dictionary = placemark.addressDictionary {
let place = transaction.edit(Static.placeController.object) let place = transaction.edit(Static.placeController.object)
place?.title = placemark.name place?.title = placemark.name
place?.subtitle = ABCreateStringWithAddressDictionary(addressDictionary, true) place?.subtitle = CNPostalAddressFormatter.string(
from: autoreleasepool {
let address = CNMutablePostalAddress()
(dictionary["Street"] as? String).flatMap({ address.street = $0 })
(dictionary["State"] as? String).flatMap({ address.state = $0 })
(dictionary["City"] as? String).flatMap({ address.city = $0 })
(dictionary["Country"] as? String).flatMap({ address.country = $0 })
(dictionary["ZIP"] as? String).flatMap({ address.postalCode = $0 })
return address
},
style: .mailingAddress
)
transaction.commit { (_) -> Void in } transaction.commit { (_) -> Void in }
} }

View File

@@ -2,7 +2,7 @@
// BaseTestCase.swift // BaseTestCase.swift
// CoreStore // CoreStore
// //
// Copyright © 2016 John Rommel Estropia // Copyright © 2018 John Rommel Estropia
// //
// Permission is hereby granted, free of charge, to any person obtaining a copy // Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal // of this software and associated documentation files (the "Software"), to deal
@@ -36,11 +36,11 @@ class BaseTestCase: XCTestCase {
// MARK: Internal // MARK: Internal
@nonobjc @nonobjc
func prepareStack<T>(configurations configurations: [String?] = [nil], @noescape _ closure: (dataStack: DataStack) -> T) -> T { func prepareStack(configurations: [ModelConfiguration] = [nil], _ closure: (_ dataStack: DataStack) throws -> Void) {
let stack = DataStack( let stack = DataStack(
modelName: "Model", xcodeModelName: "Model",
bundle: NSBundle(forClass: self.dynamicType) bundle: Bundle(for: type(of: self))
) )
do { do {
@@ -49,23 +49,23 @@ class BaseTestCase: XCTestCase {
try stack.addStorageAndWait( try stack.addStorageAndWait(
SQLiteStore( SQLiteStore(
fileURL: SQLiteStore.defaultRootDirectory fileURL: SQLiteStore.defaultRootDirectory
.URLByAppendingPathComponent(NSUUID().UUIDString) .appendingPathComponent(UUID().uuidString)
.URLByAppendingPathComponent("\(self.dynamicType)_\(($0 ?? "-null-")).sqlite"), .appendingPathComponent("\(type(of: self))_\(($0 ?? "-null-")).sqlite"),
configuration: $0, configuration: $0,
localStorageOptions: .RecreateStoreOnModelMismatch localStorageOptions: .recreateStoreOnModelMismatch
) )
) )
} }
try closure(stack)
} }
catch let error as NSError { catch let error as NSError {
XCTFail(error.coreStoreDumpString) XCTFail(error.coreStoreDumpString)
} }
return closure(dataStack: stack)
} }
@nonobjc @nonobjc
func expectLogger<T>(expectations: [TestLogger.Expectation], @noescape closure: () -> T) -> T { func expectLogger<T>(_ expectations: [TestLogger.Expectation], closure: () throws -> T) rethrows -> T {
CoreStore.logger = TestLogger(self.prepareLoggerExpectations(expectations)) CoreStore.logger = TestLogger(self.prepareLoggerExpectations(expectations))
defer { defer {
@@ -73,22 +73,22 @@ class BaseTestCase: XCTestCase {
self.checkExpectationsImmediately() self.checkExpectationsImmediately()
CoreStore.logger = TestLogger([:]) CoreStore.logger = TestLogger([:])
} }
return closure() return try closure()
} }
@nonobjc @nonobjc
func expectLogger(expectations: [TestLogger.Expectation: XCTestExpectation]) { func expectLogger(_ expectations: [TestLogger.Expectation: XCTestExpectation]) {
CoreStore.logger = TestLogger(expectations) CoreStore.logger = TestLogger(expectations)
} }
@nonobjc @nonobjc
func prepareLoggerExpectations(expectations: [TestLogger.Expectation]) -> [TestLogger.Expectation: XCTestExpectation] { func prepareLoggerExpectations(_ expectations: [TestLogger.Expectation]) -> [TestLogger.Expectation: XCTestExpectation] {
var testExpectations: [TestLogger.Expectation: XCTestExpectation] = [:] var testExpectations: [TestLogger.Expectation: XCTestExpectation] = [:]
for expectation in expectations { for expectation in expectations {
testExpectations[expectation] = self.expectationWithDescription("Logger Expectation: \(expectation)") testExpectations[expectation] = self.expectation(description: "Logger Expectation: \(expectation)")
} }
return testExpectations return testExpectations
} }
@@ -96,13 +96,13 @@ class BaseTestCase: XCTestCase {
@nonobjc @nonobjc
func checkExpectationsImmediately() { func checkExpectationsImmediately() {
self.waitForExpectationsWithTimeout(0, handler: nil) self.waitForExpectations(timeout: 0, handler: { _ in })
} }
@nonobjc @nonobjc
func waitAndCheckExpectations() { func waitAndCheckExpectations() {
self.waitForExpectationsWithTimeout(10, handler: nil) self.waitForExpectations(timeout: 10, handler: {_ in })
} }
// MARK: XCTestCase // MARK: XCTestCase
@@ -126,7 +126,7 @@ class BaseTestCase: XCTestCase {
private func deleteStores() { private func deleteStores() {
_ = try? NSFileManager.defaultManager().removeItemAtURL(SQLiteStore.defaultRootDirectory) _ = try? FileManager.default.removeItem(at: SQLiteStore.defaultRootDirectory)
} }
} }
@@ -137,11 +137,11 @@ class TestLogger: CoreStoreLogger {
enum Expectation { enum Expectation {
case LogWarning case logWarning
case LogFatal case logFatal
case LogError case logError
case AssertionFailure case assertionFailure
case FatalError case fatalError
} }
init(_ expectations: [Expectation: XCTestExpectation]) { init(_ expectations: [Expectation: XCTestExpectation]) {
@@ -152,33 +152,35 @@ class TestLogger: CoreStoreLogger {
// MARK: CoreStoreLogger // MARK: CoreStoreLogger
func log(level level: LogLevel, message: String, fileName: StaticString, lineNumber: Int, functionName: StaticString) { var enableObjectConcurrencyDebugging: Bool = true
func log(level: LogLevel, message: String, fileName: StaticString, lineNumber: Int, functionName: StaticString) {
switch level { switch level {
case .Warning: self.fulfill(.LogWarning) case .warning: self.fulfill(.logWarning)
case .Fatal: self.fulfill(.LogFatal) case .fatal: self.fulfill(.logFatal)
default: break default: break
} }
} }
func log(error error: CoreStoreError, message: String, fileName: StaticString, lineNumber: Int, functionName: StaticString) { func log(error: CoreStoreError, message: String, fileName: StaticString, lineNumber: Int, functionName: StaticString) {
self.fulfill(.LogError) self.fulfill(.logError)
} }
func assert(@autoclosure condition: () -> Bool, @autoclosure message: () -> String, fileName: StaticString, lineNumber: Int, functionName: StaticString) { func assert(_ condition: @autoclosure () -> Bool, message: @autoclosure () -> String, fileName: StaticString, lineNumber: Int, functionName: StaticString) {
if condition() { if condition() {
return 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)
} }
@@ -186,7 +188,7 @@ class TestLogger: CoreStoreLogger {
private var expectations: [Expectation: XCTestExpectation] private var expectations: [Expectation: XCTestExpectation]
private func fulfill(expectation: Expectation) { private func fulfill(_ expectation: Expectation) {
if let instance = self.expectations[expectation] { if let instance = self.expectations[expectation] {

View File

@@ -2,8 +2,25 @@
// BaseTestDataTestCase.swift // BaseTestDataTestCase.swift
// CoreStore // CoreStore
// //
// Created by John Rommel Estropia on 2016/06/11. // Copyright © 2018 John Rommel Estropia
// Copyright © 2016 John Rommel Estropia. All rights reserved. //
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in all
// copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
// SOFTWARE.
// //
import Foundation import Foundation
@@ -17,60 +34,61 @@ import CoreStore
class BaseTestDataTestCase: BaseTestCase { class BaseTestDataTestCase: BaseTestCase {
@nonobjc @nonobjc
let dateFormatter: NSDateFormatter = { let dateFormatter: DateFormatter = cs_lazy {
let formatter = NSDateFormatter() let formatter = DateFormatter()
formatter.locale = NSLocale(localeIdentifier: "en_US_POSIX") formatter.locale = Locale(identifier: "en_US_POSIX")
formatter.timeZone = NSTimeZone(name: "UTC") formatter.timeZone = TimeZone(identifier: "UTC")
formatter.calendar = NSCalendar(identifier: NSCalendarIdentifierGregorian) formatter.calendar = Calendar(identifier: Calendar.Identifier.gregorian)
formatter.dateFormat = "yyyy'-'MM'-'dd'T'HH':'mm':'ssZ" formatter.dateFormat = "yyyy'-'MM'-'dd'T'HH':'mm':'ssZ"
return formatter return formatter
}() }
@nonobjc @nonobjc
func prepareTestDataForStack(stack: DataStack, configurations: [String?] = [nil]) { func prepareTestDataForStack(_ stack: DataStack, configurations: [ModelConfiguration] = [nil]) {
stack.beginSynchronous { (transaction) in try! stack.perform(
synchronous: { (transaction) in
for (configurationIndex, configuration) in configurations.enumerate() {
let configurationOrdinal = configurationIndex + 1 for (configurationIndex, configuration) in configurations.enumerated() {
if configuration == nil || configuration == "Config1" {
for idIndex in 1 ... 5 { let configurationOrdinal = configurationIndex + 1
if configuration == nil || configuration == "Config1" {
let object = transaction.create(Into<TestEntity1>(configuration)) for idIndex in 1 ... 5 {
object.testEntityID = NSNumber(integer: (configurationOrdinal * 100) + idIndex)
let object = transaction.create(Into<TestEntity1>(configuration))
object.testNumber = idIndex object.testEntityID = NSNumber(value: (configurationOrdinal * 100) + idIndex)
object.testDate = self.dateFormatter.dateFromString("2000-\(configurationOrdinal)-\(idIndex)T00:00:00Z")
object.testBoolean = (idIndex % 2) == 1 object.testNumber = NSNumber(value: idIndex)
object.testDecimal = NSDecimalNumber(string: "\(idIndex)") object.testDate = self.dateFormatter.date(from: "2000-\(configurationOrdinal)-\(idIndex)T00:00:00Z")
object.testBoolean = NSNumber(value: (idIndex % 2) == 1)
let string = "\(configuration ?? "nil"):TestEntity1:\(idIndex)" object.testDecimal = NSDecimalNumber(string: "\(idIndex)")
object.testString = string
object.testData = (string as NSString).dataUsingEncoding(NSUTF8StringEncoding) 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" {
if configuration == nil || configuration == "Config2" {
for idIndex in 1 ... 5 {
let object = transaction.create(Into<TestEntity2>(configuration)) for idIndex in 1 ... 5 {
object.testEntityID = NSNumber(integer: (configurationOrdinal * 200) + idIndex)
let object = transaction.create(Into<TestEntity2>(configuration))
object.testNumber = idIndex object.testEntityID = NSNumber(value: (configurationOrdinal * 200) + idIndex)
object.testDate = self.dateFormatter.dateFromString("2000-\(configurationOrdinal)-\(idIndex)T00:00:00Z")
object.testBoolean = (idIndex % 2) == 1 object.testNumber = NSNumber(value: idIndex)
object.testDecimal = NSDecimalNumber(string: "\(idIndex)") object.testDate = self.dateFormatter.date(from: "2000-\(configurationOrdinal)-\(idIndex)T00:00:00Z")
object.testBoolean = NSNumber(value: (idIndex % 2) == 1)
let string = "\(configuration ?? "nil"):TestEntity2:\(idIndex)" object.testDecimal = NSDecimalNumber(string: "\(idIndex)")
object.testString = string
object.testData = (string as NSString).dataUsingEncoding(NSUTF8StringEncoding) let string = "\(configuration ?? "nil"):TestEntity2:\(idIndex)"
object.testString = string
object.testData = (string as NSString).data(using: String.Encoding.utf8.rawValue)
}
} }
} }
} }
transaction.commitAndWait() )
}
} }
} }

View File

@@ -2,7 +2,7 @@
// BridgingTests.h // BridgingTests.h
// CoreStore // CoreStore
// //
// Copyright © 2016 John Rommel Estropia // Copyright © 2018 John Rommel Estropia
// //
// Permission is hereby granted, free of charge, to any person obtaining a copy // Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal // of this software and associated documentation files (the "Software"), to deal

View File

@@ -2,7 +2,7 @@
// BridgingTests.m // BridgingTests.m
// CoreStore // CoreStore
// //
// Copyright © 2016 John Rommel Estropia // Copyright © 2018 John Rommel Estropia
// //
// Permission is hereby granted, free of charge, to any person obtaining a copy // Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal // of this software and associated documentation files (the "Software"), to deal
@@ -163,7 +163,7 @@
- (void)test_ThatDataStacks_BridgeCorrectly { - (void)test_ThatDataStacks_BridgeCorrectly {
CSDataStack *dataStack = [[CSDataStack alloc] CSDataStack *dataStack = [[CSDataStack alloc]
initWithModelName:@"Model" initWithXcodeModelName:@"Model"
bundle:[NSBundle bundleForClass:[self class]] bundle:[NSBundle bundleForClass:[self class]]
versionChain:nil]; versionChain:nil];
XCTAssertNotNil(dataStack); XCTAssertNotNil(dataStack);
@@ -193,8 +193,75 @@
XCTAssertEqualObjects([[sqliteStorage class] storeType], [CSSQLiteStore storeType]); XCTAssertEqualObjects([[sqliteStorage class] storeType], [CSSQLiteStore storeType]);
XCTAssertEqualObjects([[sqliteStorage class] storeType], NSSQLiteStoreType); XCTAssertEqualObjects([[sqliteStorage class] storeType], NSSQLiteStoreType);
XCTAssertNil(sqliteStorage.configuration); XCTAssertNil(sqliteStorage.configuration);
XCTAssertEqualObjects(sqliteStorage.storeOptions, @{ NSSQLitePragmasOption: @{ @"journal_mode": @"WAL" } }); NSDictionary *storeOptions;
if (@available(iOS 11.0, macOS 10.13, tvOS 11.0, *)) {
storeOptions = @{ NSSQLitePragmasOption: @{ @"journal_mode": @"WAL" },
NSBinaryStoreInsecureDecodingCompatibilityOption: @YES };
}
else {
storeOptions = @{ NSSQLitePragmasOption: @{ @"journal_mode": @"WAL" }};
}
XCTAssertEqualObjects(sqliteStorage.storeOptions, storeOptions);
XCTAssertNil(sqliteError); XCTAssertNil(sqliteError);
} }
- (void)test_ThatTransactions_BridgeCorrectly {
[CSCoreStore
setDefaultStack:[[CSDataStack alloc]
initWithXcodeModelName:@"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]]);
NSError *error;
BOOL result = [transaction commitAndWaitWithError:&error];
XCTAssertTrue(result);
XCTAssertNil(error);
}
{
XCTestExpectation *expectation = [self expectationWithDescription:@"sync"];
NSError *error;
BOOL result = [CSCoreStore
beginSynchronous:^(CSSynchronousDataTransaction * _Nonnull transaction) {
XCTAssertNotNil(transaction);
XCTAssert([transaction isKindOfClass:[CSSynchronousDataTransaction class]]);
NSError *error;
XCTAssertTrue([transaction commitAndWaitWithError:&error]);
XCTAssertNil(error);
[expectation fulfill];
}
error:&error];
XCTAssertTrue(result);
XCTAssertNil(error);
}
{
XCTestExpectation *expectation = [self expectationWithDescription:@"async"];
[CSCoreStore beginAsynchronous:^(CSAsynchronousDataTransaction * _Nonnull transaction) {
XCTAssertNotNil(transaction);
XCTAssert([transaction isKindOfClass:[CSAsynchronousDataTransaction class]]);
[transaction
commitWithSuccess:^{
[expectation fulfill];
}
failure:^(CSError *error){
XCTFail();
}];
}];
}
[self waitForExpectationsWithTimeout:10 handler:nil];
}
@end @end

View File

@@ -0,0 +1,91 @@
//
// 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.
//
@testable
import CoreStore
// MARK: - ConvenienceTests
@available(macOS 10.12, *)
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,347 @@
//
// 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 {
let species = Value.Required<String>("species", initial: "Swift")
let master = Relationship.ToOne<Person>("master")
let color = Transformable.Optional<Color>("color")
}
class Dog: Animal {
let nickname = Value.Optional<String>("nickname")
let age = Value.Required<Int>("age", initial: 1)
let friends = Relationship.ToManyOrdered<Dog>("friends")
let friendedBy = Relationship.ToManyUnordered<Dog>("friendedBy", inverse: { $0.friends })
}
class Person: CoreStoreObject {
let title = Value.Required<String>(
"title",
initial: "Mr.",
customSetter: Person.setTitle
)
let name = Value.Required<String>(
"name",
initial: "",
customSetter: Person.setName
)
let displayName = Value.Optional<String>(
"displayName",
isTransient: true,
customGetter: Person.getDisplayName(_:),
affectedByKeyPaths: Person.keyPathsAffectingDisplayName()
)
let pets = Relationship.ToManyUnordered<Animal>("pets", inverse: { $0.master })
private static func setTitle(_ partialObject: PartialObject<Person>, _ newValue: String) {
partialObject.setPrimitiveValue(newValue, for: { $0.title })
partialObject.setPrimitiveValue(nil, for: { $0.displayName })
}
private static func setName(_ partialObject: PartialObject<Person>, _ newValue: String) {
partialObject.setPrimitiveValue(newValue, for: { $0.name })
partialObject.setPrimitiveValue(nil, for: { $0.displayName })
}
static func getDisplayName(_ partialObject: PartialObject<Person>) -> String? {
if let displayName = partialObject.primitiveValue(for: { $0.displayName }) {
return displayName
}
let title = partialObject.value(for: { $0.title })
let name = partialObject.value(for: { $0.name })
let displayName = "\(title) \(name)"
partialObject.setPrimitiveValue(displayName, for: { $0.displayName })
return displayName
}
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"),
Entity<Person>("Person")
],
versionLock: [
"Animal": [0x1b59d511019695cf, 0xdeb97e86c5eff179, 0x1cfd80745646cb3, 0x4ff99416175b5b9a],
"Dog": [0xe3f0afeb109b283a, 0x29998d292938eb61, 0x6aab788333cfc2a3, 0x492ff1d295910ea7],
"Person": [0x66d8bbfd8b21561f, 0xcecec69ecae3570f, 0xc4b73d71256214ef, 0x89b99bfe3e013e8b]
]
)
)
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.value, "Swift")
XCTAssertTrue(type(of: animal.species.value) == String.self)
animal.species .= "Sparrow"
XCTAssertEqual(animal.species.value, "Sparrow")
animal.color .= .yellow
XCTAssertEqual(animal.color.value, Color.yellow)
let dog = transaction.create(Into<Dog>())
XCTAssertEqual(dog.species.value, "Swift")
XCTAssertEqual(dog.nickname.value, nil)
XCTAssertEqual(dog.age.value, 1)
let didSetObserver = dog.species.observe(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.value, "Dog")
didSetObserverDone.fulfill()
}
let willSetObserver = dog.species.observe(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.value, "Swift")
willSetPriorObserverDone.fulfill()
}
else {
XCTAssertEqual(change.newValue, "Dog")
XCTAssertEqual(object.species.value, "Dog")
willSetNotPriorObserverDone.fulfill()
}
}
dog.species .= "Dog"
XCTAssertEqual(dog.species.value, "Dog")
didSetObserver.invalidate()
willSetObserver.invalidate()
dog.nickname .= "Spot"
XCTAssertEqual(dog.nickname.value, "Spot")
let person = transaction.create(Into<Person>())
XCTAssertTrue(person.pets.value.isEmpty)
XCTAssertEqual(
cs_dynamicType(of: person.rawObject!).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.value, "John")
XCTAssertEqual(person.displayName.value, "Mr. John") // Custom getter
person.title .= "Sir"
XCTAssertEqual(person.displayName.value, "Sir John")
person.pets.value.insert(dog)
XCTAssertEqual(person.pets.count, 1)
XCTAssertEqual(person.pets.value.first, dog)
XCTAssertEqual(person.pets.value.first?.master.value, person)
XCTAssertEqual(dog.master.value, person)
XCTAssertEqual(dog.master.value?.pets.value.first, dog)
},
success: { _ in
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.value, "Sparrow")
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.value, "Spot")
XCTAssertEqual(dog!.species.value, "Dog")
let person = try transaction.fetchOne(From<Person>())
XCTAssertNotNil(person)
XCTAssertEqual(person!.pets.value.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(\Dog.age)))
XCTAssertEqual(totalAge, 1)
_ = try transaction.fetchAll(
From<Dog>()
.where(\Animal.species == "Dog" && \.age == 10)
)
_ = try transaction.fetchAll(
From<Dog>()
.where(\.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.waitAndCheckExpectations()
}
}
@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("\(type(of: 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 // ErrorTests.swift
// CoreStore // CoreStore
// //
// Copyright © 2016 John Rommel Estropia // Copyright © 2018 John Rommel Estropia
// //
// Permission is hereby granted, free of charge, to any person obtaining a copy // Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal // of this software and associated documentation files (the "Software"), to deal
@@ -36,33 +36,33 @@ final class ErrorTests: XCTestCase {
@objc @objc
dynamic func test_ThatUnknownErrors_BridgeCorrectly() { dynamic func test_ThatUnknownErrors_BridgeCorrectly() {
let error = CoreStoreError.Unknown let error = CoreStoreError.unknown
XCTAssertEqual((error as NSError).domain, CoreStoreErrorDomain) 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 userInfo: NSDictionary = [:]
let objcError = error.bridgeToObjectiveC let objcError = error.bridgeToObjectiveC
XCTAssertEqual(error, objcError.bridgeToSwift) XCTAssertEqual(error, objcError.bridgeToSwift)
XCTAssertEqual(objcError.domain, CoreStoreErrorDomain) XCTAssertEqual(objcError.domain, CoreStoreErrorDomain)
XCTAssertEqual(objcError.code, CoreStoreErrorCode.UnknownError.rawValue) XCTAssertEqual(objcError.code, CoreStoreErrorCode.unknownError.rawValue)
XCTAssertEqual(objcError.userInfo, userInfo) XCTAssertEqual(objcError.userInfo as NSDictionary, userInfo)
let objcError2 = objcError.bridgeToSwift.bridgeToObjectiveC let objcError2 = objcError.bridgeToSwift.bridgeToObjectiveC
XCTAssertEqual(error, objcError2.bridgeToSwift) XCTAssertEqual(error, objcError2.bridgeToSwift)
XCTAssertEqual(objcError2.domain, CoreStoreErrorDomain) XCTAssertEqual(objcError2.domain, CoreStoreErrorDomain)
XCTAssertEqual(objcError2.code, CoreStoreErrorCode.UnknownError.rawValue) XCTAssertEqual(objcError2.code, CoreStoreErrorCode.unknownError.rawValue)
XCTAssertEqual(objcError2.userInfo, userInfo) XCTAssertEqual(objcError2.userInfo as NSDictionary, userInfo)
} }
@objc @objc
dynamic func test_ThatDifferentStorageExistsAtURLErrors_BridgeCorrectly() { dynamic func test_ThatDifferentStorageExistsAtURLErrors_BridgeCorrectly() {
let dummyURL = NSURL(string: "file:///test1/test2.sqlite")! let dummyURL = URL(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).domain, CoreStoreErrorDomain)
XCTAssertEqual((error as NSError).code, CoreStoreErrorCode.DifferentPersistentStoreExistsAtURL.rawValue) XCTAssertEqual((error as NSError).code, CoreStoreErrorCode.differentStorageExistsAtURL.rawValue)
let userInfo: NSDictionary = [ let userInfo: NSDictionary = [
"existingPersistentStoreURL": dummyURL "existingPersistentStoreURL": dummyURL
@@ -70,54 +70,59 @@ final class ErrorTests: XCTestCase {
let objcError = error.bridgeToObjectiveC let objcError = error.bridgeToObjectiveC
XCTAssertEqual(error, objcError.bridgeToSwift) XCTAssertEqual(error, objcError.bridgeToSwift)
XCTAssertEqual(objcError.domain, CoreStoreErrorDomain) XCTAssertEqual(objcError.domain, CoreStoreErrorDomain)
XCTAssertEqual(objcError.code, CoreStoreErrorCode.DifferentPersistentStoreExistsAtURL.rawValue) XCTAssertEqual(objcError.code, CoreStoreErrorCode.differentStorageExistsAtURL.rawValue)
XCTAssertEqual(objcError.userInfo, userInfo) XCTAssertEqual(objcError.userInfo as NSDictionary, userInfo)
let objcError2 = objcError.bridgeToSwift.bridgeToObjectiveC let objcError2 = objcError.bridgeToSwift.bridgeToObjectiveC
XCTAssertEqual(error, objcError2.bridgeToSwift) XCTAssertEqual(error, objcError2.bridgeToSwift)
XCTAssertEqual(objcError2.domain, CoreStoreErrorDomain) XCTAssertEqual(objcError2.domain, CoreStoreErrorDomain)
XCTAssertEqual(objcError2.code, CoreStoreErrorCode.DifferentPersistentStoreExistsAtURL.rawValue) XCTAssertEqual(objcError2.code, CoreStoreErrorCode.differentStorageExistsAtURL.rawValue)
XCTAssertEqual(objcError2.userInfo, userInfo) XCTAssertEqual(objcError2.userInfo as NSDictionary, userInfo)
} }
@objc @objc
dynamic func test_ThatMappingModelNotFoundErrors_BridgeCorrectly() { dynamic func test_ThatMappingModelNotFoundErrors_BridgeCorrectly() {
let dummyURL = NSURL(string: "file:///test1/test2.sqlite")! let dummyURL = URL(string: "file:///test1/test2.sqlite")!
let model = NSManagedObjectModel.fromBundle(NSBundle(forClass: self.dynamicType), modelName: "Model") let schemaHistory = SchemaHistory(
XcodeDataModelSchema.from(
modelName: "Model",
bundle: Bundle(for: type(of: self))
)
)
let version = "1.0.0" let version = "1.0.0"
let error = CoreStoreError.MappingModelNotFound(localStoreURL: dummyURL, targetModel: model, targetModelVersion: version) let error = CoreStoreError.mappingModelNotFound(localStoreURL: dummyURL, targetModel: schemaHistory.rawModel, targetModelVersion: version)
XCTAssertEqual((error as NSError).domain, CoreStoreErrorDomain) 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 = [ let userInfo: NSDictionary = [
"localStoreURL": dummyURL, "localStoreURL": dummyURL,
"targetModel": model, "targetModel": schemaHistory.rawModel,
"targetModelVersion": version "targetModelVersion": version
] ]
let objcError = error.bridgeToObjectiveC let objcError = error.bridgeToObjectiveC
XCTAssertEqual(error, objcError.bridgeToSwift) XCTAssertEqual(error, objcError.bridgeToSwift)
XCTAssertEqual(objcError.domain, CoreStoreErrorDomain) XCTAssertEqual(objcError.domain, CoreStoreErrorDomain)
XCTAssertEqual(objcError.code, CoreStoreErrorCode.MappingModelNotFound.rawValue) XCTAssertEqual(objcError.code, CoreStoreErrorCode.mappingModelNotFound.rawValue)
XCTAssertEqual(objcError.userInfo, userInfo) XCTAssertEqual(objcError.userInfo as NSDictionary, userInfo)
let objcError2 = objcError.bridgeToSwift.bridgeToObjectiveC let objcError2 = objcError.bridgeToSwift.bridgeToObjectiveC
XCTAssertEqual(error, objcError2.bridgeToSwift) XCTAssertEqual(error, objcError2.bridgeToSwift)
XCTAssertEqual(objcError2.domain, CoreStoreErrorDomain) XCTAssertEqual(objcError2.domain, CoreStoreErrorDomain)
XCTAssertEqual(objcError2.code, CoreStoreErrorCode.MappingModelNotFound.rawValue) XCTAssertEqual(objcError2.code, CoreStoreErrorCode.mappingModelNotFound.rawValue)
XCTAssertEqual(objcError2.userInfo, userInfo) XCTAssertEqual(objcError2.userInfo as NSDictionary, userInfo)
} }
@objc @objc
dynamic func test_ThatProgressiveMigrationRequiredErrors_BridgeCorrectly() { dynamic func test_ThatProgressiveMigrationRequiredErrors_BridgeCorrectly() {
let dummyURL = NSURL(string: "file:///test1/test2.sqlite")! let dummyURL = URL(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).domain, CoreStoreErrorDomain)
XCTAssertEqual((error as NSError).code, CoreStoreErrorCode.ProgressiveMigrationRequired.rawValue) XCTAssertEqual((error as NSError).code, CoreStoreErrorCode.progressiveMigrationRequired.rawValue)
let userInfo: NSDictionary = [ let userInfo: NSDictionary = [
"localStoreURL": dummyURL "localStoreURL": dummyURL
@@ -125,14 +130,14 @@ final class ErrorTests: XCTestCase {
let objcError = error.bridgeToObjectiveC let objcError = error.bridgeToObjectiveC
XCTAssertEqual(error, objcError.bridgeToSwift) XCTAssertEqual(error, objcError.bridgeToSwift)
XCTAssertEqual(objcError.domain, CoreStoreErrorDomain) XCTAssertEqual(objcError.domain, CoreStoreErrorDomain)
XCTAssertEqual(objcError.code, CoreStoreErrorCode.ProgressiveMigrationRequired.rawValue) XCTAssertEqual(objcError.code, CoreStoreErrorCode.progressiveMigrationRequired.rawValue)
XCTAssertEqual(objcError.userInfo, userInfo) XCTAssertEqual(objcError.userInfo as NSDictionary, userInfo)
let objcError2 = objcError.bridgeToSwift.bridgeToObjectiveC let objcError2 = objcError.bridgeToSwift.bridgeToObjectiveC
XCTAssertEqual(error, objcError2.bridgeToSwift) XCTAssertEqual(error, objcError2.bridgeToSwift)
XCTAssertEqual(objcError2.domain, CoreStoreErrorDomain) XCTAssertEqual(objcError2.domain, CoreStoreErrorDomain)
XCTAssertEqual(objcError2.code, CoreStoreErrorCode.ProgressiveMigrationRequired.rawValue) XCTAssertEqual(objcError2.code, CoreStoreErrorCode.progressiveMigrationRequired.rawValue)
XCTAssertEqual(objcError2.userInfo, userInfo) XCTAssertEqual(objcError2.userInfo as NSDictionary, userInfo)
} }
@objc @objc
@@ -144,12 +149,12 @@ final class ErrorTests: XCTestCase {
userInfo: [ userInfo: [
"key1": "value1", "key1": "value1",
"key2": 2, "key2": 2,
"key3": NSDate() "key3": Date()
] ]
) )
let error = CoreStoreError(internalError) let error = CoreStoreError(internalError)
XCTAssertEqual((error as NSError).domain, CoreStoreErrorDomain) 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 = [ let userInfo: NSDictionary = [
"NSError": internalError "NSError": internalError
@@ -157,13 +162,13 @@ final class ErrorTests: XCTestCase {
let objcError = error.bridgeToObjectiveC let objcError = error.bridgeToObjectiveC
XCTAssertEqual(error, objcError.bridgeToSwift) XCTAssertEqual(error, objcError.bridgeToSwift)
XCTAssertEqual(objcError.domain, CoreStoreErrorDomain) XCTAssertEqual(objcError.domain, CoreStoreErrorDomain)
XCTAssertEqual(objcError.code, CoreStoreErrorCode.InternalError.rawValue) XCTAssertEqual(objcError.code, CoreStoreErrorCode.internalError.rawValue)
XCTAssertEqual(objcError.userInfo, userInfo) XCTAssertEqual(objcError.userInfo as NSDictionary, userInfo)
let objcError2 = objcError.bridgeToSwift.bridgeToObjectiveC let objcError2 = objcError.bridgeToSwift.bridgeToObjectiveC
XCTAssertEqual(error, objcError2.bridgeToSwift) XCTAssertEqual(error, objcError2.bridgeToSwift)
XCTAssertEqual(objcError2.domain, CoreStoreErrorDomain) XCTAssertEqual(objcError2.domain, CoreStoreErrorDomain)
XCTAssertEqual(objcError2.code, CoreStoreErrorCode.InternalError.rawValue) XCTAssertEqual(objcError2.code, CoreStoreErrorCode.internalError.rawValue)
XCTAssertEqual(objcError2.userInfo, userInfo) XCTAssertEqual(objcError2.userInfo as NSDictionary, userInfo)
} }
} }

File diff suppressed because it is too large Load Diff

View File

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

View File

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

File diff suppressed because it is too large Load Diff

View File

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

View File

@@ -2,7 +2,7 @@
// IntoTests.swift // IntoTests.swift
// CoreStore // CoreStore
// //
// Copyright © 2016 John Rommel Estropia // Copyright © 2018 John Rommel Estropia
// //
// Permission is hereby granted, free of charge, to any person obtaining a copy // Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal // of this software and associated documentation files (the "Software"), to deal
@@ -36,7 +36,7 @@ final class IntoTests: XCTestCase {
@objc @objc
dynamic func test_ThatIntoClauseConstants_AreCorrect() { dynamic func test_ThatIntoClauseConstants_AreCorrect() {
XCTAssertEqual(Into<NSManagedObject>.defaultConfigurationName, "PF_DEFAULT_CONFIGURATION_NAME") XCTAssertEqual(DataStack.defaultConfigurationName, "PF_DEFAULT_CONFIGURATION_NAME")
} }
@objc @objc
@@ -44,7 +44,7 @@ final class IntoTests: XCTestCase {
do { do {
let into = Into() let into = Into<NSManagedObject>()
XCTAssert(into.entityClass === NSManagedObject.self) XCTAssert(into.entityClass === NSManagedObject.self)
XCTAssertNil(into.configuration) XCTAssertNil(into.configuration)
XCTAssertTrue(into.inferStoreIfPossible) XCTAssertTrue(into.inferStoreIfPossible)
@@ -58,14 +58,7 @@ final class IntoTests: XCTestCase {
} }
do { do {
let into = Into(TestEntity1) let into = Into(TestEntity1.self)
XCTAssert(into.entityClass === TestEntity1.self)
XCTAssertNil(into.configuration)
XCTAssertTrue(into.inferStoreIfPossible)
}
do {
let into = Into(TestEntity1.self as AnyClass)
XCTAssert(into.entityClass === TestEntity1.self) XCTAssert(into.entityClass === TestEntity1.self)
XCTAssertNil(into.configuration) XCTAssertNil(into.configuration)
XCTAssertTrue(into.inferStoreIfPossible) XCTAssertTrue(into.inferStoreIfPossible)
@@ -84,13 +77,6 @@ final class IntoTests: XCTestCase {
XCTAssertEqual(into.configuration, "Config1") XCTAssertEqual(into.configuration, "Config1")
XCTAssertFalse(into.inferStoreIfPossible) 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 @objc
@@ -98,43 +84,30 @@ final class IntoTests: XCTestCase {
do { do {
let into = Into() let into = Into<NSManagedObject>()
XCTAssertEqual(into, Into())
XCTAssertEqual(into, Into<NSManagedObject>()) XCTAssertEqual(into, Into<NSManagedObject>())
XCTAssertEqual(into, Into(NSManagedObject.self as AnyClass)) XCTAssertEqual(into, Into(NSManagedObject.self))
XCTAssertFalse(into == Into<TestEntity1>()) XCTAssertNotEqual(into, Into<NSManagedObject>(TestEntity1.self))
XCTAssertNotEqual(into, Into<NSManagedObject>("Config1")) XCTAssertNotEqual(into, Into<NSManagedObject>("Config1"))
} }
do { do {
let into = Into<TestEntity1>() 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)
XCTAssertEqual(into, Into<TestEntity1>()) XCTAssertEqual(into, Into<TestEntity1>())
XCTAssertEqual(into, Into(TestEntity1.self as AnyClass)) XCTAssertEqual(into, Into(TestEntity1.self))
XCTAssertFalse(into == Into<TestEntity2>())
XCTAssertNotEqual(into, Into<TestEntity1>("Config1")) XCTAssertNotEqual(into, Into<TestEntity1>("Config1"))
} }
do { do {
let into = Into(TestEntity1.self as AnyClass) let into = Into(TestEntity1.self)
XCTAssert(into == Into<TestEntity1>()) XCTAssert(into == Into<TestEntity1>())
XCTAssertEqual(into, Into(TestEntity1)) XCTAssertEqual(into, Into(TestEntity1.self))
XCTAssertFalse(into == Into<TestEntity2>())
XCTAssertFalse(into == Into<TestEntity1>("Config1")) XCTAssertFalse(into == Into<TestEntity1>("Config1"))
} }
do { do {
let into = Into<TestEntity1>("Config1") let into = Into<TestEntity1>("Config1")
XCTAssertEqual(into, Into(TestEntity1.self, "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")) XCTAssertNotEqual(into, Into<TestEntity1>("Config2"))
} }
do { do {
@@ -142,16 +115,14 @@ final class IntoTests: XCTestCase {
let into = Into(TestEntity1.self, "Config1") let into = Into(TestEntity1.self, "Config1")
XCTAssertEqual(into, Into(TestEntity1.self, "Config1")) XCTAssertEqual(into, Into(TestEntity1.self, "Config1"))
XCTAssertEqual(into, Into<TestEntity1>("Config1")) XCTAssertEqual(into, Into<TestEntity1>("Config1"))
XCTAssertFalse(into == Into<TestEntity2>("Config1"))
XCTAssertNotEqual(into, Into<TestEntity1>("Config2")) XCTAssertNotEqual(into, Into<TestEntity1>("Config2"))
} }
do { do {
let into = Into(TestEntity1.self as AnyClass, "Config1") let into = Into(TestEntity1.self, "Config1")
XCTAssert(into == Into<TestEntity1>("Config1")) XCTAssertEqual(into, Into<TestEntity1>("Config1"))
XCTAssertEqual(into, Into(TestEntity1.self, "Config1")) XCTAssertEqual(into, Into(TestEntity1.self, "Config1"))
XCTAssertFalse(into == Into<TestEntity2>("Config1")) XCTAssertNotEqual(into, Into<TestEntity1>("Config2"))
XCTAssertFalse(into == Into<TestEntity1>("Config2"))
} }
} }
@@ -160,45 +131,9 @@ final class IntoTests: XCTestCase {
do { do {
let into = Into() let into = Into<NSManagedObject>()
let objcInto = into.bridgeToObjectiveC let objcInto = into.bridgeToObjectiveC
XCTAssertEqual(into, objcInto.bridgeToSwift) 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 // ListObserverTests.swift
// CoreStore // CoreStore
// //
// Copyright © 2016 John Rommel Estropia // Copyright © 2018 John Rommel Estropia
// //
// Permission is hereby granted, free of charge, to any person obtaining a copy // Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal // of this software and associated documentation files (the "Software"), to deal
@@ -29,10 +29,9 @@ import XCTest
import CoreStore import CoreStore
#if os(iOS) || os(watchOS) || os(tvOS)
// MARK: - ListObserverTests // MARK: - ListObserverTests
@available(macOS 10.12, *)
class ListObserverTests: BaseTestDataTestCase { class ListObserverTests: BaseTestDataTestCase {
@objc @objc
@@ -42,9 +41,9 @@ class ListObserverTests: BaseTestDataTestCase {
let observer = TestListObserver() let observer = TestListObserver()
let monitor = stack.monitorSectionedList( let monitor = stack.monitorSectionedList(
From(TestEntity1), From<TestEntity1>(),
SectionBy("testBoolean"), SectionBy(#keyPath(TestEntity1.testBoolean)),
OrderBy(.Ascending("testBoolean"), .Ascending("testEntityID")) OrderBy<TestEntity1>(.ascending(#keyPath(TestEntity1.testBoolean)), .ascending(#keyPath(TestEntity1.testEntityID)))
) )
monitor.addObserver(observer) monitor.addObserver(observer)
@@ -54,13 +53,13 @@ class ListObserverTests: BaseTestDataTestCase {
var events = 0 var events = 0
let willChangeExpectation = self.expectationForNotification( let willChangeExpectation = self.expectation(
"listMonitorWillChange:", forNotification: NSNotification.Name(rawValue: "listMonitorWillChange:"),
object: observer, object: observer,
handler: { (note) -> Bool in handler: { (note) -> Bool in
XCTAssertEqual(events, 0) XCTAssertEqual(events, 0)
XCTAssertEqual((note.userInfo ?? [:]), NSDictionary()) XCTAssertEqual((note.userInfo as NSDictionary?) ?? [:], NSDictionary())
defer { defer {
events += 1 events += 1
@@ -68,16 +67,16 @@ class ListObserverTests: BaseTestDataTestCase {
return events == 0 return events == 0
} }
) )
let didInsertSectionExpectation = self.expectationForNotification( let didInsertSectionExpectation = self.expectation(
"listMonitor:didInsertSection:toSectionIndex:", forNotification: NSNotification.Name(rawValue: "listMonitor:didInsertSection:toSectionIndex:"),
object: observer, object: observer,
handler: { (note) -> Bool in handler: { (note) -> Bool in
XCTAssertEqual(events, 1) XCTAssertEqual(events, 1)
XCTAssertEqual( XCTAssertEqual(
(note.userInfo ?? [:]), ((note.userInfo as NSDictionary?) ?? [:]),
[ [
"sectionInfo": monitor.sectionInfoAtIndex(0), "sectionInfo": monitor.sectionInfo(at: 0),
"sectionIndex": 0 "sectionIndex": 0
] as NSDictionary ] as NSDictionary
) )
@@ -88,8 +87,8 @@ class ListObserverTests: BaseTestDataTestCase {
return events == 1 return events == 1
} }
) )
let didInsertObjectExpectation = self.expectationForNotification( let didInsertObjectExpectation = self.expectation(
"listMonitor:didInsertObject:toIndexPath:", forNotification: NSNotification.Name(rawValue: "listMonitor:didInsertObject:toIndexPath:"),
object: observer, object: observer,
handler: { (note) -> Bool in handler: { (note) -> Bool in
@@ -98,21 +97,21 @@ class ListObserverTests: BaseTestDataTestCase {
let userInfo = note.userInfo let userInfo = note.userInfo
XCTAssertNotNil(userInfo) XCTAssertNotNil(userInfo)
XCTAssertEqual( XCTAssertEqual(
Set(((userInfo as? [String: AnyObject]) ?? [:]).keys), Set(userInfo?.keys.map({ $0 as! String }) ?? []),
["indexPath", "object"] ["indexPath", "object"]
) )
let indexPath = userInfo?["indexPath"] as? NSIndexPath let indexPath = userInfo?["indexPath"] as? NSIndexPath
XCTAssertEqual(indexPath?.section, 0) XCTAssertEqual(indexPath?.index(atPosition: 0), 0)
XCTAssertEqual(indexPath?.row, 0) XCTAssertEqual(indexPath?.index(atPosition: 1), 0)
let object = userInfo?["object"] as? TestEntity1 let object = userInfo?["object"] as? TestEntity1
XCTAssertEqual(object?.testBoolean, NSNumber(bool: true)) XCTAssertEqual(object?.testBoolean, NSNumber(value: true))
XCTAssertEqual(object?.testNumber, NSNumber(integer: 1)) XCTAssertEqual(object?.testNumber, NSNumber(value: 1))
XCTAssertEqual(object?.testDecimal, NSDecimalNumber(string: "1")) XCTAssertEqual(object?.testDecimal, NSDecimalNumber(string: "1"))
XCTAssertEqual(object?.testString, "nil:TestEntity1:1") XCTAssertEqual(object?.testString, "nil:TestEntity1:1")
XCTAssertEqual(object?.testData, ("nil:TestEntity1:1" as NSString).dataUsingEncoding(NSUTF8StringEncoding)!) XCTAssertEqual(object?.testData, ("nil:TestEntity1:1" as NSString).data(using: String.Encoding.utf8.rawValue)!)
XCTAssertEqual(object?.testDate, self.dateFormatter.dateFromString("2000-01-01T00:00:00Z")!) XCTAssertEqual(object?.testDate, self.dateFormatter.date(from: "2000-01-01T00:00:00Z")!)
defer { defer {
events += 1 events += 1
@@ -120,12 +119,12 @@ class ListObserverTests: BaseTestDataTestCase {
return events == 2 return events == 2
} }
) )
let didChangeExpectation = self.expectationForNotification( let didChangeExpectation = self.expectation(
"listMonitorDidChange:", forNotification: NSNotification.Name(rawValue: "listMonitorDidChange:"),
object: observer, object: observer,
handler: { (note) -> Bool in handler: { (note) -> Bool in
XCTAssertEqual((note.userInfo ?? [:]), NSDictionary()) XCTAssertEqual((note.userInfo as NSDictionary?) ?? [:], NSDictionary())
defer { defer {
events += 1 events += 1
@@ -133,30 +132,30 @@ class ListObserverTests: BaseTestDataTestCase {
return events == 3 return events == 3
} }
) )
let saveExpectation = self.expectationWithDescription("save") let saveExpectation = self.expectation(description: "save")
stack.beginAsynchronous { (transaction) in stack.perform(
asynchronous: { (transaction) -> Bool 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
switch result { let object = transaction.create(Into<TestEntity1>())
object.testBoolean = NSNumber(value: true)
case .Success(let hasChanges): object.testNumber = NSNumber(value: 1)
XCTAssertTrue(hasChanges) object.testDecimal = NSDecimalNumber(string: "1")
saveExpectation.fulfill() object.testString = "nil:TestEntity1:1"
object.testData = ("nil:TestEntity1:1" as NSString).data(using: String.Encoding.utf8.rawValue)!
case .Failure: object.testDate = self.dateFormatter.date(from: "2000-01-01T00:00:00Z")!
XCTFail()
} return transaction.hasChanges
},
success: { (hasChanges) in
XCTAssertTrue(hasChanges)
saveExpectation.fulfill()
},
failure: { _ in
XCTFail()
} }
} )
self.waitAndCheckExpectations() self.waitAndCheckExpectations()
} }
} }
@@ -170,28 +169,28 @@ class ListObserverTests: BaseTestDataTestCase {
let observer = TestListObserver() let observer = TestListObserver()
let monitor = stack.monitorSectionedList( let monitor = stack.monitorSectionedList(
From(TestEntity1), From<TestEntity1>(),
SectionBy("testBoolean"), SectionBy(#keyPath(TestEntity1.testBoolean)),
OrderBy(.Ascending("testBoolean"), .Ascending("testEntityID")) OrderBy<TestEntity1>(.ascending(#keyPath(TestEntity1.testBoolean)), .ascending(#keyPath(TestEntity1.testEntityID)))
) )
monitor.addObserver(observer) monitor.addObserver(observer)
XCTAssertTrue(monitor.hasSections()) XCTAssertTrue(monitor.hasSections())
XCTAssertEqual(monitor.numberOfSections(), 2) XCTAssertEqual(monitor.numberOfSections(), 2)
XCTAssertTrue(monitor.hasObjects()) XCTAssertTrue(monitor.hasObjects())
XCTAssertTrue(monitor.hasObjectsInSection(0)) XCTAssertTrue(monitor.hasObjects(in: 0))
XCTAssertEqual(monitor.numberOfObjectsInSection(0), 2) XCTAssertEqual(monitor.numberOfObjects(in: 0), 2)
XCTAssertEqual(monitor.numberOfObjectsInSection(1), 3) XCTAssertEqual(monitor.numberOfObjects(in: 1), 3)
var events = 0 var events = 0
let willChangeExpectation = self.expectationForNotification( let willChangeExpectation = self.expectation(
"listMonitorWillChange:", forNotification: NSNotification.Name(rawValue: "listMonitorWillChange:"),
object: observer, object: observer,
handler: { (note) -> Bool in handler: { (note) -> Bool in
XCTAssertEqual(events, 0) XCTAssertEqual(events, 0)
XCTAssertEqual((note.userInfo ?? [:]), NSDictionary()) XCTAssertEqual((note.userInfo as NSDictionary?) ?? [:], NSDictionary())
defer { defer {
events += 1 events += 1
@@ -199,67 +198,65 @@ class ListObserverTests: BaseTestDataTestCase {
return events == 0 return events == 0
} }
) )
for _ in 1 ... 2 {
let didUpdateObjectExpectation = self.expectation(
let didUpdateObjectExpectation = self.expectationForNotification( forNotification: NSNotification.Name(rawValue: "listMonitor:didUpdateObject:atIndexPath:"),
"listMonitor:didUpdateObject:atIndexPath:", object: observer,
object: observer, handler: { (note) -> Bool in
handler: { (note) -> Bool in
XCTAssert(events == 1 || events == 2)
let userInfo = note.userInfo
XCTAssertNotNil(userInfo)
XCTAssertEqual(
Set(userInfo?.keys.map({ $0 as! String }) ?? []),
["indexPath", "object"]
)
let indexPath = userInfo?["indexPath"] as? NSIndexPath
let object = userInfo?["object"] as? TestEntity1
switch object?.testEntityID {
XCTAssert(events == 1 || events == 2) case NSNumber(value: 101)?:
XCTAssertEqual(indexPath?.index(atPosition: 0), 1)
XCTAssertEqual(indexPath?.index(atPosition: 1), 0)
let userInfo = note.userInfo XCTAssertEqual(object?.testBoolean, NSNumber(value: true))
XCTAssertNotNil(userInfo) XCTAssertEqual(object?.testNumber, NSNumber(value: 11))
XCTAssertEqual( XCTAssertEqual(object?.testDecimal, NSDecimalNumber(string: "11"))
Set(((userInfo as? [String: AnyObject]) ?? [:]).keys), XCTAssertEqual(object?.testString, "nil:TestEntity1:11")
["indexPath", "object"] 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 indexPath = userInfo?["indexPath"] as? NSIndexPath case NSNumber(value: 102)?:
let object = userInfo?["object"] as? TestEntity1 XCTAssertEqual(indexPath?.index(atPosition: 0), 0)
XCTAssertEqual(indexPath?.index(atPosition: 1), 0)
switch object?.testEntityID { XCTAssertEqual(object?.testBoolean, NSNumber(value: false))
XCTAssertEqual(object?.testNumber, NSNumber(value: 22))
case NSNumber(integer: 101)?: XCTAssertEqual(object?.testDecimal, NSDecimalNumber(string: "22"))
XCTAssertEqual(indexPath?.section, 1) XCTAssertEqual(object?.testString, "nil:TestEntity1:22")
XCTAssertEqual(indexPath?.row, 0) 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")!)
XCTAssertEqual(object?.testBoolean, NSNumber(bool: true))
XCTAssertEqual(object?.testNumber, NSNumber(integer: 11)) default:
XCTAssertEqual(object?.testDecimal, NSDecimalNumber(string: "11")) XCTFail()
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 {
}
let didChangeExpectation = self.expectationForNotification( events += 1
"listMonitorDidChange:", }
return events == 1 || events == 2
}
)
let didChangeExpectation = self.expectation(
forNotification: NSNotification.Name(rawValue: "listMonitorDidChange:"),
object: observer, object: observer,
handler: { (note) -> Bool in handler: { (note) -> Bool in
XCTAssertEqual(events, 3) XCTAssertEqual(events, 3)
XCTAssertEqual((note.userInfo ?? [:]), NSDictionary()) XCTAssertEqual((note.userInfo as NSDictionary?) ?? [:], NSDictionary())
defer { defer {
events += 1 events += 1
@@ -267,50 +264,50 @@ class ListObserverTests: BaseTestDataTestCase {
return events == 3 return events == 3
} }
) )
let saveExpectation = self.expectationWithDescription("save") let saveExpectation = self.expectation(description: "save")
stack.beginAsynchronous { (transaction) in stack.perform(
asynchronous: { (transaction) -> Bool in
if let object = transaction.fetchOne(
From(TestEntity1),
Where("testEntityID", isEqualTo: 101)) {
object.testNumber = NSNumber(integer: 11) if let object = try transaction.fetchOne(
object.testDecimal = NSDecimalNumber(string: "11") From<TestEntity1>(),
object.testString = "nil:TestEntity1:11" Where<TestEntity1>(#keyPath(TestEntity1.testEntityID), isEqualTo: 101)) {
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): object.testNumber = NSNumber(value: 11)
XCTAssertTrue(hasChanges) object.testDecimal = NSDecimalNumber(string: "11")
saveExpectation.fulfill() 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 {
case .Failure:
XCTFail() 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() self.waitAndCheckExpectations()
} }
} }
@@ -324,21 +321,21 @@ class ListObserverTests: BaseTestDataTestCase {
let observer = TestListObserver() let observer = TestListObserver()
let monitor = stack.monitorSectionedList( let monitor = stack.monitorSectionedList(
From(TestEntity1), From<TestEntity1>(),
SectionBy("testBoolean"), SectionBy(#keyPath(TestEntity1.testBoolean)),
OrderBy(.Ascending("testBoolean"), .Ascending("testEntityID")) OrderBy<TestEntity1>(.ascending(#keyPath(TestEntity1.testBoolean)), .ascending(#keyPath(TestEntity1.testEntityID)))
) )
monitor.addObserver(observer) monitor.addObserver(observer)
var events = 0 var events = 0
let willChangeExpectation = self.expectationForNotification( let willChangeExpectation = self.expectation(
"listMonitorWillChange:", forNotification: NSNotification.Name(rawValue: "listMonitorWillChange:"),
object: observer, object: observer,
handler: { (note) -> Bool in handler: { (note) -> Bool in
XCTAssertEqual(events, 0) XCTAssertEqual(events, 0)
XCTAssertEqual((note.userInfo ?? [:]), NSDictionary()) XCTAssertEqual((note.userInfo as NSDictionary?) ?? [:], NSDictionary())
defer { defer {
events += 1 events += 1
@@ -346,8 +343,8 @@ class ListObserverTests: BaseTestDataTestCase {
return events == 0 return events == 0
} }
) )
let didMoveObjectExpectation = self.expectationForNotification( let didMoveObjectExpectation = self.expectation(
"listMonitor:didMoveObject:fromIndexPath:toIndexPath:", forNotification: NSNotification.Name(rawValue: "listMonitor:didMoveObject:fromIndexPath:toIndexPath:"),
object: observer, object: observer,
handler: { (note) -> Bool in handler: { (note) -> Bool in
@@ -356,21 +353,21 @@ class ListObserverTests: BaseTestDataTestCase {
let userInfo = note.userInfo let userInfo = note.userInfo
XCTAssertNotNil(userInfo) XCTAssertNotNil(userInfo)
XCTAssertEqual( XCTAssertEqual(
Set(((userInfo as? [String: AnyObject]) ?? [:]).keys), Set(userInfo?.keys.map({ $0 as! String }) ?? []),
["fromIndexPath", "toIndexPath", "object"] ["fromIndexPath", "toIndexPath", "object"]
) )
let fromIndexPath = userInfo?["fromIndexPath"] as? NSIndexPath let fromIndexPath = userInfo?["fromIndexPath"] as? NSIndexPath
XCTAssertEqual(fromIndexPath?.section, 0) XCTAssertEqual(fromIndexPath?.index(atPosition: 0), 0)
XCTAssertEqual(fromIndexPath?.row, 0) XCTAssertEqual(fromIndexPath?.index(atPosition: 1), 0)
let toIndexPath = userInfo?["toIndexPath"] as? NSIndexPath let toIndexPath = userInfo?["toIndexPath"] as? NSIndexPath
XCTAssertEqual(toIndexPath?.section, 1) XCTAssertEqual(toIndexPath?.index(atPosition: 0), 1)
XCTAssertEqual(toIndexPath?.row, 1) XCTAssertEqual(toIndexPath?.index(atPosition: 1), 1)
let object = userInfo?["object"] as? TestEntity1 let object = userInfo?["object"] as? TestEntity1
XCTAssertEqual(object?.testEntityID, NSNumber(integer: 102)) XCTAssertEqual(object?.testEntityID, NSNumber(value: 102))
XCTAssertEqual(object?.testBoolean, NSNumber(bool: true)) XCTAssertEqual(object?.testBoolean, NSNumber(value: true))
defer { defer {
@@ -379,13 +376,13 @@ class ListObserverTests: BaseTestDataTestCase {
return events == 1 return events == 1
} }
) )
let didChangeExpectation = self.expectationForNotification( let didChangeExpectation = self.expectation(
"listMonitorDidChange:", forNotification: NSNotification.Name(rawValue: "listMonitorDidChange:"),
object: observer, object: observer,
handler: { (note) -> Bool in handler: { (note) -> Bool in
XCTAssertEqual(events, 2) XCTAssertEqual(events, 2)
XCTAssertEqual((note.userInfo ?? [:]), NSDictionary()) XCTAssertEqual((note.userInfo as NSDictionary?) ?? [:], NSDictionary())
defer { defer {
events += 1 events += 1
@@ -393,32 +390,32 @@ class ListObserverTests: BaseTestDataTestCase {
return events == 2 return events == 2
} }
) )
let saveExpectation = self.expectationWithDescription("save") let saveExpectation = self.expectation(description: "save")
stack.beginAsynchronous { (transaction) in stack.perform(
asynchronous: { (transaction) -> Bool in
if let object = transaction.fetchOne(
From(TestEntity1),
Where("testEntityID", isEqualTo: 102)) {
object.testBoolean = NSNumber(bool: true) if let object = try transaction.fetchOne(
} From<TestEntity1>(),
else { 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() XCTFail()
} }
transaction.commit { (result) in )
switch result {
case .Success(let hasChanges):
XCTAssertTrue(hasChanges)
saveExpectation.fulfill()
case .Failure:
XCTFail()
}
}
}
self.waitAndCheckExpectations() self.waitAndCheckExpectations()
} }
} }
@@ -432,21 +429,21 @@ class ListObserverTests: BaseTestDataTestCase {
let observer = TestListObserver() let observer = TestListObserver()
let monitor = stack.monitorSectionedList( let monitor = stack.monitorSectionedList(
From(TestEntity1), From<TestEntity1>(),
SectionBy("testBoolean"), SectionBy(#keyPath(TestEntity1.testBoolean)),
OrderBy(.Ascending("testBoolean"), .Ascending("testEntityID")) OrderBy<TestEntity1>(.ascending(#keyPath(TestEntity1.testBoolean)), .ascending(#keyPath(TestEntity1.testEntityID)))
) )
monitor.addObserver(observer) monitor.addObserver(observer)
var events = 0 var events = 0
let willChangeExpectation = self.expectationForNotification( let willChangeExpectation = self.expectation(
"listMonitorWillChange:", forNotification: NSNotification.Name(rawValue: "listMonitorWillChange:"),
object: observer, object: observer,
handler: { (note) -> Bool in handler: { (note) -> Bool in
XCTAssertEqual(events, 0) XCTAssertEqual(events, 0)
XCTAssertEqual((note.userInfo ?? [:]), NSDictionary()) XCTAssertEqual((note.userInfo as NSDictionary?) ?? [:], NSDictionary())
defer { defer {
events += 1 events += 1
@@ -454,40 +451,37 @@ class ListObserverTests: BaseTestDataTestCase {
return events == 0 return events == 0
} }
) )
for _ in 1 ... 2 { let didUpdateObjectExpectation = self.expectation(
forNotification: NSNotification.Name(rawValue: "listMonitor:didDeleteObject:fromIndexPath:"),
let didUpdateObjectExpectation = self.expectationForNotification( object: observer,
"listMonitor:didDeleteObject:fromIndexPath:", handler: { (note) -> Bool in
object: observer,
handler: { (note) -> Bool in XCTAssert(events == 1 || events == 2)
let userInfo = note.userInfo
XCTAssertNotNil(userInfo)
XCTAssertEqual(
Set(userInfo?.keys.map({ $0 as! String }) ?? []),
["indexPath", "object"]
)
let indexPath = userInfo?["indexPath"] as? NSIndexPath
XCTAssertEqual(indexPath?.section, 0)
XCTAssert(indexPath?.index(atPosition: 1) == 0 || indexPath?.index(atPosition: 1) == 1)
let object = userInfo?["object"] as? TestEntity1
XCTAssertEqual(object?.isDeleted, true)
defer {
XCTAssert(events == 1 || events == 2) events += 1
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
} }
let didDeleteSectionExpectation = self.expectationForNotification( )
"listMonitor:didDeleteSection:fromSectionIndex:", let didDeleteSectionExpectation = self.expectation(
forNotification: NSNotification.Name(rawValue: "listMonitor:didDeleteSection:fromSectionIndex:"),
object: observer, object: observer,
handler: { (note) -> Bool in handler: { (note) -> Bool in
@@ -496,16 +490,16 @@ class ListObserverTests: BaseTestDataTestCase {
let userInfo = note.userInfo let userInfo = note.userInfo
XCTAssertNotNil(userInfo) XCTAssertNotNil(userInfo)
XCTAssertEqual( XCTAssertEqual(
Set(((userInfo as? [String: AnyObject]) ?? [:]).keys), Set(userInfo?.keys.map({ $0 as! String }) ?? []),
["sectionInfo", "sectionIndex"] ["sectionInfo", "sectionIndex"]
) )
let sectionInfo = userInfo?["sectionInfo"] let sectionInfo = userInfo?["sectionInfo"] as? NSFetchedResultsSectionInfo
XCTAssertNotNil(sectionInfo) XCTAssertNotNil(sectionInfo)
XCTAssertEqual(sectionInfo?.name, "0") XCTAssertEqual(sectionInfo?.name, "0")
let sectionIndex = userInfo?["sectionIndex"] let sectionIndex = userInfo?["sectionIndex"]
XCTAssertEqual(sectionIndex as? NSNumber, NSNumber(integer: 0)) XCTAssertEqual(sectionIndex as? NSNumber, NSNumber(value: 0))
defer { defer {
@@ -514,13 +508,13 @@ class ListObserverTests: BaseTestDataTestCase {
return events == 3 return events == 3
} }
) )
let didChangeExpectation = self.expectationForNotification( let didChangeExpectation = self.expectation(
"listMonitorDidChange:", forNotification: NSNotification.Name(rawValue: "listMonitorDidChange:"),
object: observer, object: observer,
handler: { (note) -> Bool in handler: { (note) -> Bool in
XCTAssertEqual(events, 4) XCTAssertEqual(events, 4)
XCTAssertEqual((note.userInfo ?? [:]), NSDictionary()) XCTAssertEqual((note.userInfo as NSDictionary?) ?? [:], NSDictionary())
defer { defer {
events += 1 events += 1
@@ -528,26 +522,27 @@ class ListObserverTests: BaseTestDataTestCase {
return events == 4 return events == 4
} }
) )
let saveExpectation = self.expectationWithDescription("save") let saveExpectation = self.expectation(description: "save")
stack.beginAsynchronous { (transaction) in stack.perform(
asynchronous: { (transaction) -> Bool in
transaction.deleteAll(
From(TestEntity1),
Where("testBoolean", isEqualTo: false)
)
transaction.commit { (result) in
switch result { let count = try transaction.deleteAll(
From<TestEntity1>(),
case .Success(let hasChanges): Where<TestEntity1>(#keyPath(TestEntity1.testBoolean), isEqualTo: false)
XCTAssertTrue(hasChanges) )
saveExpectation.fulfill() XCTAssertEqual(count, 2)
return transaction.hasChanges
case .Failure: },
XCTFail() success: { (hasChanges) in
}
XCTAssertTrue(hasChanges)
saveExpectation.fulfill()
},
failure: { _ in
XCTFail()
} }
} )
self.waitAndCheckExpectations() self.waitAndCheckExpectations()
} }
} }
@@ -556,43 +551,44 @@ class ListObserverTests: BaseTestDataTestCase {
// MARK: TestListObserver // MARK: TestListObserver
@available(macOS 10.12, *)
class TestListObserver: ListSectionObserver { class TestListObserver: ListSectionObserver {
// MARK: ListObserver // MARK: ListObserver
typealias ListEntityType = TestEntity1 typealias ListEntityType = TestEntity1
func listMonitorWillChange(monitor: ListMonitor<TestEntity1>) { func listMonitorWillChange(_ monitor: ListMonitor<TestEntity1>) {
NSNotificationCenter.defaultCenter().postNotificationName( NotificationCenter.default.post(
"listMonitorWillChange:", name: Notification.Name(rawValue: "listMonitorWillChange:"),
object: self, object: self,
userInfo: [:] userInfo: [:]
) )
} }
func listMonitorDidChange(monitor: ListMonitor<TestEntity1>) { func listMonitorDidChange(_ monitor: ListMonitor<TestEntity1>) {
NSNotificationCenter.defaultCenter().postNotificationName( NotificationCenter.default.post(
"listMonitorDidChange:", name: Notification.Name(rawValue: "listMonitorDidChange:"),
object: self, object: self,
userInfo: [:] userInfo: [:]
) )
} }
func listMonitorWillRefetch(monitor: ListMonitor<TestEntity1>) { func listMonitorWillRefetch(_ monitor: ListMonitor<TestEntity1>) {
NSNotificationCenter.defaultCenter().postNotificationName( NotificationCenter.default.post(
"listMonitorWillRefetch:", name: Notification.Name(rawValue: "listMonitorWillRefetch:"),
object: self, object: self,
userInfo: [:] userInfo: [:]
) )
} }
func listMonitorDidRefetch(monitor: ListMonitor<TestEntity1>) { func listMonitorDidRefetch(_ monitor: ListMonitor<TestEntity1>) {
NSNotificationCenter.defaultCenter().postNotificationName( NotificationCenter.default.post(
"listMonitorDidRefetch:", name: Notification.Name(rawValue: "listMonitorDidRefetch:"),
object: self, object: self,
userInfo: [:] userInfo: [:]
) )
@@ -601,10 +597,10 @@ class TestListObserver: ListSectionObserver {
// MARK: ListObjectObserver // MARK: ListObjectObserver
func listMonitor(monitor: ListMonitor<TestEntity1>, didInsertObject object: TestEntity1, toIndexPath indexPath: NSIndexPath) { func listMonitor(_ monitor: ListMonitor<TestEntity1>, didInsertObject object: TestEntity1, toIndexPath indexPath: IndexPath) {
NSNotificationCenter.defaultCenter().postNotificationName( NotificationCenter.default.post(
"listMonitor:didInsertObject:toIndexPath:", name: Notification.Name(rawValue: "listMonitor:didInsertObject:toIndexPath:"),
object: self, object: self,
userInfo: [ userInfo: [
"object": object, "object": object,
@@ -613,10 +609,10 @@ class TestListObserver: ListSectionObserver {
) )
} }
func listMonitor(monitor: ListMonitor<TestEntity1>, didDeleteObject object: TestEntity1, fromIndexPath indexPath: NSIndexPath) { func listMonitor(_ monitor: ListMonitor<TestEntity1>, didDeleteObject object: TestEntity1, fromIndexPath indexPath: IndexPath) {
NSNotificationCenter.defaultCenter().postNotificationName( NotificationCenter.default.post(
"listMonitor:didDeleteObject:fromIndexPath:", name: Notification.Name(rawValue: "listMonitor:didDeleteObject:fromIndexPath:"),
object: self, object: self,
userInfo: [ userInfo: [
"object": object, "object": object,
@@ -625,10 +621,10 @@ class TestListObserver: ListSectionObserver {
) )
} }
func listMonitor(monitor: ListMonitor<TestEntity1>, didUpdateObject object: TestEntity1, atIndexPath indexPath: NSIndexPath) { func listMonitor(_ monitor: ListMonitor<TestEntity1>, didUpdateObject object: TestEntity1, atIndexPath indexPath: IndexPath) {
NSNotificationCenter.defaultCenter().postNotificationName( NotificationCenter.default.post(
"listMonitor:didUpdateObject:atIndexPath:", name: Notification.Name(rawValue: "listMonitor:didUpdateObject:atIndexPath:"),
object: self, object: self,
userInfo: [ userInfo: [
"object": object, "object": object,
@@ -638,10 +634,10 @@ class TestListObserver: ListSectionObserver {
} }
func listMonitor(monitor: ListMonitor<TestEntity1>, didMoveObject object: TestEntity1, fromIndexPath: NSIndexPath, toIndexPath: NSIndexPath) { func listMonitor(_ monitor: ListMonitor<TestEntity1>, didMoveObject object: TestEntity1, fromIndexPath: IndexPath, toIndexPath: IndexPath) {
NSNotificationCenter.defaultCenter().postNotificationName( NotificationCenter.default.post(
"listMonitor:didMoveObject:fromIndexPath:toIndexPath:", name: Notification.Name(rawValue: "listMonitor:didMoveObject:fromIndexPath:toIndexPath:"),
object: self, object: self,
userInfo: [ userInfo: [
"object": object, "object": object,
@@ -654,10 +650,10 @@ class TestListObserver: ListSectionObserver {
// MARK: 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) {
NSNotificationCenter.defaultCenter().postNotificationName( NotificationCenter.default.post(
"listMonitor:didInsertSection:toSectionIndex:", name: Notification.Name(rawValue: "listMonitor:didInsertSection:toSectionIndex:"),
object: self, object: self,
userInfo: [ userInfo: [
"sectionInfo": sectionInfo, "sectionInfo": sectionInfo,
@@ -666,10 +662,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) {
NSNotificationCenter.defaultCenter().postNotificationName( NotificationCenter.default.post(
"listMonitor:didDeleteSection:fromSectionIndex:", name: Notification.Name(rawValue: "listMonitor:didDeleteSection:fromSectionIndex:"),
object: self, object: self,
userInfo: [ userInfo: [
"sectionInfo": sectionInfo, "sectionInfo": sectionInfo,
@@ -678,5 +674,3 @@ class TestListObserver: ListSectionObserver {
) )
} }
} }
#endif

View File

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

View File

@@ -1,23 +1,23 @@
<?xml version="1.0" encoding="UTF-8" standalone="yes"?> <?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<model userDefinedModelVersionIdentifier="" type="com.apple.IDECoreDataModeler.DataModel" documentVersion="1.0" lastSavedToolsVersion="10174" systemVersion="15F34" minimumToolsVersion="Xcode 4.3"> <model type="com.apple.IDECoreDataModeler.DataModel" documentVersion="1.0" lastSavedToolsVersion="11759" systemVersion="16C67" minimumToolsVersion="Xcode 4.3" sourceLanguage="Objective-C" userDefinedModelVersionIdentifier="">
<entity name="TestEntity1AAA" representedClassName="CoreStoreTests.TestEntity1" syncable="YES"> <entity name="TestEntity1AAA" representedClassName="CoreStoreTests.TestEntity1" syncable="YES">
<attribute name="testBoolean" optional="YES" attributeType="Boolean" syncable="YES"/> <attribute name="testBoolean" optional="YES" attributeType="Boolean" usesScalarValueType="NO" syncable="YES"/>
<attribute name="testData" optional="YES" attributeType="Binary" syncable="YES"/> <attribute name="testData" optional="YES" attributeType="Binary" syncable="YES"/>
<attribute name="testDate" optional="YES" attributeType="Date" syncable="YES"/> <attribute name="testDate" optional="YES" attributeType="Date" usesScalarValueType="NO" syncable="YES"/>
<attribute name="testDecimal" optional="YES" attributeType="Decimal" syncable="YES"/> <attribute name="testDecimal" optional="YES" attributeType="Decimal" syncable="YES"/>
<attribute name="testEntityID" optional="YES" attributeType="Integer 64" syncable="YES"/> <attribute name="testEntityID" optional="YES" attributeType="Integer 64" usesScalarValueType="NO" syncable="YES"/>
<attribute name="testNil" optional="YES" attributeType="String" syncable="YES"/> <attribute name="testNil" optional="YES" attributeType="String" syncable="YES"/>
<attribute name="testNumber" optional="YES" attributeType="Integer 32" syncable="YES"/> <attribute name="testNumber" optional="YES" attributeType="Integer 32" usesScalarValueType="NO" syncable="YES"/>
<attribute name="testString" optional="YES" attributeType="String" syncable="YES"/> <attribute name="testString" optional="YES" attributeType="String" syncable="YES"/>
</entity> </entity>
<entity name="TestEntity2" representedClassName="CoreStoreTests.TestEntity2" syncable="YES"> <entity name="TestEntity2" representedClassName="CoreStoreTests.TestEntity2" syncable="YES">
<attribute name="testBoolean" optional="YES" attributeType="Boolean" syncable="YES"/> <attribute name="testBoolean" optional="YES" attributeType="Boolean" usesScalarValueType="NO" syncable="YES"/>
<attribute name="testData" optional="YES" attributeType="Binary" syncable="YES"/> <attribute name="testData" optional="YES" attributeType="Binary" syncable="YES"/>
<attribute name="testDate" optional="YES" attributeType="Date" syncable="YES"/> <attribute name="testDate" optional="YES" attributeType="Date" usesScalarValueType="NO" syncable="YES"/>
<attribute name="testDecimal" optional="YES" attributeType="Decimal" syncable="YES"/> <attribute name="testDecimal" optional="YES" attributeType="Decimal" syncable="YES"/>
<attribute name="testEntityID" optional="YES" attributeType="Integer 64" syncable="YES"/> <attribute name="testEntityID" optional="YES" attributeType="Integer 64" usesScalarValueType="NO" syncable="YES"/>
<attribute name="testNil" optional="YES" attributeType="String" syncable="YES"/> <attribute name="testNil" optional="YES" attributeType="String" syncable="YES"/>
<attribute name="testNumber" optional="YES" attributeType="Integer 32" syncable="YES"/> <attribute name="testNumber" optional="YES" attributeType="Integer 32" usesScalarValueType="NO" syncable="YES"/>
<attribute name="testString" optional="YES" attributeType="String" syncable="YES"/> <attribute name="testString" optional="YES" attributeType="String" syncable="YES"/>
</entity> </entity>
<configuration name="Config1"> <configuration name="Config1">

View File

@@ -2,7 +2,7 @@
// ObjectObserverTests.swift // ObjectObserverTests.swift
// CoreStore // CoreStore
// //
// Copyright © 2016 John Rommel Estropia // Copyright © 2018 John Rommel Estropia
// //
// Permission is hereby granted, free of charge, to any person obtaining a copy // Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal // of this software and associated documentation files (the "Software"), to deal
@@ -29,10 +29,9 @@ import XCTest
import CoreStore import CoreStore
#if os(iOS) || os(watchOS) || os(tvOS)
// MARK: - ObjectObserverTests // MARK: - ObjectObserverTests
@available(macOS 10.12, *)
class ObjectObserverTests: BaseTestDataTestCase { class ObjectObserverTests: BaseTestDataTestCase {
@objc @objc
@@ -42,9 +41,9 @@ class ObjectObserverTests: BaseTestDataTestCase {
self.prepareTestDataForStack(stack) self.prepareTestDataForStack(stack)
guard let object = stack.fetchOne( guard let object = try stack.fetchOne(
From(TestEntity1), From<TestEntity1>(),
Where("testEntityID", isEqualTo: 101)) else { Where<TestEntity1>(#keyPath(TestEntity1.testEntityID), isEqualTo: 101)) else {
XCTFail() XCTFail()
return return
@@ -58,14 +57,14 @@ class ObjectObserverTests: BaseTestDataTestCase {
var events = 0 var events = 0
let willUpdateExpectation = self.expectationForNotification( let willUpdateExpectation = self.expectation(
"objectMonitor:willUpdateObject:", forNotification: NSNotification.Name(rawValue: "objectMonitor:willUpdateObject:"),
object: observer, object: observer,
handler: { (note) -> Bool in handler: { (note) -> Bool in
XCTAssertEqual(events, 0) XCTAssertEqual(events, 0)
XCTAssertEqual( XCTAssertEqual(
(note.userInfo ?? [:]), ((note.userInfo as NSDictionary?) ?? [:]),
["object": object] as NSDictionary ["object": object] as NSDictionary
) )
defer { defer {
@@ -75,26 +74,26 @@ class ObjectObserverTests: BaseTestDataTestCase {
return events == 0 return events == 0
} }
) )
let didUpdateExpectation = self.expectationForNotification( let didUpdateExpectation = self.expectation(
"objectMonitor:didUpdateObject:changedPersistentKeys:", forNotification: NSNotification.Name(rawValue: "objectMonitor:didUpdateObject:changedPersistentKeys:"),
object: observer, object: observer,
handler: { (note) -> Bool in handler: { (note) -> Bool in
XCTAssertEqual(events, 1) XCTAssertEqual(events, 1)
XCTAssertEqual( XCTAssertEqual(
(note.userInfo ?? [:]), ((note.userInfo as NSDictionary?) ?? [:]),
[ [
"object": object, "object": object,
"changedPersistentKeys": Set( "changedPersistentKeys": Set(
[ [
"testNumber", #keyPath(TestEntity1.testNumber),
"testString" #keyPath(TestEntity1.testString)
] ]
) )
] as NSDictionary ] as NSDictionary
) )
let object = note.userInfo?["object"] as? TestEntity1 let object = note.userInfo?["object"] as? TestEntity1
XCTAssertEqual(object?.testNumber, NSNumber(integer: 10)) XCTAssertEqual(object?.testNumber, NSNumber(value: 10))
XCTAssertEqual(object?.testString, "nil:TestEntity1:10") XCTAssertEqual(object?.testString, "nil:TestEntity1:10")
defer { defer {
@@ -104,30 +103,30 @@ class ObjectObserverTests: BaseTestDataTestCase {
return events == 1 return events == 1
} }
) )
let saveExpectation = self.expectationWithDescription("save") let saveExpectation = self.expectation(description: "save")
stack.beginAsynchronous { (transaction) in stack.perform(
asynchronous: { (transaction) -> Bool in
guard let object = transaction.edit(object) else {
guard let object = transaction.edit(object) else {
XCTFail()
try transaction.cancel()
}
object.testNumber = NSNumber(value: 10)
object.testString = "nil:TestEntity1:10"
return transaction.hasChanges
},
success: { (hasChanges) in
XCTAssertTrue(hasChanges)
saveExpectation.fulfill()
},
failure: { _ in
XCTFail() XCTFail()
return
} }
object.testNumber = NSNumber(integer: 10) )
object.testString = "nil:TestEntity1:10"
transaction.commit { (result) in
switch result {
case .Success(let hasChanges):
XCTAssertTrue(hasChanges)
saveExpectation.fulfill()
case .Failure:
XCTFail()
}
}
}
self.waitAndCheckExpectations() self.waitAndCheckExpectations()
} }
} }
@@ -139,9 +138,9 @@ class ObjectObserverTests: BaseTestDataTestCase {
self.prepareTestDataForStack(stack) self.prepareTestDataForStack(stack)
guard let object = stack.fetchOne( guard let object = try stack.fetchOne(
From(TestEntity1), From<TestEntity1>(),
Where("testEntityID", isEqualTo: 101)) else { Where<TestEntity1>(#keyPath(TestEntity1.testEntityID), isEqualTo: 101)) else {
XCTFail() XCTFail()
return return
@@ -155,14 +154,14 @@ class ObjectObserverTests: BaseTestDataTestCase {
var events = 0 var events = 0
let didDeleteExpectation = self.expectationForNotification( let didDeleteExpectation = self.expectation(
"objectMonitor:didDeleteObject:", forNotification: NSNotification.Name(rawValue: "objectMonitor:didDeleteObject:"),
object: observer, object: observer,
handler: { (note) -> Bool in handler: { (note) -> Bool in
XCTAssertEqual(events, 0) XCTAssertEqual(events, 0)
XCTAssertEqual( XCTAssertEqual(
(note.userInfo ?? [:]), ((note.userInfo as NSDictionary?) ?? [:]),
["object": object] as NSDictionary ["object": object] as NSDictionary
) )
defer { defer {
@@ -172,30 +171,30 @@ class ObjectObserverTests: BaseTestDataTestCase {
return events == 0 return events == 0
} }
) )
let saveExpectation = self.expectationWithDescription("save") let saveExpectation = self.expectation(description: "save")
stack.beginAsynchronous { (transaction) in stack.perform(
asynchronous: { (transaction) -> Bool in
guard let object = transaction.edit(object) else {
guard let object = transaction.edit(object) else {
XCTFail()
try transaction.cancel()
}
transaction.delete(object)
return transaction.hasChanges
},
success: { (hasChanges) in
XCTAssertTrue(hasChanges)
XCTAssertTrue(monitor.isObjectDeleted)
saveExpectation.fulfill()
},
failure: { _ in
XCTFail() XCTFail()
return
} }
transaction.delete(object) )
transaction.commit { (result) in
switch result {
case .Success(let hasChanges):
XCTAssertTrue(hasChanges)
XCTAssertTrue(monitor.isObjectDeleted)
saveExpectation.fulfill()
case .Failure:
XCTFail()
}
}
}
self.waitAndCheckExpectations() self.waitAndCheckExpectations()
} }
} }
@@ -204,14 +203,15 @@ class ObjectObserverTests: BaseTestDataTestCase {
// MARK: TestObjectObserver // MARK: TestObjectObserver
@available(macOS 10.12, *)
class TestObjectObserver: ObjectObserver { class TestObjectObserver: ObjectObserver {
typealias ObjectEntityType = TestEntity1 typealias ObjectEntityType = TestEntity1
func objectMonitor(monitor: ObjectMonitor<TestEntity1>, willUpdateObject object: TestEntity1) { func objectMonitor(_ monitor: ObjectMonitor<TestEntity1>, willUpdateObject object: TestEntity1) {
NSNotificationCenter.defaultCenter().postNotificationName( NotificationCenter.default.post(
"objectMonitor:willUpdateObject:", name: Notification.Name(rawValue: "objectMonitor:willUpdateObject:"),
object: self, object: self,
userInfo: [ userInfo: [
"object": object "object": object
@@ -219,10 +219,10 @@ class TestObjectObserver: ObjectObserver {
) )
} }
func objectMonitor(monitor: ObjectMonitor<TestEntity1>, didUpdateObject object: TestEntity1, changedPersistentKeys: Set<KeyPath>) { func objectMonitor(_ monitor: ObjectMonitor<TestEntity1>, didUpdateObject object: TestEntity1, changedPersistentKeys: Set<String>) {
NSNotificationCenter.defaultCenter().postNotificationName( NotificationCenter.default.post(
"objectMonitor:didUpdateObject:changedPersistentKeys:", name: NSNotification.Name(rawValue: "objectMonitor:didUpdateObject:changedPersistentKeys:"),
object: self, object: self,
userInfo: [ userInfo: [
"object": object, "object": object,
@@ -231,10 +231,10 @@ class TestObjectObserver: ObjectObserver {
) )
} }
func objectMonitor(monitor: ObjectMonitor<TestEntity1>, didDeleteObject object: TestEntity1) { func objectMonitor(_ monitor: ObjectMonitor<TestEntity1>, didDeleteObject object: TestEntity1) {
NSNotificationCenter.defaultCenter().postNotificationName( NotificationCenter.default.post(
"objectMonitor:didDeleteObject:", name: Notification.Name(rawValue: "objectMonitor:didDeleteObject:"),
object: self, object: self,
userInfo: [ userInfo: [
"object": object "object": object
@@ -242,5 +242,3 @@ class TestObjectObserver: ObjectObserver {
) )
} }
} }
#endif

View File

@@ -2,7 +2,7 @@
// OrderByTests.swift // OrderByTests.swift
// CoreStore // CoreStore
// //
// Copyright © 2016 John Rommel Estropia // Copyright © 2018 John Rommel Estropia
// //
// Permission is hereby granted, free of charge, to any person obtaining a copy // Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal // of this software and associated documentation files (the "Software"), to deal
@@ -38,21 +38,21 @@ final class OrderByTests: XCTestCase {
do { do {
let orderBy = OrderBy() let orderBy = OrderBy<NSManagedObject>()
XCTAssertEqual(orderBy, OrderBy([] as [NSSortDescriptor])) XCTAssertEqual(orderBy, OrderBy<NSManagedObject>([NSSortDescriptor]()))
XCTAssertNotEqual(orderBy, OrderBy(NSSortDescriptor(key: "key", ascending: false))) XCTAssertNotEqual(orderBy, OrderBy<NSManagedObject>(NSSortDescriptor(key: "key", ascending: false)))
XCTAssertTrue(orderBy.sortDescriptors.isEmpty) XCTAssertTrue(orderBy.sortDescriptors.isEmpty)
} }
do { do {
let sortDescriptor = NSSortDescriptor(key: "key1", ascending: true) let sortDescriptor = NSSortDescriptor(key: "key1", ascending: true)
let orderBy = OrderBy(sortDescriptor) let orderBy = OrderBy<NSManagedObject>(sortDescriptor)
XCTAssertEqual(orderBy, OrderBy(sortDescriptor)) XCTAssertEqual(orderBy, OrderBy(sortDescriptor))
XCTAssertEqual(orderBy, OrderBy(.Ascending("key1"))) XCTAssertEqual(orderBy, OrderBy<NSManagedObject>(.ascending("key1")))
XCTAssertNotEqual(orderBy, OrderBy(.Ascending("key2"))) XCTAssertNotEqual(orderBy, OrderBy<NSManagedObject>(.ascending("key2")))
XCTAssertNotEqual(orderBy, OrderBy(.Descending("key1"))) XCTAssertNotEqual(orderBy, OrderBy<NSManagedObject>(.descending("key1")))
XCTAssertNotEqual(orderBy, OrderBy(NSSortDescriptor(key: "key1", ascending: false))) XCTAssertNotEqual(orderBy, OrderBy<NSManagedObject>(NSSortDescriptor(key: "key1", ascending: false)))
XCTAssertEqual(orderBy, OrderBy([sortDescriptor])) XCTAssertEqual(orderBy, OrderBy<NSManagedObject>([sortDescriptor]))
XCTAssertEqual(orderBy.sortDescriptors, [sortDescriptor]) XCTAssertEqual(orderBy.sortDescriptors, [sortDescriptor])
} }
do { do {
@@ -61,76 +61,76 @@ final class OrderByTests: XCTestCase {
NSSortDescriptor(key: "key1", ascending: true), NSSortDescriptor(key: "key1", ascending: true),
NSSortDescriptor(key: "key2", ascending: false) NSSortDescriptor(key: "key2", ascending: false)
] ]
let orderBy = OrderBy(sortDescriptors) let orderBy = OrderBy<NSManagedObject>(sortDescriptors)
XCTAssertEqual(orderBy, OrderBy(sortDescriptors)) XCTAssertEqual(orderBy, OrderBy<NSManagedObject>(sortDescriptors))
XCTAssertEqual(orderBy, OrderBy(.Ascending("key1"), .Descending("key2"))) XCTAssertEqual(orderBy, OrderBy<NSManagedObject>(.ascending("key1"), .descending("key2")))
XCTAssertNotEqual( XCTAssertNotEqual(
orderBy, orderBy,
OrderBy( OrderBy<NSManagedObject>(
[ [
NSSortDescriptor(key: "key1", ascending: false), NSSortDescriptor(key: "key1", ascending: false),
NSSortDescriptor(key: "key2", ascending: false) NSSortDescriptor(key: "key2", ascending: false)
] ]
) )
) )
XCTAssertNotEqual(orderBy, OrderBy(.Ascending("key1"), .Ascending("key2"))) XCTAssertNotEqual(orderBy, OrderBy<NSManagedObject>(.ascending("key1"), .ascending("key2")))
XCTAssertNotEqual(orderBy, OrderBy(.Ascending("key1"), .Descending("key3"))) XCTAssertNotEqual(orderBy, OrderBy<NSManagedObject>(.ascending("key1"), .descending("key3")))
XCTAssertEqual(orderBy.sortDescriptors, sortDescriptors) XCTAssertEqual(orderBy.sortDescriptors, sortDescriptors)
} }
do { do {
let orderBy = OrderBy(.Ascending("key1")) let orderBy = OrderBy<NSManagedObject>(.ascending("key1"))
let sortDescriptor = NSSortDescriptor(key: "key1", ascending: true) let sortDescriptor = NSSortDescriptor(key: "key1", ascending: true)
XCTAssertEqual(orderBy, OrderBy(sortDescriptor)) XCTAssertEqual(orderBy, OrderBy<NSManagedObject>(sortDescriptor))
XCTAssertEqual(orderBy, OrderBy(.Ascending("key1"))) XCTAssertEqual(orderBy, OrderBy<NSManagedObject>(.ascending("key1")))
XCTAssertNotEqual(orderBy, OrderBy(.Descending("key1"))) XCTAssertNotEqual(orderBy, OrderBy<NSManagedObject>(.descending("key1")))
XCTAssertNotEqual(orderBy, OrderBy(.Ascending("key2"))) XCTAssertNotEqual(orderBy, OrderBy<NSManagedObject>(.ascending("key2")))
XCTAssertEqual(orderBy, OrderBy([sortDescriptor])) XCTAssertEqual(orderBy, OrderBy<NSManagedObject>([sortDescriptor]))
XCTAssertEqual(orderBy.sortDescriptors, [sortDescriptor]) XCTAssertEqual(orderBy.sortDescriptors, [sortDescriptor])
} }
do { do {
let orderBy = OrderBy(.Ascending("key1"), .Descending("key2")) let orderBy = OrderBy<NSManagedObject>(.ascending("key1"), .descending("key2"))
let sortDescriptors = [ let sortDescriptors = [
NSSortDescriptor(key: "key1", ascending: true), NSSortDescriptor(key: "key1", ascending: true),
NSSortDescriptor(key: "key2", ascending: false) NSSortDescriptor(key: "key2", ascending: false)
] ]
XCTAssertEqual(orderBy, OrderBy(sortDescriptors)) XCTAssertEqual(orderBy, OrderBy<NSManagedObject>(sortDescriptors))
XCTAssertEqual(orderBy, OrderBy(.Ascending("key1"), .Descending("key2"))) XCTAssertEqual(orderBy, OrderBy<NSManagedObject>(.ascending("key1"), .descending("key2")))
XCTAssertNotEqual( XCTAssertNotEqual(
orderBy, orderBy,
OrderBy( OrderBy<NSManagedObject>(
[ [
NSSortDescriptor(key: "key1", ascending: false), NSSortDescriptor(key: "key1", ascending: false),
NSSortDescriptor(key: "key2", ascending: false) NSSortDescriptor(key: "key2", ascending: false)
] ]
) )
) )
XCTAssertNotEqual(orderBy, OrderBy(.Ascending("key1"), .Ascending("key2"))) XCTAssertNotEqual(orderBy, OrderBy<NSManagedObject>(.ascending("key1"), .ascending("key2")))
XCTAssertNotEqual(orderBy, OrderBy(.Ascending("key1"), .Descending("key3"))) XCTAssertNotEqual(orderBy, OrderBy<NSManagedObject>(.ascending("key1"), .descending("key3")))
XCTAssertEqual(orderBy.sortDescriptors, sortDescriptors) XCTAssertEqual(orderBy.sortDescriptors, sortDescriptors)
} }
do { do {
let sortKeys: [SortKey] = [.Ascending("key1"), .Descending("key2")] let sortKeys: [OrderBy<NSManagedObject>.SortKey] = [.ascending("key1"), .descending("key2")]
let orderBy = OrderBy(sortKeys) let orderBy = OrderBy<NSManagedObject>(sortKeys)
let sortDescriptors = [ let sortDescriptors = [
NSSortDescriptor(key: "key1", ascending: true), NSSortDescriptor(key: "key1", ascending: true),
NSSortDescriptor(key: "key2", ascending: false) NSSortDescriptor(key: "key2", ascending: false)
] ]
XCTAssertEqual(orderBy, OrderBy(sortDescriptors)) XCTAssertEqual(orderBy, OrderBy<NSManagedObject>(sortDescriptors))
XCTAssertEqual(orderBy, OrderBy(.Ascending("key1"), .Descending("key2"))) XCTAssertEqual(orderBy, OrderBy<NSManagedObject>(.ascending("key1"), .descending("key2")))
XCTAssertNotEqual( XCTAssertNotEqual(
orderBy, orderBy,
OrderBy( OrderBy<NSManagedObject>(
[ [
NSSortDescriptor(key: "key1", ascending: false), NSSortDescriptor(key: "key1", ascending: false),
NSSortDescriptor(key: "key2", ascending: false) NSSortDescriptor(key: "key2", ascending: false)
] ]
) )
) )
XCTAssertNotEqual(orderBy, OrderBy(.Ascending("key1"), .Ascending("key2"))) XCTAssertNotEqual(orderBy, OrderBy<NSManagedObject>(.ascending("key1"), .ascending("key2")))
XCTAssertNotEqual(orderBy, OrderBy(.Ascending("key1"), .Descending("key3"))) XCTAssertNotEqual(orderBy, OrderBy<NSManagedObject>(.ascending("key1"), .descending("key3")))
XCTAssertEqual(orderBy.sortDescriptors, sortDescriptors) XCTAssertEqual(orderBy.sortDescriptors, sortDescriptors)
} }
} }
@@ -138,15 +138,15 @@ final class OrderByTests: XCTestCase {
@objc @objc
dynamic func test_ThatOrderByClauseOperations_ComputeCorrectly() { dynamic func test_ThatOrderByClauseOperations_ComputeCorrectly() {
let orderBy1 = OrderBy(.Ascending("key1")) let orderBy1 = OrderBy<NSManagedObject>(.ascending("key1"))
let orderBy2 = OrderBy(.Descending("key2")) let orderBy2 = OrderBy<NSManagedObject>(.descending("key2"))
let orderBy3 = OrderBy(.Ascending("key3")) let orderBy3 = OrderBy<NSManagedObject>(.ascending("key3"))
do { do {
let plusOrderBy = orderBy1 + orderBy2 + orderBy3 let plusOrderBy = orderBy1 + orderBy2 + orderBy3
XCTAssertEqual(plusOrderBy, OrderBy(.Ascending("key1"), .Descending("key2"), .Ascending("key3"))) XCTAssertEqual(plusOrderBy, OrderBy<NSManagedObject>(.ascending("key1"), .descending("key2"), .ascending("key3")))
XCTAssertEqual(plusOrderBy, OrderBy(.Ascending("key1")) + OrderBy(.Descending("key2"), .Ascending("key3"))) XCTAssertEqual(plusOrderBy, OrderBy<NSManagedObject>(.ascending("key1")) + OrderBy<NSManagedObject>(.descending("key2"), .ascending("key3")))
XCTAssertNotEqual(plusOrderBy, orderBy1 + orderBy3 + orderBy2) XCTAssertNotEqual(plusOrderBy, orderBy1 + orderBy3 + orderBy2)
XCTAssertNotEqual(plusOrderBy, orderBy2 + orderBy1 + orderBy3) XCTAssertNotEqual(plusOrderBy, orderBy2 + orderBy1 + orderBy3)
XCTAssertNotEqual(plusOrderBy, orderBy2 + orderBy3 + orderBy1) XCTAssertNotEqual(plusOrderBy, orderBy2 + orderBy3 + orderBy1)
@@ -158,14 +158,14 @@ final class OrderByTests: XCTestCase {
var plusOrderBy = orderBy1 var plusOrderBy = orderBy1
plusOrderBy += orderBy2 plusOrderBy += orderBy2
XCTAssertEqual(plusOrderBy, OrderBy(.Ascending("key1"), .Descending("key2"))) XCTAssertEqual(plusOrderBy, OrderBy<NSManagedObject>(.ascending("key1"), .descending("key2")))
XCTAssertEqual(plusOrderBy, OrderBy(.Ascending("key1")) + OrderBy(.Descending("key2"))) XCTAssertEqual(plusOrderBy, OrderBy<NSManagedObject>(.ascending("key1")) + OrderBy<NSManagedObject>(.descending("key2")))
XCTAssertNotEqual(plusOrderBy, orderBy2 + orderBy1) XCTAssertNotEqual(plusOrderBy, orderBy2 + orderBy1)
XCTAssertEqual(plusOrderBy.sortDescriptors, orderBy1.sortDescriptors + orderBy2.sortDescriptors) XCTAssertEqual(plusOrderBy.sortDescriptors, orderBy1.sortDescriptors + orderBy2.sortDescriptors)
plusOrderBy += orderBy3 plusOrderBy += orderBy3
XCTAssertEqual(plusOrderBy, OrderBy(.Ascending("key1"), .Descending("key2"), .Ascending("key3"))) XCTAssertEqual(plusOrderBy, OrderBy<NSManagedObject>(.ascending("key1"), .descending("key2"), .ascending("key3")))
XCTAssertEqual(plusOrderBy, OrderBy(.Ascending("key1"), .Descending("key2")) + OrderBy(.Ascending("key3"))) XCTAssertEqual(plusOrderBy, OrderBy<NSManagedObject>(.ascending("key1"), .descending("key2")) + OrderBy<NSManagedObject>(.ascending("key3")))
XCTAssertNotEqual(plusOrderBy, orderBy1 + orderBy3 + orderBy2) XCTAssertNotEqual(plusOrderBy, orderBy1 + orderBy3 + orderBy2)
XCTAssertNotEqual(plusOrderBy, orderBy2 + orderBy1 + orderBy3) XCTAssertNotEqual(plusOrderBy, orderBy2 + orderBy1 + orderBy3)
XCTAssertNotEqual(plusOrderBy, orderBy2 + orderBy3 + orderBy1) XCTAssertNotEqual(plusOrderBy, orderBy2 + orderBy3 + orderBy1)
@@ -178,8 +178,8 @@ final class OrderByTests: XCTestCase {
@objc @objc
dynamic func test_ThatOrderByClauses_ApplyToFetchRequestsCorrectly() { dynamic func test_ThatOrderByClauses_ApplyToFetchRequestsCorrectly() {
let orderBy = OrderBy(.Ascending("key")) let orderBy = OrderBy<NSManagedObject>(.ascending("key"))
let request = NSFetchRequest() let request = CoreStoreFetchRequest()
orderBy.applyToFetchRequest(request) orderBy.applyToFetchRequest(request)
XCTAssertNotNil(request.sortDescriptors) XCTAssertNotNil(request.sortDescriptors)
XCTAssertEqual(request.sortDescriptors ?? [], orderBy.sortDescriptors) XCTAssertEqual(request.sortDescriptors ?? [], orderBy.sortDescriptors)

File diff suppressed because it is too large Load Diff

View File

@@ -2,7 +2,7 @@
// SectionByTests.swift // SectionByTests.swift
// CoreStore // CoreStore
// //
// Copyright © 2016 John Rommel Estropia // Copyright © 2018 John Rommel Estropia
// //
// Permission is hereby granted, free of charge, to any person obtaining a copy // Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal // of this software and associated documentation files (the "Software"), to deal
@@ -29,10 +29,9 @@ import XCTest
import CoreStore import CoreStore
#if os(iOS) || os(watchOS) || os(tvOS)
//MARK: - SectionByTests //MARK: - SectionByTests
@available(macOS 10.12, *)
final class SectionByTests: XCTestCase { final class SectionByTests: XCTestCase {
@objc @objc
@@ -40,18 +39,16 @@ final class SectionByTests: XCTestCase {
do { do {
let sectionBy = SectionBy("key") let sectionBy = SectionBy<NSManagedObject>("key")
XCTAssertEqual(sectionBy.sectionKeyPath, "key") XCTAssertEqual(sectionBy.sectionKeyPath, "key")
XCTAssertEqual(sectionBy.sectionIndexTransformer(sectionName: "key"), "key") XCTAssertEqual(sectionBy.sectionIndexTransformer("key"), "key")
} }
do { do {
let sectionBy = SectionBy("key") { $0.flatMap { "\($0):suffix" } } let sectionBy = SectionBy<NSManagedObject>("key") { $0.flatMap { "\($0):suffix" } }
XCTAssertEqual(sectionBy.sectionKeyPath, "key") XCTAssertEqual(sectionBy.sectionKeyPath, "key")
XCTAssertEqual(sectionBy.sectionIndexTransformer(sectionName: "key"), "key:suffix") XCTAssertEqual(sectionBy.sectionIndexTransformer("key"), "key:suffix")
XCTAssertNil(sectionBy.sectionIndexTransformer(sectionName: nil)) XCTAssertNil(sectionBy.sectionIndexTransformer(nil))
} }
} }
} }
#endif

View File

@@ -2,7 +2,7 @@
// SelectTests.swift // SelectTests.swift
// CoreStore // CoreStore
// //
// Copyright © 2016 John Rommel Estropia // Copyright © 2018 John Rommel Estropia
// //
// Permission is hereby granted, free of charge, to any person obtaining a copy // Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal // of this software and associated documentation files (the "Software"), to deal
@@ -38,18 +38,18 @@ final class SelectTests: XCTestCase {
do { do {
let term: SelectTerm = "attribute" let term: SelectTerm<NSManagedObject> = "attribute"
XCTAssertEqual(term, SelectTerm.Attribute("attribute")) XCTAssertEqual(term, SelectTerm.attribute("attribute"))
XCTAssertNotEqual(term, SelectTerm.Attribute("attribute2")) XCTAssertNotEqual(term, SelectTerm.attribute("attribute2"))
XCTAssertNotEqual(term, SelectTerm.Average("attribute")) XCTAssertNotEqual(term, SelectTerm.average("attribute"))
XCTAssertNotEqual(term, SelectTerm.Count("attribute")) XCTAssertNotEqual(term, SelectTerm.count("attribute"))
XCTAssertNotEqual(term, SelectTerm.Maximum("attribute")) XCTAssertNotEqual(term, SelectTerm.maximum("attribute"))
XCTAssertNotEqual(term, SelectTerm.Minimum("attribute")) XCTAssertNotEqual(term, SelectTerm.minimum("attribute"))
XCTAssertNotEqual(term, SelectTerm.Sum("attribute")) XCTAssertNotEqual(term, SelectTerm.sum("attribute"))
XCTAssertNotEqual(term, SelectTerm.ObjectID()) XCTAssertNotEqual(term, SelectTerm.objectID())
switch term { switch term {
case ._Attribute(let key): case ._attribute(let key):
XCTAssertEqual(key, "attribute") XCTAssertEqual(key, "attribute")
default: default:
@@ -58,17 +58,17 @@ final class SelectTests: XCTestCase {
} }
do { do {
let term = SelectTerm.Attribute("attribute") let term = SelectTerm<NSManagedObject>.attribute("attribute")
XCTAssertNotEqual(term, SelectTerm.Attribute("attribute2")) XCTAssertNotEqual(term, SelectTerm.attribute("attribute2"))
XCTAssertNotEqual(term, SelectTerm.Average("attribute")) XCTAssertNotEqual(term, SelectTerm.average("attribute"))
XCTAssertNotEqual(term, SelectTerm.Count("attribute")) XCTAssertNotEqual(term, SelectTerm.count("attribute"))
XCTAssertNotEqual(term, SelectTerm.Maximum("attribute")) XCTAssertNotEqual(term, SelectTerm.maximum("attribute"))
XCTAssertNotEqual(term, SelectTerm.Minimum("attribute")) XCTAssertNotEqual(term, SelectTerm.minimum("attribute"))
XCTAssertNotEqual(term, SelectTerm.Sum("attribute")) XCTAssertNotEqual(term, SelectTerm.sum("attribute"))
XCTAssertNotEqual(term, SelectTerm.ObjectID()) XCTAssertNotEqual(term, SelectTerm.objectID())
switch term { switch term {
case ._Attribute(let key): case ._attribute(let key):
XCTAssertEqual(key, "attribute") XCTAssertEqual(key, "attribute")
default: default:
@@ -82,23 +82,23 @@ final class SelectTests: XCTestCase {
do { do {
let term = SelectTerm.Average("attribute") let term = SelectTerm<NSManagedObject>.average("attribute")
XCTAssertEqual(term, SelectTerm.Average("attribute")) XCTAssertEqual(term, SelectTerm.average("attribute"))
XCTAssertNotEqual(term, SelectTerm.Average("attribute", As: "alias")) XCTAssertNotEqual(term, SelectTerm.average("attribute", as: "alias"))
XCTAssertNotEqual(term, SelectTerm.Average("attribute2")) XCTAssertNotEqual(term, SelectTerm.average("attribute2"))
XCTAssertNotEqual(term, SelectTerm.Attribute("attribute")) XCTAssertNotEqual(term, SelectTerm.attribute("attribute"))
XCTAssertNotEqual(term, SelectTerm.Count("attribute")) XCTAssertNotEqual(term, SelectTerm.count("attribute"))
XCTAssertNotEqual(term, SelectTerm.Maximum("attribute")) XCTAssertNotEqual(term, SelectTerm.maximum("attribute"))
XCTAssertNotEqual(term, SelectTerm.Minimum("attribute")) XCTAssertNotEqual(term, SelectTerm.minimum("attribute"))
XCTAssertNotEqual(term, SelectTerm.Sum("attribute")) XCTAssertNotEqual(term, SelectTerm.sum("attribute"))
XCTAssertNotEqual(term, SelectTerm.ObjectID()) XCTAssertNotEqual(term, SelectTerm.objectID())
switch term { switch term {
case ._Aggregate(let function, let keyPath, let alias, let nativeType): case ._aggregate(let function, let keyPath, let alias, let nativeType):
XCTAssertEqual(function, "average:") XCTAssertEqual(function, "average:")
XCTAssertEqual(keyPath, "attribute") XCTAssertEqual(keyPath, "attribute")
XCTAssertEqual(alias, "average(attribute)") XCTAssertEqual(alias, "average(attribute)")
XCTAssertTrue(nativeType == .DecimalAttributeType) XCTAssertTrue(nativeType == .decimalAttributeType)
default: default:
XCTFail() XCTFail()
@@ -106,23 +106,23 @@ final class SelectTests: XCTestCase {
} }
do { do {
let term = SelectTerm.Average("attribute", As: "alias") let term = SelectTerm<NSManagedObject>.average("attribute", as: "alias")
XCTAssertEqual(term, SelectTerm.Average("attribute", As: "alias")) XCTAssertEqual(term, SelectTerm.average("attribute", as: "alias"))
XCTAssertNotEqual(term, SelectTerm.Average("attribute", As: "alias2")) XCTAssertNotEqual(term, SelectTerm.average("attribute", as: "alias2"))
XCTAssertNotEqual(term, SelectTerm.Average("attribute2")) XCTAssertNotEqual(term, SelectTerm.average("attribute2"))
XCTAssertNotEqual(term, SelectTerm.Attribute("attribute")) XCTAssertNotEqual(term, SelectTerm.attribute("attribute"))
XCTAssertNotEqual(term, SelectTerm.Count("attribute")) XCTAssertNotEqual(term, SelectTerm.count("attribute"))
XCTAssertNotEqual(term, SelectTerm.Maximum("attribute")) XCTAssertNotEqual(term, SelectTerm.maximum("attribute"))
XCTAssertNotEqual(term, SelectTerm.Minimum("attribute")) XCTAssertNotEqual(term, SelectTerm.minimum("attribute"))
XCTAssertNotEqual(term, SelectTerm.Sum("attribute")) XCTAssertNotEqual(term, SelectTerm.sum("attribute"))
XCTAssertNotEqual(term, SelectTerm.ObjectID()) XCTAssertNotEqual(term, SelectTerm.objectID())
switch term { switch term {
case ._Aggregate(let function, let keyPath, let alias, let nativeType): case ._aggregate(let function, let keyPath, let alias, let nativeType):
XCTAssertEqual(function, "average:") XCTAssertEqual(function, "average:")
XCTAssertEqual(keyPath, "attribute") XCTAssertEqual(keyPath, "attribute")
XCTAssertEqual(alias, "alias") XCTAssertEqual(alias, "alias")
XCTAssertTrue(nativeType == .DecimalAttributeType) XCTAssertTrue(nativeType == .decimalAttributeType)
default: default:
XCTFail() XCTFail()
@@ -135,23 +135,23 @@ final class SelectTests: XCTestCase {
do { do {
let term = SelectTerm.Count("attribute") let term = SelectTerm<NSManagedObject>.count("attribute")
XCTAssertEqual(term, SelectTerm.Count("attribute")) XCTAssertEqual(term, SelectTerm.count("attribute"))
XCTAssertNotEqual(term, SelectTerm.Count("attribute", As: "alias")) XCTAssertNotEqual(term, SelectTerm.count("attribute", as: "alias"))
XCTAssertNotEqual(term, SelectTerm.Count("attribute2")) XCTAssertNotEqual(term, SelectTerm.count("attribute2"))
XCTAssertNotEqual(term, SelectTerm.Attribute("attribute")) XCTAssertNotEqual(term, SelectTerm.attribute("attribute"))
XCTAssertNotEqual(term, SelectTerm.Average("attribute")) XCTAssertNotEqual(term, SelectTerm.average("attribute"))
XCTAssertNotEqual(term, SelectTerm.Maximum("attribute")) XCTAssertNotEqual(term, SelectTerm.maximum("attribute"))
XCTAssertNotEqual(term, SelectTerm.Minimum("attribute")) XCTAssertNotEqual(term, SelectTerm.minimum("attribute"))
XCTAssertNotEqual(term, SelectTerm.Sum("attribute")) XCTAssertNotEqual(term, SelectTerm.sum("attribute"))
XCTAssertNotEqual(term, SelectTerm.ObjectID()) XCTAssertNotEqual(term, SelectTerm.objectID())
switch term { switch term {
case ._Aggregate(let function, let keyPath, let alias, let nativeType): case ._aggregate(let function, let keyPath, let alias, let nativeType):
XCTAssertEqual(function, "count:") XCTAssertEqual(function, "count:")
XCTAssertEqual(keyPath, "attribute") XCTAssertEqual(keyPath, "attribute")
XCTAssertEqual(alias, "count(attribute)") XCTAssertEqual(alias, "count(attribute)")
XCTAssertTrue(nativeType == .Integer64AttributeType) XCTAssertTrue(nativeType == .integer64AttributeType)
default: default:
XCTFail() XCTFail()
@@ -159,23 +159,23 @@ final class SelectTests: XCTestCase {
} }
do { do {
let term = SelectTerm.Count("attribute", As: "alias") let term = SelectTerm<NSManagedObject>.count("attribute", as: "alias")
XCTAssertEqual(term, SelectTerm.Count("attribute", As: "alias")) XCTAssertEqual(term, SelectTerm.count("attribute", as: "alias"))
XCTAssertNotEqual(term, SelectTerm.Count("attribute", As: "alias2")) XCTAssertNotEqual(term, SelectTerm.count("attribute", as: "alias2"))
XCTAssertNotEqual(term, SelectTerm.Count("attribute2")) XCTAssertNotEqual(term, SelectTerm.count("attribute2"))
XCTAssertNotEqual(term, SelectTerm.Attribute("attribute")) XCTAssertNotEqual(term, SelectTerm.attribute("attribute"))
XCTAssertNotEqual(term, SelectTerm.Average("attribute")) XCTAssertNotEqual(term, SelectTerm.average("attribute"))
XCTAssertNotEqual(term, SelectTerm.Maximum("attribute")) XCTAssertNotEqual(term, SelectTerm.maximum("attribute"))
XCTAssertNotEqual(term, SelectTerm.Minimum("attribute")) XCTAssertNotEqual(term, SelectTerm.minimum("attribute"))
XCTAssertNotEqual(term, SelectTerm.Sum("attribute")) XCTAssertNotEqual(term, SelectTerm.sum("attribute"))
XCTAssertNotEqual(term, SelectTerm.ObjectID()) XCTAssertNotEqual(term, SelectTerm.objectID())
switch term { switch term {
case ._Aggregate(let function, let keyPath, let alias, let nativeType): case ._aggregate(let function, let keyPath, let alias, let nativeType):
XCTAssertEqual(function, "count:") XCTAssertEqual(function, "count:")
XCTAssertEqual(keyPath, "attribute") XCTAssertEqual(keyPath, "attribute")
XCTAssertEqual(alias, "alias") XCTAssertEqual(alias, "alias")
XCTAssertTrue(nativeType == .Integer64AttributeType) XCTAssertTrue(nativeType == .integer64AttributeType)
default: default:
XCTFail() XCTFail()
@@ -188,23 +188,23 @@ final class SelectTests: XCTestCase {
do { do {
let term = SelectTerm.Maximum("attribute") let term = SelectTerm<NSManagedObject>.maximum("attribute")
XCTAssertEqual(term, SelectTerm.Maximum("attribute")) XCTAssertEqual(term, SelectTerm.maximum("attribute"))
XCTAssertNotEqual(term, SelectTerm.Maximum("attribute", As: "alias")) XCTAssertNotEqual(term, SelectTerm.maximum("attribute", as: "alias"))
XCTAssertNotEqual(term, SelectTerm.Maximum("attribute2")) XCTAssertNotEqual(term, SelectTerm.maximum("attribute2"))
XCTAssertNotEqual(term, SelectTerm.Attribute("attribute")) XCTAssertNotEqual(term, SelectTerm.attribute("attribute"))
XCTAssertNotEqual(term, SelectTerm.Average("attribute")) XCTAssertNotEqual(term, SelectTerm.average("attribute"))
XCTAssertNotEqual(term, SelectTerm.Count("attribute")) XCTAssertNotEqual(term, SelectTerm.count("attribute"))
XCTAssertNotEqual(term, SelectTerm.Minimum("attribute")) XCTAssertNotEqual(term, SelectTerm.minimum("attribute"))
XCTAssertNotEqual(term, SelectTerm.Sum("attribute")) XCTAssertNotEqual(term, SelectTerm.sum("attribute"))
XCTAssertNotEqual(term, SelectTerm.ObjectID()) XCTAssertNotEqual(term, SelectTerm.objectID())
switch term { switch term {
case ._Aggregate(let function, let keyPath, let alias, let nativeType): case ._aggregate(let function, let keyPath, let alias, let nativeType):
XCTAssertEqual(function, "max:") XCTAssertEqual(function, "max:")
XCTAssertEqual(keyPath, "attribute") XCTAssertEqual(keyPath, "attribute")
XCTAssertEqual(alias, "max(attribute)") XCTAssertEqual(alias, "max(attribute)")
XCTAssertTrue(nativeType == .UndefinedAttributeType) XCTAssertTrue(nativeType == .undefinedAttributeType)
default: default:
XCTFail() XCTFail()
@@ -212,23 +212,23 @@ final class SelectTests: XCTestCase {
} }
do { do {
let term = SelectTerm.Maximum("attribute", As: "alias") let term = SelectTerm<NSManagedObject>.maximum("attribute", as: "alias")
XCTAssertEqual(term, SelectTerm.Maximum("attribute", As: "alias")) XCTAssertEqual(term, SelectTerm.maximum("attribute", as: "alias"))
XCTAssertNotEqual(term, SelectTerm.Maximum("attribute", As: "alias2")) XCTAssertNotEqual(term, SelectTerm.maximum("attribute", as: "alias2"))
XCTAssertNotEqual(term, SelectTerm.Maximum("attribute2")) XCTAssertNotEqual(term, SelectTerm.maximum("attribute2"))
XCTAssertNotEqual(term, SelectTerm.Attribute("attribute")) XCTAssertNotEqual(term, SelectTerm.attribute("attribute"))
XCTAssertNotEqual(term, SelectTerm.Average("attribute")) XCTAssertNotEqual(term, SelectTerm.average("attribute"))
XCTAssertNotEqual(term, SelectTerm.Count("attribute")) XCTAssertNotEqual(term, SelectTerm.count("attribute"))
XCTAssertNotEqual(term, SelectTerm.Minimum("attribute")) XCTAssertNotEqual(term, SelectTerm.minimum("attribute"))
XCTAssertNotEqual(term, SelectTerm.Sum("attribute")) XCTAssertNotEqual(term, SelectTerm.sum("attribute"))
XCTAssertNotEqual(term, SelectTerm.ObjectID()) XCTAssertNotEqual(term, SelectTerm.objectID())
switch term { switch term {
case ._Aggregate(let function, let keyPath, let alias, let nativeType): case ._aggregate(let function, let keyPath, let alias, let nativeType):
XCTAssertEqual(function, "max:") XCTAssertEqual(function, "max:")
XCTAssertEqual(keyPath, "attribute") XCTAssertEqual(keyPath, "attribute")
XCTAssertEqual(alias, "alias") XCTAssertEqual(alias, "alias")
XCTAssertTrue(nativeType == .UndefinedAttributeType) XCTAssertTrue(nativeType == .undefinedAttributeType)
default: default:
XCTFail() XCTFail()
@@ -241,23 +241,23 @@ final class SelectTests: XCTestCase {
do { do {
let term = SelectTerm.Minimum("attribute") let term = SelectTerm<NSManagedObject>.minimum("attribute")
XCTAssertEqual(term, SelectTerm.Minimum("attribute")) XCTAssertEqual(term, SelectTerm.minimum("attribute"))
XCTAssertNotEqual(term, SelectTerm.Minimum("attribute", As: "alias")) XCTAssertNotEqual(term, SelectTerm.minimum("attribute", as: "alias"))
XCTAssertNotEqual(term, SelectTerm.Minimum("attribute2")) XCTAssertNotEqual(term, SelectTerm.minimum("attribute2"))
XCTAssertNotEqual(term, SelectTerm.Attribute("attribute")) XCTAssertNotEqual(term, SelectTerm.attribute("attribute"))
XCTAssertNotEqual(term, SelectTerm.Average("attribute")) XCTAssertNotEqual(term, SelectTerm.average("attribute"))
XCTAssertNotEqual(term, SelectTerm.Count("attribute")) XCTAssertNotEqual(term, SelectTerm.count("attribute"))
XCTAssertNotEqual(term, SelectTerm.Maximum("attribute")) XCTAssertNotEqual(term, SelectTerm.maximum("attribute"))
XCTAssertNotEqual(term, SelectTerm.Sum("attribute")) XCTAssertNotEqual(term, SelectTerm.sum("attribute"))
XCTAssertNotEqual(term, SelectTerm.ObjectID()) XCTAssertNotEqual(term, SelectTerm.objectID())
switch term { switch term {
case ._Aggregate(let function, let keyPath, let alias, let nativeType): case ._aggregate(let function, let keyPath, let alias, let nativeType):
XCTAssertEqual(function, "min:") XCTAssertEqual(function, "min:")
XCTAssertEqual(keyPath, "attribute") XCTAssertEqual(keyPath, "attribute")
XCTAssertEqual(alias, "min(attribute)") XCTAssertEqual(alias, "min(attribute)")
XCTAssertTrue(nativeType == .UndefinedAttributeType) XCTAssertTrue(nativeType == .undefinedAttributeType)
default: default:
XCTFail() XCTFail()
@@ -265,23 +265,23 @@ final class SelectTests: XCTestCase {
} }
do { do {
let term = SelectTerm.Minimum("attribute", As: "alias") let term = SelectTerm<NSManagedObject>.minimum("attribute", as: "alias")
XCTAssertEqual(term, SelectTerm.Minimum("attribute", As: "alias")) XCTAssertEqual(term, SelectTerm.minimum("attribute", as: "alias"))
XCTAssertNotEqual(term, SelectTerm.Minimum("attribute", As: "alias2")) XCTAssertNotEqual(term, SelectTerm.minimum("attribute", as: "alias2"))
XCTAssertNotEqual(term, SelectTerm.Minimum("attribute2")) XCTAssertNotEqual(term, SelectTerm.minimum("attribute2"))
XCTAssertNotEqual(term, SelectTerm.Attribute("attribute")) XCTAssertNotEqual(term, SelectTerm.attribute("attribute"))
XCTAssertNotEqual(term, SelectTerm.Average("attribute")) XCTAssertNotEqual(term, SelectTerm.average("attribute"))
XCTAssertNotEqual(term, SelectTerm.Count("attribute")) XCTAssertNotEqual(term, SelectTerm.count("attribute"))
XCTAssertNotEqual(term, SelectTerm.Maximum("attribute")) XCTAssertNotEqual(term, SelectTerm.maximum("attribute"))
XCTAssertNotEqual(term, SelectTerm.Sum("attribute")) XCTAssertNotEqual(term, SelectTerm.sum("attribute"))
XCTAssertNotEqual(term, SelectTerm.ObjectID()) XCTAssertNotEqual(term, SelectTerm.objectID())
switch term { switch term {
case ._Aggregate(let function, let keyPath, let alias, let nativeType): case ._aggregate(let function, let keyPath, let alias, let nativeType):
XCTAssertEqual(function, "min:") XCTAssertEqual(function, "min:")
XCTAssertEqual(keyPath, "attribute") XCTAssertEqual(keyPath, "attribute")
XCTAssertEqual(alias, "alias") XCTAssertEqual(alias, "alias")
XCTAssertTrue(nativeType == .UndefinedAttributeType) XCTAssertTrue(nativeType == .undefinedAttributeType)
default: default:
XCTFail() XCTFail()
@@ -294,23 +294,23 @@ final class SelectTests: XCTestCase {
do { do {
let term = SelectTerm.Sum("attribute") let term = SelectTerm<NSManagedObject>.sum("attribute")
XCTAssertEqual(term, SelectTerm.Sum("attribute")) XCTAssertEqual(term, SelectTerm.sum("attribute"))
XCTAssertNotEqual(term, SelectTerm.Sum("attribute", As: "alias")) XCTAssertNotEqual(term, SelectTerm.sum("attribute", as: "alias"))
XCTAssertNotEqual(term, SelectTerm.Sum("attribute2")) XCTAssertNotEqual(term, SelectTerm.sum("attribute2"))
XCTAssertNotEqual(term, SelectTerm.Attribute("attribute")) XCTAssertNotEqual(term, SelectTerm.attribute("attribute"))
XCTAssertNotEqual(term, SelectTerm.Average("attribute")) XCTAssertNotEqual(term, SelectTerm.average("attribute"))
XCTAssertNotEqual(term, SelectTerm.Count("attribute")) XCTAssertNotEqual(term, SelectTerm.count("attribute"))
XCTAssertNotEqual(term, SelectTerm.Maximum("attribute")) XCTAssertNotEqual(term, SelectTerm.maximum("attribute"))
XCTAssertNotEqual(term, SelectTerm.Minimum("attribute")) XCTAssertNotEqual(term, SelectTerm.minimum("attribute"))
XCTAssertNotEqual(term, SelectTerm.ObjectID()) XCTAssertNotEqual(term, SelectTerm.objectID())
switch term { switch term {
case ._Aggregate(let function, let keyPath, let alias, let nativeType): case ._aggregate(let function, let keyPath, let alias, let nativeType):
XCTAssertEqual(function, "sum:") XCTAssertEqual(function, "sum:")
XCTAssertEqual(keyPath, "attribute") XCTAssertEqual(keyPath, "attribute")
XCTAssertEqual(alias, "sum(attribute)") XCTAssertEqual(alias, "sum(attribute)")
XCTAssertTrue(nativeType == .DecimalAttributeType) XCTAssertTrue(nativeType == .decimalAttributeType)
default: default:
XCTFail() XCTFail()
@@ -318,23 +318,23 @@ final class SelectTests: XCTestCase {
} }
do { do {
let term = SelectTerm.Sum("attribute", As: "alias") let term = SelectTerm<NSManagedObject>.sum("attribute", as: "alias")
XCTAssertEqual(term, SelectTerm.Sum("attribute", As: "alias")) XCTAssertEqual(term, SelectTerm.sum("attribute", as: "alias"))
XCTAssertNotEqual(term, SelectTerm.Sum("attribute", As: "alias2")) XCTAssertNotEqual(term, SelectTerm.sum("attribute", as: "alias2"))
XCTAssertNotEqual(term, SelectTerm.Sum("attribute2")) XCTAssertNotEqual(term, SelectTerm.sum("attribute2"))
XCTAssertNotEqual(term, SelectTerm.Attribute("attribute")) XCTAssertNotEqual(term, SelectTerm.attribute("attribute"))
XCTAssertNotEqual(term, SelectTerm.Average("attribute")) XCTAssertNotEqual(term, SelectTerm.average("attribute"))
XCTAssertNotEqual(term, SelectTerm.Count("attribute")) XCTAssertNotEqual(term, SelectTerm.count("attribute"))
XCTAssertNotEqual(term, SelectTerm.Maximum("attribute")) XCTAssertNotEqual(term, SelectTerm.maximum("attribute"))
XCTAssertNotEqual(term, SelectTerm.Minimum("attribute")) XCTAssertNotEqual(term, SelectTerm.minimum("attribute"))
XCTAssertNotEqual(term, SelectTerm.ObjectID()) XCTAssertNotEqual(term, SelectTerm.objectID())
switch term { switch term {
case ._Aggregate(let function, let keyPath, let alias, let nativeType): case ._aggregate(let function, let keyPath, let alias, let nativeType):
XCTAssertEqual(function, "sum:") XCTAssertEqual(function, "sum:")
XCTAssertEqual(keyPath, "attribute") XCTAssertEqual(keyPath, "attribute")
XCTAssertEqual(alias, "alias") XCTAssertEqual(alias, "alias")
XCTAssertTrue(nativeType == .DecimalAttributeType) XCTAssertTrue(nativeType == .decimalAttributeType)
default: default:
XCTFail() XCTFail()
@@ -347,20 +347,20 @@ final class SelectTests: XCTestCase {
do { do {
let term = SelectTerm.ObjectID() let term = SelectTerm<NSManagedObject>.objectID()
XCTAssertEqual(term, SelectTerm.ObjectID()) XCTAssertEqual(term, SelectTerm.objectID())
XCTAssertNotEqual(term, SelectTerm.ObjectID(As: "alias")) XCTAssertNotEqual(term, SelectTerm.objectID(as: "alias"))
XCTAssertNotEqual(term, SelectTerm.Attribute("attribute")) XCTAssertNotEqual(term, SelectTerm.attribute("attribute"))
XCTAssertNotEqual(term, SelectTerm.Average("attribute")) XCTAssertNotEqual(term, SelectTerm.average("attribute"))
XCTAssertNotEqual(term, SelectTerm.Count("attribute")) XCTAssertNotEqual(term, SelectTerm.count("attribute"))
XCTAssertNotEqual(term, SelectTerm.Maximum("attribute")) XCTAssertNotEqual(term, SelectTerm.maximum("attribute"))
XCTAssertNotEqual(term, SelectTerm.Minimum("attribute")) XCTAssertNotEqual(term, SelectTerm.minimum("attribute"))
XCTAssertNotEqual(term, SelectTerm.Sum("attribute")) XCTAssertNotEqual(term, SelectTerm.sum("attribute"))
switch term { switch term {
case ._Identity(let alias, let nativeType): case ._identity(let alias, let nativeType):
XCTAssertEqual(alias, "objectID") XCTAssertEqual(alias, "objectID")
XCTAssertTrue(nativeType == .ObjectIDAttributeType) XCTAssertTrue(nativeType == .objectIDAttributeType)
default: default:
XCTFail() XCTFail()
@@ -368,21 +368,21 @@ final class SelectTests: XCTestCase {
} }
do { do {
let term = SelectTerm.ObjectID(As: "alias") let term = SelectTerm<NSManagedObject>.objectID(as: "alias")
XCTAssertEqual(term, SelectTerm.ObjectID(As: "alias")) XCTAssertEqual(term, SelectTerm.objectID(as: "alias"))
XCTAssertNotEqual(term, SelectTerm.ObjectID(As: "alias2")) XCTAssertNotEqual(term, SelectTerm.objectID(as: "alias2"))
XCTAssertNotEqual(term, SelectTerm.ObjectID()) XCTAssertNotEqual(term, SelectTerm.objectID())
XCTAssertNotEqual(term, SelectTerm.Attribute("attribute")) XCTAssertNotEqual(term, SelectTerm.attribute("attribute"))
XCTAssertNotEqual(term, SelectTerm.Average("attribute")) XCTAssertNotEqual(term, SelectTerm.average("attribute"))
XCTAssertNotEqual(term, SelectTerm.Count("attribute")) XCTAssertNotEqual(term, SelectTerm.count("attribute"))
XCTAssertNotEqual(term, SelectTerm.Maximum("attribute")) XCTAssertNotEqual(term, SelectTerm.maximum("attribute"))
XCTAssertNotEqual(term, SelectTerm.Minimum("attribute")) XCTAssertNotEqual(term, SelectTerm.minimum("attribute"))
XCTAssertNotEqual(term, SelectTerm.Sum("attribute")) XCTAssertNotEqual(term, SelectTerm.sum("attribute"))
switch term { switch term {
case ._Identity(let alias, let nativeType): case ._identity(let alias, let nativeType):
XCTAssertEqual(alias, "alias") XCTAssertEqual(alias, "alias")
XCTAssertTrue(nativeType == .ObjectIDAttributeType) XCTAssertTrue(nativeType == .objectIDAttributeType)
default: default:
XCTFail() XCTFail()
@@ -393,12 +393,12 @@ final class SelectTests: XCTestCase {
@objc @objc
dynamic func test_ThatSelectClauses_ConfigureCorrectly() { dynamic func test_ThatSelectClauses_ConfigureCorrectly() {
let term1 = SelectTerm.Attribute("attribute1") let term1 = SelectTerm<NSManagedObject>.attribute("attribute1")
let term2 = SelectTerm.Attribute("attribute2") let term2 = SelectTerm<NSManagedObject>.attribute("attribute2")
let term3 = SelectTerm.Attribute("attribute3") let term3 = SelectTerm<NSManagedObject>.attribute("attribute3")
do { do {
let select = Select<Int>(term1, term2, term3) let select = Select<NSManagedObject, Int>(term1, term2, term3)
XCTAssertEqual(select.selectTerms, [term1, term2, term3]) XCTAssertEqual(select.selectTerms, [term1, term2, term3])
XCTAssertNotEqual(select.selectTerms, [term1, term3, term2]) XCTAssertNotEqual(select.selectTerms, [term1, term3, term2])
XCTAssertNotEqual(select.selectTerms, [term2, term1, term3]) XCTAssertNotEqual(select.selectTerms, [term2, term1, term3])
@@ -408,7 +408,7 @@ final class SelectTests: XCTestCase {
} }
do { do {
let select = Select<Int>([term1, term2, term3]) let select = Select<NSManagedObject, Int>([term1, term2, term3])
XCTAssertEqual(select.selectTerms, [term1, term2, term3]) XCTAssertEqual(select.selectTerms, [term1, term2, term3])
XCTAssertNotEqual(select.selectTerms, [term1, term3, term2]) XCTAssertNotEqual(select.selectTerms, [term1, term3, term2])
XCTAssertNotEqual(select.selectTerms, [term2, term1, term3]) XCTAssertNotEqual(select.selectTerms, [term2, term1, term3])

View File

@@ -2,7 +2,7 @@
// SetupTests.swift // SetupTests.swift
// CoreStore // CoreStore
// //
// Copyright © 2016 John Rommel Estropia // Copyright © 2018 John Rommel Estropia
// //
// Permission is hereby granted, free of charge, to any person obtaining a copy // Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal // of this software and associated documentation files (the "Software"), to deal
@@ -29,43 +29,51 @@ import CoreStore
// MARK: - SetupTests // MARK: - SetupTests
class SetupTests: BaseTestCase { class SetupTests: BaseTestDataTestCase {
@objc @objc
dynamic func test_ThatDataStacks_ConfigureCorrectly() { dynamic func test_ThatDataStacks_ConfigureCorrectly() {
do { do {
let model = NSManagedObjectModel.mergedModelFromBundles([NSBundle(forClass: self.dynamicType)])! let schemaHistory = SchemaHistory(
XcodeDataModelSchema.from(
let stack = DataStack(model: model, migrationChain: nil) modelName: "Model",
XCTAssertEqual(stack.coordinator.managedObjectModel, model) bundle: Bundle(for: type(of: self))
)
)
let stack = DataStack(schemaHistory: schemaHistory)
XCTAssertEqual(stack.coordinator.managedObjectModel, schemaHistory.rawModel)
XCTAssertEqual(stack.rootSavingContext.persistentStoreCoordinator, stack.coordinator) XCTAssertEqual(stack.rootSavingContext.persistentStoreCoordinator, stack.coordinator)
XCTAssertNil(stack.rootSavingContext.parentContext) XCTAssertNil(stack.rootSavingContext.parent)
XCTAssertEqual(stack.mainContext.parentContext, stack.rootSavingContext) XCTAssertFalse(stack.rootSavingContext.isDataStackContext)
XCTAssertEqual(stack.model, model) XCTAssertFalse(stack.rootSavingContext.isTransactionContext)
XCTAssertTrue(stack.migrationChain.valid) XCTAssertEqual(stack.mainContext.parent, stack.rootSavingContext)
XCTAssertTrue(stack.migrationChain.empty) XCTAssertTrue(stack.mainContext.isDataStackContext)
XCTAssertTrue(stack.migrationChain.rootVersions.isEmpty) XCTAssertFalse(stack.mainContext.isTransactionContext)
XCTAssertTrue(stack.migrationChain.leafVersions.isEmpty) XCTAssertEqual(stack.schemaHistory.rawModel, schemaHistory.rawModel)
XCTAssertTrue(stack.schemaHistory.migrationChain.isValid)
XCTAssertTrue(stack.schemaHistory.migrationChain.isEmpty)
XCTAssertTrue(stack.schemaHistory.migrationChain.rootVersions.isEmpty)
XCTAssertTrue(stack.schemaHistory.migrationChain.leafVersions.isEmpty)
CoreStore.defaultStack = stack CoreStore.defaultStack = stack
XCTAssertEqual(CoreStore.defaultStack, stack) XCTAssertEqual(CoreStore.defaultStack, stack)
} }
do { do {
let migrationChain: MigrationChain = ["version1", "version2", "version3"] let migrationChain: MigrationChain = ["version1", "version2", "version3", "Model"]
let stack = self.expectLogger([.LogWarning]) { let stack = self.expectLogger([.logWarning]) {
DataStack( DataStack(
modelName: "Model", xcodeModelName: "Model",
bundle: NSBundle(forClass: self.dynamicType), bundle: Bundle(for: type(of: self)),
migrationChain: migrationChain migrationChain: migrationChain
) )
} }
XCTAssertEqual(stack.modelVersion, "Model") XCTAssertEqual(stack.modelVersion, "Model")
XCTAssertEqual(stack.migrationChain, migrationChain) XCTAssertEqual(stack.schemaHistory.migrationChain, migrationChain)
CoreStore.defaultStack = stack CoreStore.defaultStack = stack
XCTAssertEqual(CoreStore.defaultStack, stack) XCTAssertEqual(CoreStore.defaultStack, stack)
@@ -76,8 +84,8 @@ class SetupTests: BaseTestCase {
dynamic func test_ThatInMemoryStores_SetupCorrectly() { dynamic func test_ThatInMemoryStores_SetupCorrectly() {
let stack = DataStack( let stack = DataStack(
modelName: "Model", xcodeModelName: "Model",
bundle: NSBundle(forClass: self.dynamicType) bundle: Bundle(for: type(of: self))
) )
do { do {
@@ -131,8 +139,8 @@ class SetupTests: BaseTestCase {
dynamic func test_ThatSQLiteStores_SetupCorrectly() { dynamic func test_ThatSQLiteStores_SetupCorrectly() {
let stack = DataStack( let stack = DataStack(
modelName: "Model", xcodeModelName: "Model",
bundle: NSBundle(forClass: self.dynamicType) bundle: Bundle(for: type(of: self))
) )
do { do {
@@ -154,7 +162,7 @@ class SetupTests: BaseTestCase {
let sqliteStore = SQLiteStore( let sqliteStore = SQLiteStore(
fileName: "ConfigStore1.sqlite", fileName: "ConfigStore1.sqlite",
configuration: "Config1", configuration: "Config1",
localStorageOptions: .RecreateStoreOnModelMismatch localStorageOptions: .recreateStoreOnModelMismatch
) )
do { do {
@@ -173,7 +181,7 @@ class SetupTests: BaseTestCase {
let sqliteStore = SQLiteStore( let sqliteStore = SQLiteStore(
fileName: "ConfigStore2.sqlite", fileName: "ConfigStore2.sqlite",
configuration: "Config2", configuration: "Config2",
localStorageOptions: .RecreateStoreOnModelMismatch localStorageOptions: .recreateStoreOnModelMismatch
) )
do { do {
@@ -189,16 +197,74 @@ class SetupTests: BaseTestCase {
} }
} }
@objc
dynamic func test_ThatSQLiteStores_DeleteFilesCorrectly() {
let fileManager = FileManager.default
let sqliteStore = SQLiteStore()
func createStore() throws -> [String: Any] {
do {
let stack = DataStack(
xcodeModelName: "Model",
bundle: Bundle(for: type(of: self))
)
try! stack.addStorageAndWait(sqliteStore)
self.prepareTestDataForStack(stack)
}
XCTAssertTrue(fileManager.fileExists(atPath: sqliteStore.fileURL.path))
XCTAssertTrue(fileManager.fileExists(atPath: sqliteStore.fileURL.path.appending("-shm")))
return try NSPersistentStoreCoordinator.metadataForPersistentStore(
ofType: type(of: sqliteStore).storeType,
at: sqliteStore.fileURL,
options: sqliteStore.storeOptions
)
}
do {
let metadata = try createStore()
let stack = DataStack(
xcodeModelName: "Model",
bundle: Bundle(for: type(of: self))
)
try sqliteStore.cs_eraseStorageAndWait(
metadata: metadata,
soureModelHint: stack.schemaHistory.schema(for: metadata)?.rawModel()
)
XCTAssertFalse(fileManager.fileExists(atPath: sqliteStore.fileURL.path))
XCTAssertFalse(fileManager.fileExists(atPath: sqliteStore.fileURL.path.appending("-wal")))
XCTAssertFalse(fileManager.fileExists(atPath: sqliteStore.fileURL.path.appending("-shm")))
}
catch {
XCTFail()
}
do {
let metadata = try createStore()
try sqliteStore.cs_eraseStorageAndWait(metadata: metadata, soureModelHint: nil)
XCTAssertFalse(fileManager.fileExists(atPath: sqliteStore.fileURL.path))
XCTAssertFalse(fileManager.fileExists(atPath: sqliteStore.fileURL.path.appending("-wal")))
XCTAssertFalse(fileManager.fileExists(atPath: sqliteStore.fileURL.path.appending("-shm")))
}
catch {
XCTFail()
}
}
@objc @objc
dynamic func test_ThatLegacySQLiteStores_SetupCorrectly() { dynamic func test_ThatLegacySQLiteStores_SetupCorrectly() {
let stack = DataStack( let stack = DataStack(
modelName: "Model", xcodeModelName: "Model",
bundle: NSBundle(forClass: self.dynamicType) bundle: Bundle(for: type(of: self))
) )
do { do {
let sqliteStore = SQLiteStore() let sqliteStore = SQLiteStore.legacy()
do { do {
try stack.addStorageAndWait(sqliteStore) try stack.addStorageAndWait(sqliteStore)
@@ -213,10 +279,10 @@ class SetupTests: BaseTestCase {
} }
do { do {
let sqliteStore = SQLiteStore( let sqliteStore = SQLiteStore.legacy(
fileName: "ConfigStore1.sqlite", fileName: "ConfigStore1.sqlite",
configuration: "Config1", configuration: "Config1",
localStorageOptions: .RecreateStoreOnModelMismatch localStorageOptions: .recreateStoreOnModelMismatch
) )
do { do {
@@ -232,10 +298,10 @@ class SetupTests: BaseTestCase {
} }
do { do {
let sqliteStore = SQLiteStore( let sqliteStore = SQLiteStore.legacy(
fileName: "ConfigStore2.sqlite", fileName: "ConfigStore2.sqlite",
configuration: "Config2", configuration: "Config2",
localStorageOptions: .RecreateStoreOnModelMismatch localStorageOptions: .recreateStoreOnModelMismatch
) )
do { do {
@@ -250,4 +316,62 @@ class SetupTests: BaseTestCase {
XCTAssert(sqliteStore.matchesPersistentStore(persistentStore!)) XCTAssert(sqliteStore.matchesPersistentStore(persistentStore!))
} }
} }
@objc
dynamic func test_ThatLegacySQLiteStores_DeleteFilesCorrectly() {
let fileManager = FileManager.default
let sqliteStore = SQLiteStore.legacy()
func createStore() throws -> [String: Any] {
do {
let stack = DataStack(
xcodeModelName: "Model",
bundle: Bundle(for: type(of: self))
)
try! stack.addStorageAndWait(sqliteStore)
self.prepareTestDataForStack(stack)
}
XCTAssertTrue(fileManager.fileExists(atPath: sqliteStore.fileURL.path))
XCTAssertTrue(fileManager.fileExists(atPath: sqliteStore.fileURL.path.appending("-shm")))
return try NSPersistentStoreCoordinator.metadataForPersistentStore(
ofType: type(of: sqliteStore).storeType,
at: sqliteStore.fileURL,
options: sqliteStore.storeOptions
)
}
do {
let metadata = try createStore()
let stack = DataStack(
xcodeModelName: "Model",
bundle: Bundle(for: type(of: self))
)
try sqliteStore.cs_eraseStorageAndWait(
metadata: metadata,
soureModelHint: stack.schemaHistory.schema(for: metadata)?.rawModel()
)
XCTAssertFalse(fileManager.fileExists(atPath: sqliteStore.fileURL.path))
XCTAssertFalse(fileManager.fileExists(atPath: sqliteStore.fileURL.path.appending("-wal")))
XCTAssertFalse(fileManager.fileExists(atPath: sqliteStore.fileURL.path.appending("-shm")))
}
catch {
XCTFail()
}
do {
let metadata = try createStore()
try sqliteStore.cs_eraseStorageAndWait(metadata: metadata, soureModelHint: nil)
XCTAssertFalse(fileManager.fileExists(atPath: sqliteStore.fileURL.path))
XCTAssertFalse(fileManager.fileExists(atPath: sqliteStore.fileURL.path.appending("-wal")))
XCTAssertFalse(fileManager.fileExists(atPath: sqliteStore.fileURL.path.appending("-shm")))
}
catch {
XCTFail()
}
}
} }

View File

@@ -2,7 +2,7 @@
// StorageInterfaceTests.swift // StorageInterfaceTests.swift
// CoreStore // CoreStore
// //
// Copyright © 2016 John Rommel Estropia // Copyright © 2018 John Rommel Estropia
// //
// Permission is hereby granted, free of charge, to any person obtaining a copy // Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal // of this software and associated documentation files (the "Software"), to deal
@@ -37,7 +37,7 @@ final class StorageInterfaceTests: XCTestCase {
dynamic func test_ThatDefaultInMemoryStores_ConfigureCorrectly() { dynamic func test_ThatDefaultInMemoryStores_ConfigureCorrectly() {
let store = InMemoryStore() let store = InMemoryStore()
XCTAssertEqual(store.dynamicType.storeType, NSInMemoryStoreType) XCTAssertEqual(type(of: store).storeType, NSInMemoryStoreType)
XCTAssertNil(store.configuration) XCTAssertNil(store.configuration)
XCTAssertNil(store.storeOptions) XCTAssertNil(store.storeOptions)
} }
@@ -46,7 +46,7 @@ final class StorageInterfaceTests: XCTestCase {
dynamic func test_ThatCustomInMemoryStores_ConfigureCorrectly() { dynamic func test_ThatCustomInMemoryStores_ConfigureCorrectly() {
let store = InMemoryStore(configuration: "config1") let store = InMemoryStore(configuration: "config1")
XCTAssertEqual(store.dynamicType.storeType, NSInMemoryStoreType) XCTAssertEqual(type(of: store).storeType, NSInMemoryStoreType)
XCTAssertEqual(store.configuration, "config1") XCTAssertEqual(store.configuration, "config1")
XCTAssertNil(store.storeOptions) XCTAssertNil(store.storeOptions)
} }
@@ -55,24 +55,23 @@ final class StorageInterfaceTests: XCTestCase {
dynamic func test_ThatSQLiteStoreDefaultDirectories_AreCorrect() { dynamic func test_ThatSQLiteStoreDefaultDirectories_AreCorrect() {
#if os(tvOS) #if os(tvOS)
let systemDirectorySearchPath = NSSearchPathDirectory.CachesDirectory let systemDirectorySearchPath = FileManager.SearchPathDirectory.cachesDirectory
#else #else
let systemDirectorySearchPath = NSSearchPathDirectory.ApplicationSupportDirectory let systemDirectorySearchPath = FileManager.SearchPathDirectory.applicationSupportDirectory
#endif #endif
let defaultSystemDirectory = NSFileManager let defaultSystemDirectory = FileManager.default
.defaultManager() .urls(for: systemDirectorySearchPath, in: .userDomainMask).first!
.URLsForDirectory(systemDirectorySearchPath, inDomains: .UserDomainMask).first!
let defaultRootDirectory = defaultSystemDirectory.URLByAppendingPathComponent( let defaultRootDirectory = defaultSystemDirectory.appendingPathComponent(
NSBundle.mainBundle().bundleIdentifier ?? "com.CoreStore.DataStack", Bundle.main.bundleIdentifier ?? "com.CoreStore.DataStack",
isDirectory: true isDirectory: true
) )
let applicationName = (NSBundle.mainBundle().objectForInfoDictionaryKey("CFBundleName") as? String) ?? "CoreData" let applicationName = (Bundle.main.object(forInfoDictionaryKey: "CFBundleName") as? String) ?? "CoreData"
let defaultFileURL = defaultRootDirectory let defaultFileURL = defaultRootDirectory
.URLByAppendingPathComponent(applicationName, isDirectory: false) .appendingPathComponent(applicationName, isDirectory: false)
.URLByAppendingPathExtension("sqlite") .appendingPathExtension("sqlite")
XCTAssertEqual(SQLiteStore.defaultRootDirectory, defaultRootDirectory) XCTAssertEqual(SQLiteStore.defaultRootDirectory, defaultRootDirectory)
XCTAssertEqual(SQLiteStore.defaultFileURL, defaultFileURL) XCTAssertEqual(SQLiteStore.defaultFileURL, defaultFileURL)
@@ -82,137 +81,190 @@ final class StorageInterfaceTests: XCTestCase {
dynamic func test_ThatDefaultSQLiteStores_ConfigureCorrectly() { dynamic func test_ThatDefaultSQLiteStores_ConfigureCorrectly() {
let store = SQLiteStore() let store = SQLiteStore()
XCTAssertEqual(store.dynamicType.storeType, NSSQLiteStoreType) XCTAssertEqual(type(of: store).storeType, NSSQLiteStoreType)
XCTAssertNil(store.configuration) XCTAssertNil(store.configuration)
XCTAssertEqual(store.storeOptions, [NSSQLitePragmasOption: ["journal_mode": "WAL"]] as NSDictionary) if #available(iOS 11.0, macOS 10.13, tvOS 11.0, *) {
XCTAssertEqual(
store.storeOptions as NSDictionary?,
[NSSQLitePragmasOption: ["journal_mode": "WAL"],
NSBinaryStoreInsecureDecodingCompatibilityOption: true] as NSDictionary
)
}
else {
XCTAssertEqual(
store.storeOptions as NSDictionary?,
[NSSQLitePragmasOption: ["journal_mode": "WAL"]] as NSDictionary
)
}
XCTAssertEqual(store.fileURL, SQLiteStore.defaultFileURL) XCTAssertEqual(store.fileURL, SQLiteStore.defaultFileURL)
XCTAssertEqual(store.mappingModelBundles, NSBundle.allBundles()) XCTAssertTrue(store.migrationMappingProviders.isEmpty)
XCTAssertEqual(store.localStorageOptions, [.None]) XCTAssertEqual(store.localStorageOptions, .none)
} }
@objc @objc
dynamic func test_ThatFileURLSQLiteStores_ConfigureCorrectly() { dynamic func test_ThatFileURLSQLiteStores_ConfigureCorrectly() {
let fileURL = NSURL(fileURLWithPath: NSTemporaryDirectory()) let fileURL = FileManager.default.temporaryDirectory
.URLByAppendingPathComponent(NSUUID().UUIDString, isDirectory: false) .appendingPathComponent(UUID().uuidString, isDirectory: false)
.URLByAppendingPathExtension("db") .appendingPathExtension("db")
let bundles = [NSBundle(forClass: self.dynamicType)] let mappingProvider = XcodeSchemaMappingProvider(
from: "V1", to: "V2",
mappingModelBundle: Bundle(for: type(of: self))
)
let store = SQLiteStore( let store = SQLiteStore(
fileURL: fileURL, fileURL: fileURL,
configuration: "config1", configuration: "config1",
mappingModelBundles: bundles, migrationMappingProviders: [mappingProvider],
localStorageOptions: .RecreateStoreOnModelMismatch localStorageOptions: .recreateStoreOnModelMismatch
) )
XCTAssertEqual(store.dynamicType.storeType, NSSQLiteStoreType) XCTAssertEqual(type(of: store).storeType, NSSQLiteStoreType)
XCTAssertEqual(store.configuration, "config1") XCTAssertEqual(store.configuration, "config1")
XCTAssertEqual(store.storeOptions, [NSSQLitePragmasOption: ["journal_mode": "WAL"]] as NSDictionary) if #available(iOS 11.0, macOS 10.13, tvOS 11.0, *) {
XCTAssertEqual(
store.storeOptions as NSDictionary?,
[NSSQLitePragmasOption: ["journal_mode": "WAL"],
NSBinaryStoreInsecureDecodingCompatibilityOption: true] as NSDictionary
)
}
else {
XCTAssertEqual(
store.storeOptions as NSDictionary?,
[NSSQLitePragmasOption: ["journal_mode": "WAL"]] as NSDictionary
)
}
XCTAssertEqual(store.fileURL, fileURL) XCTAssertEqual(store.fileURL, fileURL)
XCTAssertEqual(store.mappingModelBundles, bundles) XCTAssertEqual(store.migrationMappingProviders as! [XcodeSchemaMappingProvider], [mappingProvider])
XCTAssertEqual(store.localStorageOptions, [.RecreateStoreOnModelMismatch]) XCTAssertEqual(store.localStorageOptions, [.recreateStoreOnModelMismatch])
} }
@objc @objc
dynamic func test_ThatFileNameSQLiteStores_ConfigureCorrectly() { dynamic func test_ThatFileNameSQLiteStores_ConfigureCorrectly() {
let fileName = NSUUID().UUIDString + ".db" let fileName = UUID().uuidString + ".db"
let bundles = [NSBundle(forClass: self.dynamicType)] let mappingProvider = XcodeSchemaMappingProvider(
from: "V1", to: "V2",
mappingModelBundle: Bundle(for: type(of: self))
)
let store = SQLiteStore( let store = SQLiteStore(
fileName: fileName, fileName: fileName,
configuration: "config1", configuration: "config1",
mappingModelBundles: bundles, migrationMappingProviders: [mappingProvider],
localStorageOptions: .RecreateStoreOnModelMismatch localStorageOptions: .recreateStoreOnModelMismatch
) )
XCTAssertEqual(store.dynamicType.storeType, NSSQLiteStoreType) XCTAssertEqual(type(of: store).storeType, NSSQLiteStoreType)
XCTAssertEqual(store.configuration, "config1") XCTAssertEqual(store.configuration, "config1")
XCTAssertEqual(store.storeOptions, [NSSQLitePragmasOption: ["journal_mode": "WAL"]] as NSDictionary) if #available(iOS 11.0, macOS 10.13, tvOS 11.0, *) {
XCTAssertEqual(
store.storeOptions as NSDictionary?,
[NSSQLitePragmasOption: ["journal_mode": "WAL"],
NSBinaryStoreInsecureDecodingCompatibilityOption: true] as NSDictionary
)
}
else {
XCTAssertEqual(
store.storeOptions as NSDictionary?,
[NSSQLitePragmasOption: ["journal_mode": "WAL"]] as NSDictionary
)
}
XCTAssertEqual(store.fileURL.URLByDeletingLastPathComponent, SQLiteStore.defaultRootDirectory) XCTAssertEqual(store.fileURL.deletingLastPathComponent(), SQLiteStore.defaultRootDirectory)
XCTAssertEqual(store.fileURL.lastPathComponent, fileName) XCTAssertEqual(store.fileURL.lastPathComponent, fileName)
XCTAssertEqual(store.mappingModelBundles, bundles) XCTAssertEqual(store.migrationMappingProviders as! [XcodeSchemaMappingProvider], [mappingProvider])
XCTAssertEqual(store.localStorageOptions, [.RecreateStoreOnModelMismatch]) XCTAssertEqual(store.localStorageOptions, [.recreateStoreOnModelMismatch])
} }
@objc @objc
dynamic func test_ThatLegacySQLiteStoreDefaultDirectories_AreCorrect() { dynamic func test_ThatLegacySQLiteStoreDefaultDirectories_AreCorrect() {
#if os(tvOS) #if os(tvOS)
let systemDirectorySearchPath = NSSearchPathDirectory.CachesDirectory let systemDirectorySearchPath = FileManager.SearchPathDirectory.cachesDirectory
#else #else
let systemDirectorySearchPath = NSSearchPathDirectory.ApplicationSupportDirectory let systemDirectorySearchPath = FileManager.SearchPathDirectory.applicationSupportDirectory
#endif #endif
let legacyDefaultRootDirectory = NSFileManager.defaultManager().URLsForDirectory( let legacyDefaultRootDirectory = FileManager.default.urls(
systemDirectorySearchPath, for: systemDirectorySearchPath,
inDomains: .UserDomainMask in: .userDomainMask).first!
).first!
let legacyDefaultFileURL = legacyDefaultRootDirectory let legacyDefaultFileURL = legacyDefaultRootDirectory
.URLByAppendingPathComponent(DataStack.applicationName, isDirectory: false) .appendingPathComponent(DataStack.applicationName, isDirectory: false)
.URLByAppendingPathExtension("sqlite") .appendingPathExtension("sqlite")
XCTAssertEqual(LegacySQLiteStore.defaultRootDirectory, legacyDefaultRootDirectory) XCTAssertEqual(SQLiteStore.legacyDefaultRootDirectory, legacyDefaultRootDirectory)
XCTAssertEqual(LegacySQLiteStore.defaultFileURL, legacyDefaultFileURL) XCTAssertEqual(SQLiteStore.legacyDefaultFileURL, legacyDefaultFileURL)
} }
@objc @objc
dynamic func test_ThatDefaultLegacySQLiteStores_ConfigureCorrectly() { dynamic func test_ThatDefaultLegacySQLiteStores_ConfigureCorrectly() {
let store = LegacySQLiteStore() let store = SQLiteStore.legacy()
XCTAssertEqual(store.dynamicType.storeType, NSSQLiteStoreType) XCTAssertEqual(type(of: store).storeType, NSSQLiteStoreType)
XCTAssertNil(store.configuration) XCTAssertNil(store.configuration)
XCTAssertEqual(store.storeOptions, [NSSQLitePragmasOption: ["journal_mode": "WAL"]] as NSDictionary) if #available(iOS 11.0, macOS 10.13, tvOS 11.0, *) {
XCTAssertEqual(
store.storeOptions as NSDictionary?,
[NSSQLitePragmasOption: ["journal_mode": "WAL"],
NSBinaryStoreInsecureDecodingCompatibilityOption: true] as NSDictionary
)
}
else {
XCTAssertEqual(
store.storeOptions as NSDictionary?,
[NSSQLitePragmasOption: ["journal_mode": "WAL"]] as NSDictionary
)
}
XCTAssertEqual(store.fileURL, LegacySQLiteStore.defaultFileURL) XCTAssertEqual(store.fileURL, SQLiteStore.legacyDefaultFileURL)
XCTAssertEqual(store.mappingModelBundles, NSBundle.allBundles()) XCTAssertTrue(store.migrationMappingProviders.isEmpty)
XCTAssertEqual(store.localStorageOptions, [.None]) XCTAssertEqual(store.localStorageOptions, .none)
}
@objc
dynamic func test_ThatFileURLLegacySQLiteStores_ConfigureCorrectly() {
let fileURL = NSURL(fileURLWithPath: NSTemporaryDirectory())
.URLByAppendingPathComponent(NSUUID().UUIDString, isDirectory: false)
.URLByAppendingPathExtension("db")
let bundles = [NSBundle(forClass: self.dynamicType)]
let store = LegacySQLiteStore(
fileURL: fileURL,
configuration: "config1",
mappingModelBundles: bundles,
localStorageOptions: .RecreateStoreOnModelMismatch
)
XCTAssertEqual(store.dynamicType.storeType, NSSQLiteStoreType)
XCTAssertEqual(store.configuration, "config1")
XCTAssertEqual(store.storeOptions, [NSSQLitePragmasOption: ["journal_mode": "WAL"]] as NSDictionary)
XCTAssertEqual(store.fileURL, fileURL)
XCTAssertEqual(store.mappingModelBundles, bundles)
XCTAssertEqual(store.localStorageOptions, [.RecreateStoreOnModelMismatch])
} }
@objc @objc
dynamic func test_ThatFileNameLegacySQLiteStores_ConfigureCorrectly() { dynamic func test_ThatFileNameLegacySQLiteStores_ConfigureCorrectly() {
let fileName = NSUUID().UUIDString + ".db" let fileName = UUID().uuidString + ".db"
let bundles = [NSBundle(forClass: self.dynamicType)] let mappingProvider = XcodeSchemaMappingProvider(
from: "V1", to: "V2",
let store = LegacySQLiteStore( mappingModelBundle: Bundle(for: type(of: self))
)
let store = SQLiteStore.legacy(
fileName: fileName, fileName: fileName,
configuration: "config1", configuration: "config1",
mappingModelBundles: bundles, migrationMappingProviders: [mappingProvider],
localStorageOptions: .RecreateStoreOnModelMismatch localStorageOptions: .recreateStoreOnModelMismatch
) )
XCTAssertEqual(store.dynamicType.storeType, NSSQLiteStoreType) XCTAssertEqual(type(of: store).storeType, NSSQLiteStoreType)
XCTAssertEqual(store.configuration, "config1") XCTAssertEqual(store.configuration, "config1")
XCTAssertEqual(store.storeOptions, [NSSQLitePragmasOption: ["journal_mode": "WAL"]] as NSDictionary) if #available(iOS 11.0, macOS 10.13, tvOS 11.0, *) {
XCTAssertEqual(
store.storeOptions as NSDictionary?,
[NSSQLitePragmasOption: ["journal_mode": "WAL"],
NSBinaryStoreInsecureDecodingCompatibilityOption: true] as NSDictionary
)
}
else {
XCTAssertEqual(
store.storeOptions as NSDictionary?,
[NSSQLitePragmasOption: ["journal_mode": "WAL"]] as NSDictionary
)
}
XCTAssertEqual(store.fileURL.URLByDeletingLastPathComponent, LegacySQLiteStore.defaultRootDirectory) XCTAssertEqual(store.fileURL.deletingLastPathComponent(), SQLiteStore.legacyDefaultRootDirectory)
XCTAssertEqual(store.fileURL.lastPathComponent, fileName) XCTAssertEqual(store.fileURL.lastPathComponent, fileName)
XCTAssertEqual(store.mappingModelBundles, bundles) XCTAssertEqual(store.migrationMappingProviders as! [XcodeSchemaMappingProvider], [mappingProvider])
XCTAssertEqual(store.localStorageOptions, [.RecreateStoreOnModelMismatch]) XCTAssertEqual(store.localStorageOptions, [.recreateStoreOnModelMismatch])
} }
} }

View File

@@ -2,7 +2,7 @@
// TestEntity1.swift // TestEntity1.swift
// CoreStore // CoreStore
// //
// Copyright © 2014 John Rommel Estropia // Copyright © 2018 John Rommel Estropia
// //
// Permission is hereby granted, free of charge, to any person obtaining a copy // Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal // of this software and associated documentation files (the "Software"), to deal
@@ -31,9 +31,9 @@ class TestEntity1: NSManagedObject {
@NSManaged var testEntityID: NSNumber? @NSManaged var testEntityID: NSNumber?
@NSManaged var testString: String? @NSManaged var testString: String?
@NSManaged var testNumber: NSNumber? @NSManaged var testNumber: NSNumber?
@NSManaged var testDate: NSDate? @NSManaged var testDate: Date?
@NSManaged var testBoolean: NSNumber? @NSManaged var testBoolean: NSNumber?
@NSManaged var testDecimal: NSDecimalNumber? @NSManaged var testDecimal: NSDecimalNumber?
@NSManaged var testData: NSData? @NSManaged var testData: Data?
@NSManaged var testNil: String? @NSManaged var testNil: String?
} }

View File

@@ -2,7 +2,7 @@
// TestEntity1.swift // TestEntity1.swift
// CoreStore // CoreStore
// //
// Copyright © 2014 John Rommel Estropia // Copyright © 2018 John Rommel Estropia
// //
// Permission is hereby granted, free of charge, to any person obtaining a copy // Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal // of this software and associated documentation files (the "Software"), to deal
@@ -31,9 +31,9 @@ class TestEntity2: NSManagedObject {
@NSManaged var testEntityID: NSNumber? @NSManaged var testEntityID: NSNumber?
@NSManaged var testString: String? @NSManaged var testString: String?
@NSManaged var testNumber: NSNumber? @NSManaged var testNumber: NSNumber?
@NSManaged var testDate: NSDate? @NSManaged var testDate: Date?
@NSManaged var testBoolean: NSNumber? @NSManaged var testBoolean: NSNumber?
@NSManaged var testDecimal: NSDecimalNumber? @NSManaged var testDecimal: NSDecimalNumber?
@NSManaged var testData: NSData? @NSManaged var testData: Data?
@NSManaged var testNil: String? @NSManaged var testNil: String?
} }

File diff suppressed because it is too large Load Diff

View File

@@ -2,7 +2,7 @@
// TweakTests.swift // TweakTests.swift
// CoreStore // CoreStore
// //
// Copyright © 2016 John Rommel Estropia // Copyright © 2018 John Rommel Estropia
// //
// Permission is hereby granted, free of charge, to any person obtaining a copy // Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal // of this software and associated documentation files (the "Software"), to deal
@@ -43,7 +43,7 @@ final class TweakTests: XCTestCase {
$0.fetchLimit = 200 $0.fetchLimit = 200
$0.predicate = predicate $0.predicate = predicate
} }
let request = NSFetchRequest() let request = CoreStoreFetchRequest()
tweak.applyToFetchRequest(request) tweak.applyToFetchRequest(request)
XCTAssertEqual(request.fetchOffset, 100) XCTAssertEqual(request.fetchOffset, 100)
XCTAssertEqual(request.fetchLimit, 200) XCTAssertEqual(request.fetchLimit, 200)

View File

@@ -2,7 +2,7 @@
// WhereTests.swift // WhereTests.swift
// CoreStore // CoreStore
// //
// Copyright © 2016 John Rommel Estropia // Copyright © 2018 John Rommel Estropia
// //
// Permission is hereby granted, free of charge, to any person obtaining a copy // Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal // of this software and associated documentation files (the "Software"), to deal
@@ -29,76 +29,218 @@ import XCTest
import CoreStore import CoreStore
// MARK: - XCTAssertAllEqual
private func XCTAssertAllEqual<D>(_ whereClauses: Where<D>...) {
XCTAssertAllEqual(whereClauses)
}
private func XCTAssertAllEqual<D>(_ whereClauses: [Where<D>]) {
for i in whereClauses.indices {
for j in whereClauses.indices where j != i {
XCTAssertEqual(whereClauses[i], whereClauses[j])
}
}
}
//MARK: - WhereTests //MARK: - WhereTests
final class WhereTests: XCTestCase { final class WhereTests: XCTestCase {
@objc
dynamic func test_ThatDynamicModelKeyPaths_CanBeCreated() {
XCTAssertEqual(String(keyPath: \TestEntity1.testEntityID), "testEntityID")
}
@objc @objc
dynamic func test_ThatWhereClauses_ConfigureCorrectly() { dynamic func test_ThatWhereClauses_ConfigureCorrectly() {
do { do {
let whereClause = Where() let whereClause = Where<NSManagedObject>()
XCTAssertEqual(whereClause, Where(true)) XCTAssertEqual(whereClause, Where<NSManagedObject>(true))
XCTAssertNotEqual(whereClause, Where(false)) XCTAssertNotEqual(whereClause, Where<NSManagedObject>(false))
XCTAssertEqual(whereClause.predicate, NSPredicate(value: true)) XCTAssertEqual(whereClause.predicate, NSPredicate(value: true))
} }
do { do {
let whereClause = Where(true) let whereClause = Where<NSManagedObject>(true)
XCTAssertEqual(whereClause, Where()) XCTAssertEqual(whereClause, Where<NSManagedObject>())
XCTAssertNotEqual(whereClause, Where(false)) XCTAssertNotEqual(whereClause, Where<NSManagedObject>(false))
XCTAssertEqual(whereClause.predicate, NSPredicate(value: true)) XCTAssertEqual(whereClause.predicate, NSPredicate(value: true))
} }
do { do {
let predicate = NSPredicate(format: "%K == %@", "key", "value") let predicate = NSPredicate(format: "%K == %@", "key", "value")
let whereClause = Where(predicate) let whereClause = Where<NSManagedObject>(predicate)
XCTAssertEqual(whereClause, Where(predicate)) XCTAssertEqual(whereClause, Where<NSManagedObject>(predicate))
XCTAssertEqual(whereClause.predicate, predicate) XCTAssertEqual(whereClause.predicate, predicate)
} }
do { do {
let whereClause = Where("%K == %@", "key", "value") let whereClause = Where<NSManagedObject>("%K == %@", "key", "value")
let predicate = NSPredicate(format: "%K == %@", "key", "value") let predicate = NSPredicate(format: "%K == %@", "key", "value")
XCTAssertEqual(whereClause, Where(predicate)) XCTAssertEqual(whereClause, Where<NSManagedObject>(predicate))
XCTAssertEqual(whereClause.predicate, predicate) XCTAssertEqual(whereClause.predicate, predicate)
} }
do { do {
let whereClause = Where("%K == %@", argumentArray: ["key", "value"]) let whereClause = Where<NSManagedObject>("%K == %@", argumentArray: ["key", "value"])
let predicate = NSPredicate(format: "%K == %@", "key", "value") let predicate = NSPredicate(format: "%K == %@", "key", "value")
XCTAssertEqual(whereClause, Where(predicate)) XCTAssertEqual(whereClause, Where<NSManagedObject>(predicate))
XCTAssertEqual(whereClause.predicate, predicate) XCTAssertEqual(whereClause.predicate, predicate)
} }
do { do {
let whereClause = Where("key", isEqualTo: "value") let whereClause = Where<NSManagedObject>("key", isEqualTo: "value")
let predicate = NSPredicate(format: "%K == %@", "key", "value") let predicate = NSPredicate(format: "%K == %@", "key", "value")
XCTAssertEqual(whereClause, Where(predicate)) XCTAssertEqual(whereClause, Where<NSManagedObject>(predicate))
XCTAssertEqual(whereClause.predicate, predicate) XCTAssertEqual(whereClause.predicate, predicate)
} }
do { do {
let whereClause = Where("key", isMemberOf: ["value1", "value2", "value3"]) let whereClause = Where<NSManagedObject>("key", isMemberOf: ["value1", "value2", "value3"])
let predicate = NSPredicate(format: "%K IN %@", "key", ["value1", "value2", "value3"]) let predicate = NSPredicate(format: "%K IN %@", "key", ["value1", "value2", "value3"])
XCTAssertEqual(whereClause, Where(predicate)) XCTAssertEqual(whereClause, Where<NSManagedObject>(predicate))
XCTAssertEqual(whereClause.predicate, predicate) XCTAssertEqual(whereClause.predicate, predicate)
} }
} }
@objc
dynamic func test_ThatWhereClauses_BridgeArgumentsCorrectly() {
do {
let value: Int = 100
XCTAssertAllEqual(
Where<NSManagedObject>("%K == %d", "key", value),
Where<NSManagedObject>("%K == %d", "key", value as AnyObject),
Where<NSManagedObject>("%K == %d", "key", NSNumber(value: value)),
Where<NSManagedObject>("%K == %@", "key", value),
Where<NSManagedObject>("%K == %@", "key", value as AnyObject),
Where<NSManagedObject>("%K == %@", "key", NSNumber(value: value)),
Where<NSManagedObject>("key", isEqualTo: value),
Where<NSManagedObject>("key", isEqualTo: NSNumber(value: value))
)
}
do {
let value = NSNumber(value: 100)
XCTAssertAllEqual(
Where<NSManagedObject>("%K == %d", "key", value),
Where<NSManagedObject>("%K == %d", "key", value as AnyObject),
Where<NSManagedObject>("%K == %d", "key", value.intValue),
Where<NSManagedObject>("%K == %@", "key", value),
Where<NSManagedObject>("%K == %@", "key", value as AnyObject),
Where<NSManagedObject>("%K == %@", "key", value.intValue),
Where<NSManagedObject>("key", isEqualTo: value),
Where<NSManagedObject>("key", isEqualTo: value.intValue)
)
}
do {
let value: Int64 = Int64.max
XCTAssertAllEqual(
Where<NSManagedObject>("%K == %d", "key", value),
Where<NSManagedObject>("%K == %d", "key", value as AnyObject),
Where<NSManagedObject>("%K == %d", "key", NSNumber(value: value)),
Where<NSManagedObject>("%K == %@", "key", value),
Where<NSManagedObject>("%K == %@", "key", value as AnyObject),
Where<NSManagedObject>("%K == %@", "key", NSNumber(value: value)),
Where<NSManagedObject>("key", isEqualTo: value),
Where<NSManagedObject>("key", isEqualTo: NSNumber(value: value))
)
}
do {
let value = NSNumber(value: Int64.max)
XCTAssertAllEqual(
Where<NSManagedObject>("%K == %d", "key", value),
Where<NSManagedObject>("%K == %d", "key", value as AnyObject),
Where<NSManagedObject>("%K == %d", "key", value.int64Value),
Where<NSManagedObject>("%K == %@", "key", value),
Where<NSManagedObject>("%K == %@", "key", value as AnyObject),
Where<NSManagedObject>("%K == %@", "key", value.int64Value),
Where<NSManagedObject>("key", isEqualTo: value),
Where<NSManagedObject>("key", isEqualTo: value.int64Value)
)
}
do {
let value: String = "value"
XCTAssertAllEqual(
Where<NSManagedObject>("%K == %s", "key", value),
Where<NSManagedObject>("%K == %s", "key", value as AnyObject),
Where<NSManagedObject>("%K == %s", "key", NSString(string: value)),
Where<NSManagedObject>("%K == %@", "key", value),
Where<NSManagedObject>("%K == %@", "key", value as AnyObject),
Where<NSManagedObject>("%K == %@", "key", NSString(string: value)),
Where<NSManagedObject>("key", isEqualTo: value),
Where<NSManagedObject>("key", isEqualTo: value as NSString),
Where<NSManagedObject>("key", isEqualTo: NSString(string: value))
)
}
do {
let value = NSString(string: "value")
XCTAssertAllEqual(
Where<NSManagedObject>("%K == %s", "key", value),
Where<NSManagedObject>("%K == %s", "key", value as String),
Where<NSManagedObject>("%K == %s", "key", value as String as AnyObject),
Where<NSManagedObject>("%K == %@", "key", value),
Where<NSManagedObject>("%K == %@", "key", value as String),
Where<NSManagedObject>("%K == %@", "key", value as String as AnyObject),
Where<NSManagedObject>("key", isEqualTo: value),
Where<NSManagedObject>("key", isEqualTo: value as String),
Where<NSManagedObject>("key", isEqualTo: value as String as NSString)
)
}
do {
let value: [Int] = [100, 200]
XCTAssertAllEqual(
Where<NSManagedObject>("%K IN %@", "key", value),
Where<NSManagedObject>("%K IN %@", "key", value as AnyObject),
Where<NSManagedObject>("%K IN %@", "key", value as [AnyObject]),
Where<NSManagedObject>("%K IN %@", "key", value as NSArray),
Where<NSManagedObject>("%K IN %@", "key", NSArray(array: value)),
Where<NSManagedObject>("%K IN %@", "key", value as AnyObject as! NSArray),
Where<NSManagedObject>("key", isMemberOf: value)
)
}
do {
let value: [Int64] = [Int64.min, 100, Int64.max]
XCTAssertAllEqual(
Where<NSManagedObject>("%K IN %@", "key", value),
Where<NSManagedObject>("%K IN %@", "key", value as AnyObject),
Where<NSManagedObject>("%K IN %@", "key", value as [AnyObject]),
Where<NSManagedObject>("%K IN %@", "key", value as NSArray),
Where<NSManagedObject>("%K IN %@", "key", NSArray(array: value)),
Where<NSManagedObject>("%K IN %@", "key", value as AnyObject as! NSArray),
Where<NSManagedObject>("key", isMemberOf: value)
)
}
}
@objc @objc
dynamic func test_ThatWhereClauseOperations_ComputeCorrectly() { dynamic func test_ThatWhereClauseOperations_ComputeCorrectly() {
let whereClause1 = Where("key1", isEqualTo: "value1") let whereClause1 = Where<NSManagedObject>("key1", isEqualTo: "value1")
let whereClause2 = Where("key2", isEqualTo: "value2") let whereClause2 = Where<NSManagedObject>("key2", isEqualTo: "value2")
let whereClause3 = Where("key3", isEqualTo: "value3") let whereClause3 = Where<NSManagedObject>("key3", isEqualTo: "value3")
do { do {
let notWhere = !whereClause1 let notWhere = !whereClause1
let notPredicate = NSCompoundPredicate( let notPredicate = NSCompoundPredicate(
type: .NotPredicateType, type: .not,
subpredicates: [whereClause1.predicate] subpredicates: [whereClause1.predicate]
) )
XCTAssertEqual(notWhere.predicate, notPredicate) XCTAssertEqual(notWhere.predicate, notPredicate)
@@ -108,10 +250,10 @@ final class WhereTests: XCTestCase {
let andWhere = whereClause1 && whereClause2 && whereClause3 let andWhere = whereClause1 && whereClause2 && whereClause3
let andPredicate = NSCompoundPredicate( let andPredicate = NSCompoundPredicate(
type: .AndPredicateType, type: .and,
subpredicates: [ subpredicates: [
NSCompoundPredicate( NSCompoundPredicate(
type: .AndPredicateType, type: .and,
subpredicates: [whereClause1.predicate, whereClause2.predicate] subpredicates: [whereClause1.predicate, whereClause2.predicate]
), ),
whereClause3.predicate whereClause3.predicate
@@ -120,14 +262,29 @@ final class WhereTests: XCTestCase {
XCTAssertEqual(andWhere.predicate, andPredicate) XCTAssertEqual(andWhere.predicate, andPredicate)
XCTAssertEqual(andWhere, whereClause1 && whereClause2 && whereClause3) XCTAssertEqual(andWhere, whereClause1 && whereClause2 && whereClause3)
} }
do {
let andWhere = whereClause1 && whereClause2 && whereClause3
let noneWhere: Where<NSManagedObject>? = nil
let someWhere: Where<NSManagedObject>? = Where<NSManagedObject>("key4", isEqualTo: "value4")
let finalNoneWhere = andWhere &&? noneWhere
let finalSomeWhere = andWhere &&? someWhere
let unwrappedFinalSomeWhere = andWhere && someWhere!
XCTAssertEqual(andWhere.predicate, finalNoneWhere.predicate)
XCTAssertEqual(finalSomeWhere.predicate, unwrappedFinalSomeWhere.predicate)
}
do { do {
let orWhere = whereClause1 || whereClause2 || whereClause3 let orWhere = whereClause1 || whereClause2 || whereClause3
let orPredicate = NSCompoundPredicate( let orPredicate = NSCompoundPredicate(
type: .OrPredicateType, type: .or,
subpredicates: [ subpredicates: [
NSCompoundPredicate( NSCompoundPredicate(
type: .OrPredicateType, type: .or,
subpredicates: [whereClause1.predicate, whereClause2.predicate] subpredicates: [whereClause1.predicate, whereClause2.predicate]
), ),
whereClause3.predicate whereClause3.predicate
@@ -136,13 +293,28 @@ final class WhereTests: XCTestCase {
XCTAssertEqual(orWhere.predicate, orPredicate) XCTAssertEqual(orWhere.predicate, orPredicate)
XCTAssertEqual(orWhere, whereClause1 || whereClause2 || whereClause3) XCTAssertEqual(orWhere, whereClause1 || whereClause2 || whereClause3)
} }
do {
let orWhere = whereClause1 || whereClause2 || whereClause3
let noneWhere: Where<NSManagedObject>? = nil
let someWhere: Where<NSManagedObject>? = Where<NSManagedObject>("key4", isEqualTo: "value4")
let finalNoneWhere = orWhere &&? noneWhere
let finalSomeWhere = orWhere &&? someWhere
let unwrappedFinalSomeWhere = orWhere && someWhere!
XCTAssertEqual(orWhere.predicate, finalNoneWhere.predicate)
XCTAssertEqual(finalSomeWhere.predicate, unwrappedFinalSomeWhere.predicate)
}
} }
@objc @objc
dynamic func test_ThatWhereClauses_ApplyToFetchRequestsCorrectly() { dynamic func test_ThatWhereClauses_ApplyToFetchRequestsCorrectly() {
let whereClause = Where("key", isEqualTo: "value") let whereClause = Where<NSManagedObject>("key", isEqualTo: "value")
let request = NSFetchRequest() let request = CoreStoreFetchRequest()
whereClause.applyToFetchRequest(request) whereClause.applyToFetchRequest(request)
XCTAssertNotNil(request.predicate) XCTAssertNotNil(request.predicate)
XCTAssertEqual(request.predicate, whereClause.predicate) XCTAssertEqual(request.predicate, whereClause.predicate)

View File

@@ -1,6 +1,6 @@
The MIT License (MIT) The MIT License (MIT)
Copyright © 2014 John Rommel Estropia Copyright © 2018 John Rommel Estropia
Permission is hereby granted, free of charge, to any person obtaining a copy Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal of this software and associated documentation files (the "Software"), to deal

View File

@@ -2,7 +2,7 @@
// Package.swift // Package.swift
// CoreStore // CoreStore
// //
// Copyright © 2016 John Rommel Estropia // Copyright © 2018 John Rommel Estropia
// //
// Permission is hereby granted, free of charge, to any person obtaining a copy // Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal // of this software and associated documentation files (the "Software"), to deal
@@ -28,7 +28,7 @@ import PackageDescription
let targets: [Target] let targets: [Target]
#if os(iOS) #if os(iOS)
targets = [Target(name: "CoreStore iOS")] targets = [Target(name: "CoreStore iOS")]
#elseif os(OSX) #elseif os(macOS)
targets = [Target(name: "CoreStore OSX")] targets = [Target(name: "CoreStore OSX")]
#elseif os(watchOS) #elseif os(watchOS)
targets = [Target(name: "CoreStore watchOS")] targets = [Target(name: "CoreStore watchOS")]
@@ -41,11 +41,5 @@ targets = []
let package = Package( let package = Package(
name: "CoreStore", name: "CoreStore",
targets: targets, targets: targets,
dependencies: [
.Package(
url: "https://github.com/JohnEstropia/GCDKit.git",
"1.2.6"
)
],
exclude: ["Carthage", "CoreStoreDemo", "Sources/libA/images"] exclude: ["Carthage", "CoreStoreDemo", "Sources/libA/images"]
) )

View File

@@ -0,0 +1,53 @@
import UIKit
import CoreStore
/// Model Declaration =====
class Animal: CoreStoreObject {
let species = Value.Required<String>("species", initial: "Swift")
let master = Relationship.ToOne<Person>("master")
let color = Transformable.Optional<UIColor>("color", initial: .orange)
}
class Person: CoreStoreObject {
let name = Value.Optional<String>("name")
let pets = Relationship.ToManyUnordered<Animal>("pets", inverse: { $0.master })
}
/// =======================
/// Stack setup ===========
let dataStack = DataStack(
CoreStoreSchema(
modelVersion: "V1",
entities: [
Entity<Animal>("Animal"),
Entity<Person>("Person")
]
)
)
try dataStack.addStorageAndWait(SQLiteStore(fileName: "data.sqlite"))
/// =======================
/// Transactions ==========
dataStack.perform(synchronous: { transaction in
let animal = transaction.create(Into<Animal>())
animal.species .= "Sparrow"
animal.color .= .yellow
let person = transaction.create(Into<Person>())
person.name .= "John"
person.pets.value.insert(animal)
})
/// =======================
/// Accessing Objects =====
let bird = dataStack.fetchOne(From<Animal>().where(\.species == "Sparrow"))!
bird.species.value
bird.color.value
print(bird)
let owner = bird.master.value!
owner.name.value
owner.pets.count
print(owner)
/// =======================

View File

@@ -0,0 +1,4 @@
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<playground version='5.0' target-platform='ios' executeOnSourceChanges='false'>
<timeline fileName='timeline.xctimeline'/>
</playground>

View File

@@ -0,0 +1,4 @@
<?xml version="1.0" encoding="UTF-8"?>
<Workspace
version = "1.0">
</Workspace>

1241
README.md

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,278 @@
//
// AsynchronousDataTransaction.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
import CoreData
// MARK: - AsynchronousDataTransaction
/**
The `AsynchronousDataTransaction` provides an interface for `DynamicObject` creates, updates, and deletes. A transaction object should typically be only used from within a transaction block initiated from `DataStack.perform(asynchronous:...)`, or from `CoreStore.perform(synchronous:...)`.
*/
public final class AsynchronousDataTransaction: BaseDataTransaction {
/**
Cancels a transaction by throwing `CoreStoreError.userCancelled`.
```
try transaction.cancel()
```
- Important: Never use `try?` or `try!` on a `cancel()` call. Always use `try`. Using `try?` will swallow the cancellation and the transaction will proceed to commit as normal. Using `try!` will crash the app as `cancel()` will *always* throw an error.
*/
public func cancel() throws -> Never {
throw CoreStoreError.userCancelled
}
// MARK: - Result
/**
The `Result` contains the success or failure information for a completed transaction
*/
public enum Result<T> {
/**
`Result<T>.success` indicates that the transaction succeeded, either because the save succeeded or because there were no changes to save. The associated `userInfo` is the value returned from the transaction closure.
*/
case success(userInfo: T)
/**
`Result<T>.failure` indicates that the transaction either failed or was cancelled. The associated object for this value is a `CoreStoreError` enum value.
*/
case failure(error: CoreStoreError)
/**
Returns `true` if the result indicates `.success`, `false` if the result is `.failure`.
*/
public var boolValue: Bool {
switch self {
case .success: return true
case .failure: return false
}
}
// MARK: Internal
internal init(userInfo: T) {
self = .success(userInfo: userInfo)
}
internal init(error: CoreStoreError) {
self = .failure(error: error)
}
}
// MARK: -
// MARK: BaseDataTransaction
/**
Creates a new `NSManagedObject` or `CoreStoreObject` with the specified entity type.
- parameter into: the `Into` clause indicating the destination `NSManagedObject` or `CoreStoreObject` entity type and the destination configuration
- returns: a new `NSManagedObject` or `CoreStoreObject` instance of the specified entity type.
*/
public override func create<D>(_ into: Into<D>) -> D {
CoreStore.assert(
!self.isCommitted,
"Attempted to create an entity of type \(cs_typeName(into.entityClass)) from an already committed \(cs_typeName(self))."
)
return super.create(into)
}
/**
Returns an editable proxy of a specified `NSManagedObject` or `CoreStoreObject`.
- parameter object: the `NSManagedObject` or `CoreStoreObject` to be edited
- returns: an editable proxy for the specified `NSManagedObject` or `CoreStoreObject`.
*/
public override func edit<D: DynamicObject>(_ object: D?) -> D? {
CoreStore.assert(
!self.isCommitted,
"Attempted to update an entity of type \(cs_typeName(object)) from an already committed \(cs_typeName(self))."
)
return super.edit(object)
}
/**
Returns an editable proxy of the object with the specified `NSManagedObjectID`.
- parameter into: an `Into` clause specifying the entity type
- parameter objectID: the `NSManagedObjectID` for the object to be edited
- returns: an editable proxy for the specified `NSManagedObject` or `CoreStoreObject`.
*/
public override func edit<D>(_ into: Into<D>, _ objectID: NSManagedObjectID) -> D? {
CoreStore.assert(
!self.isCommitted,
"Attempted to update an entity of type \(cs_typeName(into.entityClass)) from an already committed \(cs_typeName(self))."
)
return super.edit(into, objectID)
}
/**
Deletes a specified `NSManagedObject` or `CoreStoreObject`.
- parameter object: the `NSManagedObject` or `CoreStoreObject` to be deleted
*/
public override func delete<D: DynamicObject>(_ object: D?) {
CoreStore.assert(
!self.isCommitted,
"Attempted to delete an entity of type \(cs_typeName(object)) from an already committed \(cs_typeName(self))."
)
super.delete(object)
}
/**
Deletes the specified `DynamicObject`s.
- parameter object1: the `DynamicObject` to be deleted
- parameter object2: another `DynamicObject` to be deleted
- parameter objects: other `DynamicObject`s to be deleted
*/
public override func delete<D: DynamicObject>(_ object1: D?, _ object2: D?, _ objects: D?...) {
CoreStore.assert(
!self.isCommitted,
"Attempted to delete an entities from an already committed \(cs_typeName(self))."
)
super.delete(([object1, object2] + objects).compactMap { $0 })
}
/**
Deletes the specified `DynamicObject`s.
- parameter objects: the `DynamicObject`s to be deleted
*/
public override func delete<S: Sequence>(_ objects: S) where S.Iterator.Element: DynamicObject {
CoreStore.assert(
!self.isCommitted,
"Attempted to delete an entities from an already committed \(cs_typeName(self))."
)
super.delete(objects)
}
// MARK: Internal
internal init(mainContext: NSManagedObjectContext, queue: DispatchQueue) {
super.init(mainContext: mainContext, queue: queue, supportsUndo: false, bypassesQueueing: false)
}
internal func autoCommit(_ completion: @escaping (_ hasChanges: Bool, _ error: CoreStoreError?) -> Void) {
self.isCommitted = true
let group = DispatchGroup()
group.enter()
self.context.saveAsynchronouslyWithCompletion { (hasChanges, error) -> Void in
completion(hasChanges, error)
self.result = (hasChanges, error)
group.leave()
}
group.wait()
self.context.reset()
}
// MARK: Deprecated
@available(*, deprecated, message: "Use the new auto-commiting methods `DataStack.perform(asynchronous:completion:)` or `DataStack.perform(asynchronous:success:failure:)`. Please read the documentation on the behavior of the new methods.")
public func commit(_ completion: @escaping (_ result: SaveResult) -> Void = { _ in }) {
CoreStore.assert(
self.transactionQueue.cs_isCurrentExecutionContext(),
"Attempted to commit a \(cs_typeName(self)) outside its designated queue."
)
CoreStore.assert(
!self.isCommitted,
"Attempted to commit a \(cs_typeName(self)) more than once."
)
self.autoCommit { (hasChanges, error) in
if let error = error {
completion(SaveResult(error))
}
else {
completion(SaveResult(hasChanges: hasChanges))
}
}
}
@available(*, deprecated, message: "Secondary tasks spawned from AsynchronousDataTransactions and SynchronousDataTransactions are no longer supported. ")
@discardableResult
public func beginSynchronous(_ closure: @escaping (_ transaction: SynchronousDataTransaction) -> Void) -> SaveResult? {
CoreStore.assert(
self.transactionQueue.cs_isCurrentExecutionContext(),
"Attempted to begin a child transaction from a \(cs_typeName(self)) outside its designated queue."
)
CoreStore.assert(
!self.isCommitted,
"Attempted to begin a child transaction from an already committed \(cs_typeName(self))."
)
let childTransaction = SynchronousDataTransaction(
mainContext: self.context,
queue: self.childTransactionQueue
)
childTransaction.transactionQueue.cs_sync {
closure(childTransaction)
if !childTransaction.isCommitted && childTransaction.hasChanges {
CoreStore.log(
.warning,
message: "The closure for the \(cs_typeName(childTransaction)) completed without being committed. All changes made within the transaction were discarded."
)
}
}
switch childTransaction.result {
case .none: return nil
case .some(let hasChanges, nil): return SaveResult(hasChanges: hasChanges)
case .some(_, let error?): return SaveResult(error)
}
}
}

View File

@@ -0,0 +1,47 @@
//
// AttributeProtocol.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
import CoreData
// MARK: - AttributeProtocol
internal protocol AttributeProtocol: class {
static var attributeType: NSAttributeType { get }
var keyPath: KeyPathString { get }
var isOptional: Bool { get }
var isTransient: Bool { get }
var allowsExternalBinaryDataStorage: Bool { get }
var versionHashModifier: () -> String? { get }
var renamingIdentifier: () -> String? { get }
var defaultValue: () -> Any? { get }
var affectedByKeyPaths: () -> Set<String> { get }
var rawObject: CoreStoreManagedObject? { get set }
var getter: CoreStoreManagedObject.CustomGetter? { get }
var setter: CoreStoreManagedObject.CustomSetter? { get }
}

View File

@@ -2,7 +2,7 @@
// BaseDataTransaction+Importing.swift // BaseDataTransaction+Importing.swift
// CoreStore // CoreStore
// //
// Copyright © 2015 John Rommel Estropia // Copyright © 2018 John Rommel Estropia
// //
// Permission is hereby granted, free of charge, to any person obtaining a copy // Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal // of this software and associated documentation files (the "Software"), to deal
@@ -36,27 +36,28 @@ public extension BaseDataTransaction {
- parameter into: an `Into` clause specifying the entity type - parameter into: an `Into` clause specifying the entity type
- parameter source: the object to import values from - parameter source: the object to import values from
- throws: an `ErrorType` thrown from any of the `ImportableObject` methods - throws: an `Error` thrown from any of the `ImportableObject` methods
- returns: the created `ImportableObject` instance, or `nil` if the import was ignored - returns: the created `ImportableObject` instance, or `nil` if the import was ignored
*/ */
public func importObject<T where T: NSManagedObject, T: ImportableObject>( public func importObject<D: ImportableObject>(
into: Into<T>, _ into: Into<D>,
source: T.ImportSource) throws -> T? { source: D.ImportSource) throws -> D? {
CoreStore.assert( CoreStore.assert(
self.isRunningInAllowedQueue(), self.isRunningInAllowedQueue(),
"Attempted to import an object of type \(cs_typeName(into.entityClass)) outside the transaction's designated queue." "Attempted to import an object of type \(cs_typeName(into.entityClass)) outside the transaction's designated queue."
) )
return try cs_autoreleasepool { return try autoreleasepool {
guard T.shouldInsertFromImportSource(source, inTransaction: self) else { let entityType = into.entityClass
guard entityType.shouldInsert(from: source, in: self) else {
return nil return nil
} }
let object = self.create(into) let object = self.create(into)
try object.didInsertFromImportSource(source, inTransaction: self) try object.didInsert(from: source, in: self)
return object return object
} }
} }
@@ -66,25 +67,25 @@ public extension BaseDataTransaction {
- parameter object: the `NSManagedObject` to update - parameter object: the `NSManagedObject` to update
- parameter source: the object to import values from - parameter source: the object to import values from
- throws: an `ErrorType` thrown from any of the `ImportableObject` methods - throws: an `Error` thrown from any of the `ImportableObject` methods
*/ */
public func importObject<T where T: NSManagedObject, T: ImportableObject>( public func importObject<D: ImportableObject>(
object: T, _ object: D,
source: T.ImportSource) throws { source: D.ImportSource) throws {
CoreStore.assert( CoreStore.assert(
self.isRunningInAllowedQueue(), self.isRunningInAllowedQueue(),
"Attempted to import an object of type \(cs_typeName(object)) outside the transaction's designated queue." "Attempted to import an object of type \(cs_typeName(object)) outside the transaction's designated queue."
) )
try cs_autoreleasepool { try autoreleasepool {
guard T.shouldInsertFromImportSource(source, inTransaction: self) else { let entityType = cs_dynamicType(of: object)
guard entityType.shouldInsert(from: source, in: self) else {
return return
} }
try object.didInsert(from: source, in: self)
try object.didInsertFromImportSource(source, inTransaction: self)
} }
} }
@@ -93,31 +94,31 @@ public extension BaseDataTransaction {
- parameter into: an `Into` clause specifying the entity type - parameter into: an `Into` clause specifying the entity type
- parameter sourceArray: the array of objects to import values from - parameter sourceArray: the array of objects to import values from
- throws: an `ErrorType` thrown from any of the `ImportableObject` methods - throws: an `Error` thrown from any of the `ImportableObject` methods
- returns: the array of created `ImportableObject` instances - returns: the array of created `ImportableObject` instances
*/ */
public func importObjects<T, S: SequenceType where T: NSManagedObject, T: ImportableObject, S.Generator.Element == T.ImportSource>( public func importObjects<D: ImportableObject, S: Sequence>(
into: Into<T>, _ into: Into<D>,
sourceArray: S) throws -> [T] { sourceArray: S) throws -> [D] where S.Iterator.Element == D.ImportSource {
CoreStore.assert( CoreStore.assert(
self.isRunningInAllowedQueue(), self.isRunningInAllowedQueue(),
"Attempted to import an object of type \(cs_typeName(into.entityClass)) outside the transaction's designated queue." "Attempted to import an object of type \(cs_typeName(into.entityClass)) outside the transaction's designated queue."
) )
return try cs_autoreleasepool { return try autoreleasepool {
return try sourceArray.flatMap { (source) -> T? in return try sourceArray.compactMap { (source) -> D? in
guard T.shouldInsertFromImportSource(source, inTransaction: self) else { let entityType = into.entityClass
guard entityType.shouldInsert(from: source, in: self) else {
return nil return nil
} }
return try autoreleasepool {
return try cs_autoreleasepool {
let object = self.create(into) let object = self.create(into)
try object.didInsertFromImportSource(source, inTransaction: self) try object.didInsert(from: source, in: self)
return object return object
} }
} }
@@ -129,46 +130,45 @@ public extension BaseDataTransaction {
- parameter into: an `Into` clause specifying the entity type - parameter into: an `Into` clause specifying the entity type
- parameter source: the object to import values from - parameter source: the object to import values from
- throws: an `ErrorType` thrown from any of the `ImportableUniqueObject` methods - throws: an `Error` thrown from any of the `ImportableUniqueObject` methods
- returns: the created/updated `ImportableUniqueObject` instance, or `nil` if the import was ignored - returns: the created/updated `ImportableUniqueObject` instance, or `nil` if the import was ignored
*/ */
public func importUniqueObject<T where T: NSManagedObject, T: ImportableUniqueObject>( public func importUniqueObject<D: ImportableUniqueObject>(
into: Into<T>, _ into: Into<D>,
source: T.ImportSource) throws -> T? { source: D.ImportSource) throws -> D? {
CoreStore.assert( CoreStore.assert(
self.isRunningInAllowedQueue(), self.isRunningInAllowedQueue(),
"Attempted to import an object of type \(cs_typeName(into.entityClass)) outside the transaction's designated queue." "Attempted to import an object of type \(cs_typeName(into.entityClass)) outside the transaction's designated queue."
) )
return try cs_autoreleasepool { return try autoreleasepool {
let uniqueIDKeyPath = T.uniqueIDKeyPath let entityType = into.entityClass
guard let uniqueIDValue = try T.uniqueIDFromImportSource(source, inTransaction: self) else { let uniqueIDKeyPath = entityType.uniqueIDKeyPath
guard let uniqueIDValue = try entityType.uniqueID(from: source, in: self) else {
return nil return nil
} }
if let object = self.fetchOne(From(T), Where(uniqueIDKeyPath, isEqualTo: uniqueIDValue)) { if let object = try self.fetchOne(From(entityType), Where<D>(uniqueIDKeyPath, isEqualTo: uniqueIDValue)) {
guard T.shouldUpdateFromImportSource(source, inTransaction: self) else { guard entityType.shouldUpdate(from: source, in: self) else {
return nil return nil
} }
try object.update(from: source, in: self)
try object.updateFromImportSource(source, inTransaction: self)
return object return object
} }
else { else {
guard T.shouldInsertFromImportSource(source, inTransaction: self) else { guard entityType.shouldInsert(from: source, in: self) else {
return nil return nil
} }
let object = self.create(into) let object = self.create(into)
object.uniqueIDValue = uniqueIDValue object.uniqueIDValue = uniqueIDValue
try object.didInsertFromImportSource(source, inTransaction: self) try object.didInsert(from: source, in: self)
return object return object
} }
} }
@@ -176,79 +176,80 @@ public extension BaseDataTransaction {
/** /**
Updates existing `ImportableUniqueObject`s or creates them by importing from the specified array of import sources. Updates existing `ImportableUniqueObject`s or creates them by importing from the specified array of import sources.
- Warning: While the array returned from `importUniqueObjects(...)` correctly maps to the order of `sourceArray`, the order of objects called with `ImportableUniqueObject` methods is arbitrary. Do not make assumptions that any particular object will be imported ahead or after another object. `ImportableUniqueObject` methods are called on the objects in the same order as they are in the `sourceArray`, and are returned in an array with that same order.
- Warning: If `sourceArray` contains multiple import sources with same ID, only the last `ImportSource` of the duplicates will be imported.
- parameter into: an `Into` clause specifying the entity type - parameter into: an `Into` clause specifying the entity type
- parameter sourceArray: the array of objects to import values from - parameter sourceArray: the array of objects to import values from
- parameter preProcess: a closure that lets the caller tweak the internal `UniqueIDType`-to-`ImportSource` mapping to be used for importing. Callers can remove from/add to/update `mapping` and return the updated array from the closure. - parameter preProcess: a closure that lets the caller tweak the internal `UniqueIDType`-to-`ImportSource` mapping to be used for importing. Callers can remove from/add to/update `mapping` and return the updated array from the closure.
- throws: an `ErrorType` thrown from any of the `ImportableUniqueObject` methods - throws: an `Error` thrown from any of the `ImportableUniqueObject` methods
- returns: the array of created/updated `ImportableUniqueObject` instances - returns: the array of created/updated `ImportableUniqueObject` instances
*/ */
public func importUniqueObjects<T, S: SequenceType where T: NSManagedObject, T: ImportableUniqueObject, S.Generator.Element == T.ImportSource>( public func importUniqueObjects<D: ImportableUniqueObject, S: Sequence>(
into: Into<T>, _ into: Into<D>,
sourceArray: S, sourceArray: S,
@noescape preProcess: (mapping: [T.UniqueIDType: T.ImportSource]) throws -> [T.UniqueIDType: T.ImportSource] = { $0 }) throws -> [T] { preProcess: @escaping (_ mapping: [D.UniqueIDType: D.ImportSource]) throws -> [D.UniqueIDType: D.ImportSource] = { $0 }) throws -> [D] where S.Iterator.Element == D.ImportSource {
CoreStore.assert( CoreStore.assert(
self.isRunningInAllowedQueue(), self.isRunningInAllowedQueue(),
"Attempted to import an object of type \(cs_typeName(into.entityClass)) outside the transaction's designated queue." "Attempted to import an object of type \(cs_typeName(into.entityClass)) outside the transaction's designated queue."
) )
return try cs_autoreleasepool { return try autoreleasepool {
var mapping = Dictionary<T.UniqueIDType, T.ImportSource>() let entityType = into.entityClass
let sortedIDs = try cs_autoreleasepool { var importSourceByID = Dictionary<D.UniqueIDType, D.ImportSource>()
let sortedIDs = try autoreleasepool {
return try sourceArray.flatMap { (source) -> T.UniqueIDType? in
return try sourceArray.compactMap { (source) -> D.UniqueIDType? in
guard let uniqueIDValue = try T.uniqueIDFromImportSource(source, inTransaction: self) else { guard let uniqueIDValue = try entityType.uniqueID(from: source, in: self) else {
return nil return nil
} }
importSourceByID[uniqueIDValue] = source // effectively replaces duplicate with the latest
mapping[uniqueIDValue] = source
return uniqueIDValue return uniqueIDValue
} }
} }
mapping = try cs_autoreleasepool { try preProcess(mapping: mapping) } importSourceByID = try autoreleasepool { try preProcess(importSourceByID) }
var objects = Dictionary<T.UniqueIDType, T>() var existingObjectsByID = Dictionary<D.UniqueIDType, D>()
for object in self.fetchAll(From(T), Where(T.uniqueIDKeyPath, isMemberOf: sortedIDs)) ?? [] { try self
.fetchAll(From(entityType), Where<D>(entityType.uniqueIDKeyPath, isMemberOf: sortedIDs))
.forEach { existingObjectsByID[$0.uniqueIDValue] = $0 }
var processedObjectIDs = Set<D.UniqueIDType>()
var result = [D]()
for objectID in sortedIDs where !processedObjectIDs.contains(objectID) {
try cs_autoreleasepool { guard let source = importSourceByID[objectID] else {
let uniqueIDValue = object.uniqueIDValue continue
}
guard let source = mapping.removeValueForKey(uniqueIDValue) try autoreleasepool {
where T.shouldUpdateFromImportSource(source, inTransaction: self) else {
if let object = existingObjectsByID[objectID] {
guard entityType.shouldUpdate(from: source, in: self) else {
return return
}
try object.update(from: source, in: self)
result.append(object)
} }
else if entityType.shouldInsert(from: source, in: self) {
try object.updateFromImportSource(source, inTransaction: self)
objects[uniqueIDValue] = object
}
}
for (uniqueIDValue, source) in mapping {
try cs_autoreleasepool {
guard T.shouldInsertFromImportSource(source, inTransaction: self) else {
return let object = self.create(into)
object.uniqueIDValue = objectID
try object.didInsert(from: source, in: self)
result.append(object)
} }
processedObjectIDs.insert(objectID)
let object = self.create(into)
object.uniqueIDValue = uniqueIDValue
try object.didInsertFromImportSource(source, inTransaction: self)
objects[uniqueIDValue] = object
} }
} }
return result
return sortedIDs.flatMap { objects[$0] }
} }
} }
} }

View File

@@ -0,0 +1,573 @@
//
// BaseDataTransaction+Querying.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
import CoreData
// MARK: - DataTransaction
extension BaseDataTransaction: FetchableSource, QueryableSource {
/**
Deletes all `DynamicObject`s that satisfy the specified `DeleteClause`s. Accepts `Where`, `OrderBy`, and `Tweak` clauses.
- parameter from: a `From` clause indicating the entity type
- parameter deleteClauses: a series of `DeleteClause` instances for the delete request. Accepts `Where`, `OrderBy`, and `Tweak` clauses.
- returns: the number of `DynamicObject`s deleted
*/
@discardableResult
public func deleteAll<D>(_ from: From<D>, _ deleteClauses: DeleteClause...) throws -> Int {
CoreStore.assert(
self.isRunningInAllowedQueue(),
"Attempted to delete from a \(cs_typeName(self)) outside its designated queue."
)
return try self.context.deleteAll(from, deleteClauses)
}
/**
Deletes all `DynamicObject`s that satisfy the specified `DeleteClause`s. Accepts `Where`, `OrderBy`, and `Tweak` clauses.
- parameter from: a `From` clause indicating the entity type
- parameter deleteClauses: a series of `DeleteClause` instances for the delete request. Accepts `Where`, `OrderBy`, and `Tweak` clauses.
- returns: the number of `DynamicObject`s deleted
*/
@discardableResult
public func deleteAll<D>(_ from: From<D>, _ deleteClauses: [DeleteClause]) throws -> Int {
CoreStore.assert(
self.isRunningInAllowedQueue(),
"Attempted to delete from a \(cs_typeName(self)) outside its designated queue."
)
return try self.context.deleteAll(from, deleteClauses)
}
/**
Deletes all `DynamicObject`s that satisfy the specified conditions.
```
transaction.deleteAll(From<Person>().where(\.age > 50))
```
- parameter clauseChain: a `FetchChainableBuilderType` clause chain created from a `From` clause
- returns: the number of `DynamicObject`s deleted
*/
@discardableResult
public func deleteAll<B: FetchChainableBuilderType>(_ clauseChain: B) throws -> Int {
CoreStore.assert(
self.isRunningInAllowedQueue(),
"Attempted to delete from a \(cs_typeName(self)) outside its designated queue."
)
return try self.context.deleteAll(clauseChain.from, clauseChain.fetchClauses)
}
// MARK: FetchableSource
/**
Fetches the `DynamicObject` instance in the transaction's context from a reference created from a transaction or from a different managed object context.
- parameter object: a reference to the object created/fetched outside the transaction
- returns: the `DynamicObject` instance if the object exists in the transaction, or `nil` if not found.
*/
public func fetchExisting<D: DynamicObject>(_ object: D) -> D? {
return self.context.fetchExisting(object)
}
/**
Fetches the `DynamicObject` instance in the transaction's context from an `NSManagedObjectID`.
- parameter objectID: the `NSManagedObjectID` for the object
- returns: the `DynamicObject` instance if the object exists in the transaction, or `nil` if not found.
*/
public func fetchExisting<D: DynamicObject>(_ objectID: NSManagedObjectID) -> D? {
return self.context.fetchExisting(objectID)
}
/**
Fetches the `DynamicObject` instances in the transaction's context from references created from a transaction or from a different managed object context.
- parameter objects: an array of `DynamicObject`s created/fetched outside the transaction
- returns: the `DynamicObject` array for objects that exists in the transaction
*/
public func fetchExisting<D: DynamicObject, S: Sequence>(_ objects: S) -> [D] where S.Iterator.Element == D {
return self.context.fetchExisting(objects)
}
/**
Fetches the `DynamicObject` instances in the transaction's context from a list of `NSManagedObjectID`.
- parameter objectIDs: the `NSManagedObjectID` array for the objects
- returns: the `DynamicObject` array for objects that exists in the transaction
*/
public func fetchExisting<D: DynamicObject, S: Sequence>(_ objectIDs: S) -> [D] where S.Iterator.Element == NSManagedObjectID {
return self.context.fetchExisting(objectIDs)
}
/**
Fetches the first `DynamicObject` instance that satisfies the specified `FetchClause`s. Accepts `Where`, `OrderBy`, and `Tweak` clauses.
- parameter from: a `From` clause indicating the entity type
- parameter fetchClauses: a series of `FetchClause` instances for the fetch request. Accepts `Where`, `OrderBy`, and `Tweak` clauses.
- returns: the first `DynamicObject` instance that satisfies the specified `FetchClause`s, or `nil` if no match was found
- throws: a `CoreStoreError` value indicating the failure if the specified entity could not be found in any store's schema.
*/
public func fetchOne<D>(_ from: From<D>, _ fetchClauses: FetchClause...) throws -> D? {
CoreStore.assert(
self.isRunningInAllowedQueue(),
"Attempted to fetch from a \(cs_typeName(self)) outside its designated queue."
)
return try self.context.fetchOne(from, fetchClauses)
}
/**
Fetches the first `DynamicObject` instance that satisfies the specified `FetchClause`s. Accepts `Where`, `OrderBy`, and `Tweak` clauses.
- parameter from: a `From` clause indicating the entity type
- parameter fetchClauses: a series of `FetchClause` instances for the fetch request. Accepts `Where`, `OrderBy`, and `Tweak` clauses.
- returns: the first `DynamicObject` instance that satisfies the specified `FetchClause`s, or `nil` if no match was found
- throws: a `CoreStoreError` value indicating the failure if the specified entity could not be found in any store's schema.
*/
public func fetchOne<D>(_ from: From<D>, _ fetchClauses: [FetchClause]) throws -> D? {
CoreStore.assert(
self.isRunningInAllowedQueue(),
"Attempted to fetch from a \(cs_typeName(self)) outside its designated queue."
)
return try self.context.fetchOne(from, fetchClauses)
}
/**
Fetches the first `DynamicObject` instance that satisfies the specified `FetchChainableBuilderType` built from a chain of clauses.
```
let youngestTeen = transaction.fetchOne(
From<MyPersonEntity>()
.where(\.age > 18)
.orderBy(.ascending(\.age))
)
```
- parameter clauseChain: a `FetchChainableBuilderType` built from a chain of clauses
- returns: the first `DynamicObject` instance that satisfies the specified `FetchChainableBuilderType`, or `nil` if no match was found
- throws: a `CoreStoreError` value indicating the failure if the specified entity could not be found in any store's schema.
*/
public func fetchOne<B: FetchChainableBuilderType>(_ clauseChain: B) throws -> B.ObjectType? {
CoreStore.assert(
self.isRunningInAllowedQueue(),
"Attempted to fetch from a \(cs_typeName(self)) outside its designated queue."
)
return try self.context.fetchOne(clauseChain)
}
/**
Fetches all `DynamicObject` instances that satisfy the specified `FetchClause`s. Accepts `Where`, `OrderBy`, and `Tweak` clauses.
- parameter from: a `From` clause indicating the entity type
- parameter fetchClauses: a series of `FetchClause` instances for the fetch request. Accepts `Where`, `OrderBy`, and `Tweak` clauses.
- returns: all `DynamicObject` instances that satisfy the specified `FetchClause`s, or an empty array if no match was found
- throws: a `CoreStoreError` value indicating the failure if the specified entity could not be found in any store's schema.
*/
public func fetchAll<D>(_ from: From<D>, _ fetchClauses: FetchClause...) throws -> [D] {
CoreStore.assert(
self.isRunningInAllowedQueue(),
"Attempted to fetch from a \(cs_typeName(self)) outside its designated queue."
)
return try self.context.fetchAll(from, fetchClauses)
}
/**
Fetches all `DynamicObject` instances that satisfy the specified `FetchClause`s. Accepts `Where`, `OrderBy`, and `Tweak` clauses.
- parameter from: a `From` clause indicating the entity type
- parameter fetchClauses: a series of `FetchClause` instances for the fetch request. Accepts `Where`, `OrderBy`, and `Tweak` clauses.
- returns: all `DynamicObject` instances that satisfy the specified `FetchClause`s, or an empty array if no match was found
- throws: a `CoreStoreError` value indicating the failure if the specified entity could not be found in any store's schema.
*/
public func fetchAll<D>(_ from: From<D>, _ fetchClauses: [FetchClause]) throws -> [D] {
CoreStore.assert(
self.isRunningInAllowedQueue(),
"Attempted to fetch from a \(cs_typeName(self)) outside its designated queue."
)
return try self.context.fetchAll(from, fetchClauses)
}
/**
Fetches all `DynamicObject` instances that satisfy the specified `FetchChainableBuilderType` built from a chain of clauses.
```
let people = transaction.fetchAll(
From<MyPersonEntity>()
.where(\.age > 18)
.orderBy(.ascending(\.age))
)
```
- parameter clauseChain: a `FetchChainableBuilderType` built from a chain of clauses
- returns: all `DynamicObject` instances that satisfy the specified `FetchChainableBuilderType`, or an empty array if no match was found
- throws: a `CoreStoreError` value indicating the failure if the specified entity could not be found in any store's schema.
*/
public func fetchAll<B: FetchChainableBuilderType>(_ clauseChain: B) throws -> [B.ObjectType] {
CoreStore.assert(
self.isRunningInAllowedQueue(),
"Attempted to fetch from a \(cs_typeName(self)) outside its designated queue."
)
return try self.context.fetchAll(clauseChain)
}
/**
Fetches the number of `DynamicObject`s that satisfy the specified `FetchClause`s. Accepts `Where`, `OrderBy`, and `Tweak` clauses.
- parameter from: a `From` clause indicating the entity type
- parameter fetchClauses: a series of `FetchClause` instances for the fetch request. Accepts `Where`, `OrderBy`, and `Tweak` clauses.
- returns: the number of `DynamicObject`s that satisfy the specified `FetchClause`s
- throws: a `CoreStoreError` value indicating the failure if the specified entity could not be found in any store's schema.
*/
public func fetchCount<D>(_ from: From<D>, _ fetchClauses: FetchClause...) throws -> Int {
CoreStore.assert(
self.isRunningInAllowedQueue(),
"Attempted to fetch from a \(cs_typeName(self)) outside its designated queue."
)
return try self.context.fetchCount(from, fetchClauses)
}
/**
Fetches the number of `DynamicObject`s that satisfy the specified `FetchClause`s. Accepts `Where`, `OrderBy`, and `Tweak` clauses.
- parameter from: a `From` clause indicating the entity type
- parameter fetchClauses: a series of `FetchClause` instances for the fetch request. Accepts `Where`, `OrderBy`, and `Tweak` clauses.
- returns: the number of `DynamicObject`s that satisfy the specified `FetchClause`s
- throws: a `CoreStoreError` value indicating the failure if the specified entity could not be found in any store's schema.
*/
public func fetchCount<D>(_ from: From<D>, _ fetchClauses: [FetchClause]) throws -> Int {
CoreStore.assert(
self.isRunningInAllowedQueue(),
"Attempted to fetch from a \(cs_typeName(self)) outside its designated queue."
)
return try self.context.fetchCount(from, fetchClauses)
}
/**
Fetches the number of `DynamicObject`s that satisfy the specified `FetchChainableBuilderType` built from a chain of clauses.
```
let numberOfAdults = transaction.fetchCount(
From<MyPersonEntity>()
.where(\.age > 18)
.orderBy(.ascending(\.age))
)
```
- parameter clauseChain: a `FetchChainableBuilderType` built from a chain of clauses
- returns: the number of `DynamicObject`s that satisfy the specified `FetchChainableBuilderType`
- throws: a `CoreStoreError` value indicating the failure if the specified entity could not be found in any store's schema.
*/
public func fetchCount<B: FetchChainableBuilderType>(_ clauseChain: B) throws -> Int {
CoreStore.assert(
self.isRunningInAllowedQueue(),
"Attempted to fetch from a \(cs_typeName(self)) outside its designated queue."
)
return try self.context.fetchCount(clauseChain)
}
/**
Fetches the `NSManagedObjectID` for the first `DynamicObject` that satisfies the specified `FetchClause`s. Accepts `Where`, `OrderBy`, and `Tweak` clauses.
- parameter from: a `From` clause indicating the entity type
- parameter fetchClauses: a series of `FetchClause` instances for the fetch request. Accepts `Where`, `OrderBy`, and `Tweak` clauses.
- returns: the `NSManagedObjectID` for the first `DynamicObject` that satisfies the specified `FetchClause`s, or `nil` if no match was found
- throws: a `CoreStoreError` value indicating the failure if the specified entity could not be found in any store's schema.
*/
public func fetchObjectID<D>(_ from: From<D>, _ fetchClauses: FetchClause...) throws -> NSManagedObjectID? {
CoreStore.assert(
self.isRunningInAllowedQueue(),
"Attempted to fetch from a \(cs_typeName(self)) outside its designated queue."
)
return try self.context.fetchObjectID(from, fetchClauses)
}
/**
Fetches the `NSManagedObjectID` for the first `DynamicObject` that satisfies the specified `FetchClause`s. Accepts `Where`, `OrderBy`, and `Tweak` clauses.
- parameter from: a `From` clause indicating the entity type
- parameter fetchClauses: a series of `FetchClause` instances for the fetch request. Accepts `Where`, `OrderBy`, and `Tweak` clauses.
- returns: the `NSManagedObjectID` for the first `DynamicObject` that satisfies the specified `FetchClause`s, or `nil` if no match was found
- throws: a `CoreStoreError` value indicating the failure if the specified entity could not be found in any store's schema.
*/
public func fetchObjectID<D>(_ from: From<D>, _ fetchClauses: [FetchClause]) throws -> NSManagedObjectID? {
CoreStore.assert(
self.isRunningInAllowedQueue(),
"Attempted to fetch from a \(cs_typeName(self)) outside its designated queue."
)
return try self.context.fetchObjectID(from, fetchClauses)
}
/**
Fetches the `NSManagedObjectID` for the first `DynamicObject` that satisfies the specified `FetchChainableBuilderType` built from a chain of clauses.
```
let youngestTeenID = transaction.fetchObjectID(
From<MyPersonEntity>()
.where(\.age > 18)
.orderBy(.ascending(\.age))
)
```
- parameter clauseChain: a `FetchChainableBuilderType` built from a chain of clauses
- returns: the `NSManagedObjectID` for the first `DynamicObject` that satisfies the specified `FetchChainableBuilderType`, or `nil` if no match was found
- throws: a `CoreStoreError` value indicating the failure if the specified entity could not be found in any store's schema.
*/
public func fetchObjectID<B: FetchChainableBuilderType>(_ clauseChain: B) throws -> NSManagedObjectID? {
CoreStore.assert(
self.isRunningInAllowedQueue(),
"Attempted to fetch from a \(cs_typeName(self)) outside its designated queue."
)
return try self.context.fetchObjectID(clauseChain)
}
/**
Fetches the `NSManagedObjectID` for all `DynamicObject`s that satisfy the specified `FetchClause`s. Accepts `Where`, `OrderBy`, and `Tweak` clauses.
- parameter from: a `From` clause indicating the entity type
- parameter fetchClauses: a series of `FetchClause` instances for the fetch request. Accepts `Where`, `OrderBy`, and `Tweak` clauses.
- returns: the `NSManagedObjectID` for all `DynamicObject`s that satisfy the specified `FetchClause`s, or an empty array if no match was found
- throws: a `CoreStoreError` value indicating the failure if the specified entity could not be found in any store's schema.
*/
public func fetchObjectIDs<D>(_ from: From<D>, _ fetchClauses: FetchClause...) throws -> [NSManagedObjectID] {
CoreStore.assert(
self.isRunningInAllowedQueue(),
"Attempted to fetch from a \(cs_typeName(self)) outside its designated queue."
)
return try self.context.fetchObjectIDs(from, fetchClauses)
}
/**
Fetches the `NSManagedObjectID` for all `DynamicObject`s that satisfy the specified `FetchClause`s. Accepts `Where`, `OrderBy`, and `Tweak` clauses.
- parameter from: a `From` clause indicating the entity type
- parameter fetchClauses: a series of `FetchClause` instances for the fetch request. Accepts `Where`, `OrderBy`, and `Tweak` clauses.
- returns: the `NSManagedObjectID` for all `DynamicObject`s that satisfy the specified `FetchClause`s, or an empty array if no match was found
- throws: a `CoreStoreError` value indicating the failure if the specified entity could not be found in any store's schema.
*/
public func fetchObjectIDs<D>(_ from: From<D>, _ fetchClauses: [FetchClause]) throws -> [NSManagedObjectID] {
CoreStore.assert(
self.isRunningInAllowedQueue(),
"Attempted to fetch from a \(cs_typeName(self)) outside its designated queue."
)
return try self.context.fetchObjectIDs(from, fetchClauses)
}
/**
Fetches the `NSManagedObjectID` for all `DynamicObject`s that satisfy the specified `FetchChainableBuilderType` built from a chain of clauses.
```
let idsOfAdults = transaction.fetchObjectIDs(
From<MyPersonEntity>()
.where(\.age > 18)
.orderBy(.ascending(\.age))
)
```
- parameter clauseChain: a `FetchChainableBuilderType` built from a chain of clauses
- returns: the `NSManagedObjectID` for all `DynamicObject`s that satisfy the specified `FetchChainableBuilderType`, or an empty array if no match was found
- throws: a `CoreStoreError` value indicating the failure if the specified entity could not be found in any store's schema.
*/
public func fetchObjectIDs<B: FetchChainableBuilderType>(_ clauseChain: B) throws -> [NSManagedObjectID] {
CoreStore.assert(
self.isRunningInAllowedQueue(),
"Attempted to fetch from a \(cs_typeName(self)) outside its designated queue."
)
return try self.context.fetchObjectIDs(clauseChain)
}
// MARK: QueryableSource
/**
Queries aggregate values as specified by the `QueryClause`s. Requires at least a `Select` clause, and optional `Where`, `OrderBy`, `GroupBy`, and `Tweak` clauses.
A "query" differs from a "fetch" in that it only retrieves values already stored in the persistent store. As such, values from unsaved transactions or contexts will not be incorporated in the query result.
- parameter from: a `From` clause indicating the entity type
- parameter selectClause: a `Select<U>` clause indicating the properties to fetch, and with the generic type indicating the return type.
- parameter queryClauses: a series of `QueryClause` instances for the query request. Accepts `Where`, `OrderBy`, `GroupBy`, and `Tweak` clauses.
- returns: the result of the the query, or `nil` if no match was found. The type of the return value is specified by the generic type of the `Select<U>` parameter.
- throws: a `CoreStoreError` value indicating the failure if the specified entity could not be found in any store's schema.
*/
public func queryValue<D, U: QueryableAttributeType>(_ from: From<D>, _ selectClause: Select<D, U>, _ queryClauses: QueryClause...) throws -> U? {
CoreStore.assert(
self.isRunningInAllowedQueue(),
"Attempted to query from a \(cs_typeName(self)) outside its designated queue."
)
return try self.context.queryValue(from, selectClause, queryClauses)
}
/**
Queries aggregate values or aggregates as specified by the `QueryClause`s. Requires at least a `Select` clause, and optional `Where`, `OrderBy`, `GroupBy`, and `Tweak` clauses.
A "query" differs from a "fetch" in that it only retrieves values already stored in the persistent store. As such, values from unsaved transactions or contexts will not be incorporated in the query result.
- parameter from: a `From` clause indicating the entity type
- parameter selectClause: a `Select<U>` clause indicating the properties to fetch, and with the generic type indicating the return type.
- parameter queryClauses: a series of `QueryClause` instances for the query request. Accepts `Where`, `OrderBy`, `GroupBy`, and `Tweak` clauses.
- returns: the result of the the query, or `nil` if no match was found. The type of the return value is specified by the generic type of the `Select<U>` parameter.
- throws: a `CoreStoreError` value indicating the failure if the specified entity could not be found in any store's schema.
*/
public func queryValue<D, U: QueryableAttributeType>(_ from: From<D>, _ selectClause: Select<D, U>, _ queryClauses: [QueryClause]) throws -> U? {
CoreStore.assert(
self.isRunningInAllowedQueue(),
"Attempted to query from a \(cs_typeName(self)) outside its designated queue."
)
return try self.context.queryValue(from, selectClause, queryClauses)
}
/**
Queries a property value or aggregate as specified by the `QueryChainableBuilderType` built from a chain of clauses.
A "query" differs from a "fetch" in that it only retrieves values already stored in the persistent store. As such, values from unsaved transactions or contexts will not be incorporated in the query result.
```
let averageAdultAge = transaction.queryValue(
From<MyPersonEntity>()
.select(Int.self, .average(\.age))
.where(\.age > 18)
)
```
- parameter clauseChain: a `QueryChainableBuilderType` indicating the property/aggregate to fetch and the series of queries for the request.
- returns: the result of the the query as specified by the `QueryChainableBuilderType`, or `nil` if no match was found.
- throws: a `CoreStoreError` value indicating the failure if the specified entity could not be found in any store's schema.
*/
public func queryValue<B: QueryChainableBuilderType>(_ clauseChain: B) throws -> B.ResultType? where B.ResultType: QueryableAttributeType {
CoreStore.assert(
self.isRunningInAllowedQueue(),
"Attempted to query from a \(cs_typeName(self)) outside its designated queue."
)
return try self.context.queryValue(clauseChain.from, clauseChain.select, clauseChain.queryClauses)
}
/**
Queries a dictionary of attribute values as specified by the `QueryClause`s. Requires at least a `Select` clause, and optional `Where`, `OrderBy`, `GroupBy`, and `Tweak` clauses.
A "query" differs from a "fetch" in that it only retrieves values already stored in the persistent store. As such, values from unsaved transactions or contexts will not be incorporated in the query result.
- parameter from: a `From` clause indicating the entity type
- parameter selectClause: a `Select<U>` clause indicating the properties to fetch, and with the generic type indicating the return type.
- parameter queryClauses: a series of `QueryClause` instances for the query request. Accepts `Where`, `OrderBy`, `GroupBy`, and `Tweak` clauses.
- returns: the result of the the query. The type of the return value is specified by the generic type of the `Select<U>` parameter.
- throws: a `CoreStoreError` value indicating the failure if the specified entity could not be found in any store's schema.
*/
public func queryAttributes<D>(_ from: From<D>, _ selectClause: Select<D, NSDictionary>, _ queryClauses: QueryClause...) throws -> [[String: Any]] {
CoreStore.assert(
self.isRunningInAllowedQueue(),
"Attempted to query from a \(cs_typeName(self)) outside its designated queue."
)
return try self.context.queryAttributes(from, selectClause, queryClauses)
}
/**
Queries a dictionary of attribute values as specified by the `QueryClause`s. Requires at least a `Select` clause, and optional `Where`, `OrderBy`, `GroupBy`, and `Tweak` clauses.
A "query" differs from a "fetch" in that it only retrieves values already stored in the persistent store. As such, values from unsaved transactions or contexts will not be incorporated in the query result.
- parameter from: a `From` clause indicating the entity type
- parameter selectClause: a `Select<U>` clause indicating the properties to fetch, and with the generic type indicating the return type.
- parameter queryClauses: a series of `QueryClause` instances for the query request. Accepts `Where`, `OrderBy`, `GroupBy`, and `Tweak` clauses.
- returns: the result of the the query. The type of the return value is specified by the generic type of the `Select<U>` parameter.
- throws: a `CoreStoreError` value indicating the failure if the specified entity could not be found in any store's schema.
*/
public func queryAttributes<D>(_ from: From<D>, _ selectClause: Select<D, NSDictionary>, _ queryClauses: [QueryClause]) throws -> [[String: Any]] {
CoreStore.assert(
self.isRunningInAllowedQueue(),
"Attempted to query from a \(cs_typeName(self)) outside its designated queue."
)
return try self.context.queryAttributes(from, selectClause, queryClauses)
}
/**
Queries a dictionary of attribute values or as specified by the `QueryChainableBuilderType` built from a chain of clauses.
A "query" differs from a "fetch" in that it only retrieves values already stored in the persistent store. As such, values from unsaved transactions or contexts will not be incorporated in the query result.
```
let results = dataStack.queryAttributes(
From<MyPersonEntity>()
.select(
NSDictionary.self,
.attribute(\.age, as: "age"),
.count(\.age, as: "numberOfPeople")
)
.groupBy(\.age)
)
for dictionary in results! {
let age = dictionary["age"] as! Int
let count = dictionary["numberOfPeople"] as! Int
print("There are \(count) people who are \(age) years old."
}
```
- parameter clauseChain: a `QueryChainableBuilderType` indicating the properties to fetch and the series of queries for the request.
- returns: the result of the the query as specified by the `QueryChainableBuilderType`
- throws: a `CoreStoreError` value indicating the failure if the specified entity could not be found in any store's schema.
*/
public func queryAttributes<B: QueryChainableBuilderType>(_ clauseChain: B) throws -> [[String: Any]] where B.ResultType == NSDictionary {
CoreStore.assert(
self.isRunningInAllowedQueue(),
"Attempted to query from a \(cs_typeName(self)) outside its designated queue."
)
return try self.context.queryAttributes(clauseChain.from, clauseChain.select, clauseChain.queryClauses)
}
// MARK: FetchableSource, QueryableSource
/**
The internal `NSManagedObjectContext` managed by this instance. Using this context directly should typically be avoided, and is provided by CoreStore only for extremely specialized cases.
*/
public func unsafeContext() -> NSManagedObjectContext {
return self.context
}
// MARK: Obsoleted
@available(*, obsoleted: 3.1, renamed: "unsafeContext()")
public func internalContext() -> NSManagedObjectContext {
fatalError()
}
}

View File

@@ -2,7 +2,7 @@
// BaseDataTransaction.swift // BaseDataTransaction.swift
// CoreStore // CoreStore
// //
// Copyright © 2014 John Rommel Estropia // Copyright © 2018 John Rommel Estropia
// //
// Permission is hereby granted, free of charge, to any person obtaining a copy // Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal // of this software and associated documentation files (the "Software"), to deal
@@ -25,9 +25,6 @@
import Foundation import Foundation
import CoreData import CoreData
#if USE_FRAMEWORKS
import GCDKit
#endif
// MARK: - BaseDataTransaction // MARK: - BaseDataTransaction
@@ -48,32 +45,36 @@ public /*abstract*/ class BaseDataTransaction {
} }
/** /**
Creates a new `NSManagedObject` with the specified entity type. Creates a new `NSManagedObject` or `CoreStoreObject` with the specified entity type.
- parameter into: the `Into` clause indicating the destination `NSManagedObject` entity type and the destination configuration - parameter into: the `Into` clause indicating the destination `NSManagedObject` or `CoreStoreObject` entity type and the destination configuration
- returns: a new `NSManagedObject` instance of the specified entity type. - returns: a new `NSManagedObject` or `CoreStoreObject` instance of the specified entity type.
*/ */
public func create<T: NSManagedObject>(into: Into<T>) -> T { public func create<D>(_ into: Into<D>) -> D {
let entityClass = into.entityClass
CoreStore.assert( CoreStore.assert(
self.isRunningInAllowedQueue(), self.isRunningInAllowedQueue(),
"Attempted to create an entity of type \(cs_typeName(T)) outside its designated queue." "Attempted to create an entity of type \(cs_typeName(entityClass)) outside its designated queue."
) )
let context = self.context let context = self.context
let entityClass = (into.entityClass as! NSManagedObject.Type) let dataStack = context.parentStack!
let entityIdentifier = EntityIdentifier(entityClass)
if into.inferStoreIfPossible { if into.inferStoreIfPossible {
switch context.parentStack!.persistentStoreForEntityClass( switch dataStack.persistentStore(
entityClass, for: entityIdentifier,
configuration: nil, configuration: nil,
inferStoreIfPossible: true inferStoreIfPossible: true
) { ) {
case (let persistentStore?, _): case (let persistentStore?, _):
let object = entityClass.createInContext(context) as! T return entityClass.cs_forceCreate(
context.assignObject(object, toPersistentStore: persistentStore) entityDescription: dataStack.entityDescription(for: entityIdentifier)!,
return object into: context,
assignTo: persistentStore
)
case (nil, true): case (nil, true):
CoreStore.abort("Attempted to create an entity of type \(cs_typeName(entityClass)) with ambiguous destination persistent store, but the configuration name was not specified.") CoreStore.abort("Attempted to create an entity of type \(cs_typeName(entityClass)) with ambiguous destination persistent store, but the configuration name was not specified.")
@@ -84,17 +85,19 @@ public /*abstract*/ class BaseDataTransaction {
} }
else { else {
switch context.parentStack!.persistentStoreForEntityClass( switch dataStack.persistentStore(
entityClass, for: entityIdentifier,
configuration: into.configuration configuration: into.configuration
?? into.dynamicType.defaultConfigurationName, ?? DataStack.defaultConfigurationName,
inferStoreIfPossible: false inferStoreIfPossible: false
) { ) {
case (let persistentStore?, _): case (let persistentStore?, _):
let object = entityClass.createInContext(context) as! T return entityClass.cs_forceCreate(
context.assignObject(object, toPersistentStore: persistentStore) entityDescription: dataStack.entityDescription(for: entityIdentifier)!,
return object into: context,
assignTo: persistentStore
)
case (nil, true): case (nil, true):
CoreStore.abort("Attempted to create an entity of type \(cs_typeName(entityClass)) with ambiguous destination persistent store, but the configuration name was not specified.") CoreStore.abort("Attempted to create an entity of type \(cs_typeName(entityClass)) with ambiguous destination persistent store, but the configuration name was not specified.")
@@ -113,13 +116,12 @@ public /*abstract*/ class BaseDataTransaction {
} }
/** /**
Returns an editable proxy of a specified `NSManagedObject`. Returns an editable proxy of a specified `NSManagedObject` or `CoreStoreObject`.
- parameter object: the `NSManagedObject` type to be edited - parameter object: the `NSManagedObject` or `CoreStoreObject` type to be edited
- returns: an editable proxy for the specified `NSManagedObject`. - returns: an editable proxy for the specified `NSManagedObject` or `CoreStoreObject`.
*/ */
@warn_unused_result public func edit<D: DynamicObject>(_ object: D?) -> D? {
public func edit<T: NSManagedObject>(object: T?) -> T? {
CoreStore.assert( CoreStore.assert(
self.isRunningInAllowedQueue(), self.isRunningInAllowedQueue(),
@@ -137,67 +139,64 @@ public /*abstract*/ class BaseDataTransaction {
- parameter into: an `Into` clause specifying the entity type - parameter into: an `Into` clause specifying the entity type
- parameter objectID: the `NSManagedObjectID` for the object to be edited - parameter objectID: the `NSManagedObjectID` for the object to be edited
- returns: an editable proxy for the specified `NSManagedObject`. - returns: an editable proxy for the specified `NSManagedObject` or `CoreStoreObject`.
*/ */
@warn_unused_result public func edit<D>(_ into: Into<D>, _ objectID: NSManagedObjectID) -> D? {
public func edit<T: NSManagedObject>(into: Into<T>, _ objectID: NSManagedObjectID) -> T? {
CoreStore.assert( CoreStore.assert(
self.isRunningInAllowedQueue(), self.isRunningInAllowedQueue(),
"Attempted to update an entity of type \(cs_typeName(T)) outside its designated queue." "Attempted to update an entity of type \(cs_typeName(into.entityClass)) outside its designated queue."
) )
CoreStore.assert( CoreStore.assert(
into.inferStoreIfPossible into.inferStoreIfPossible
|| (into.configuration ?? Into.defaultConfigurationName) == objectID.persistentStore?.configurationName, || (into.configuration ?? DataStack.defaultConfigurationName) == objectID.persistentStore?.configurationName,
"Attempted to update an entity of type \(cs_typeName(T)) but the specified persistent store do not match the `NSManagedObjectID`." "Attempted to update an entity of type \(cs_typeName(into.entityClass)) but the specified persistent store do not match the `NSManagedObjectID`."
) )
return self.fetchExisting(objectID) as? T return self.fetchExisting(objectID)
} }
/** /**
Deletes a specified `NSManagedObject`. Deletes a specified `NSManagedObject` or `CoreStoreObject`.
- parameter object: the `NSManagedObject` to be deleted - parameter object: the `NSManagedObject` or `CoreStoreObject` to be deleted
*/ */
public func delete(object: NSManagedObject?) { public func delete<D: DynamicObject>(_ object: D?) {
CoreStore.assert( CoreStore.assert(
self.isRunningInAllowedQueue(), self.isRunningInAllowedQueue(),
"Attempted to delete an entity outside its designated queue." "Attempted to delete an entity outside its designated queue."
) )
guard let object = object else { let context = self.context
object
return .flatMap(context.fetchExisting)
} .flatMap({ context.delete($0.cs_toRaw()) })
self.context.fetchExisting(object)?.deleteFromContext()
} }
/** /**
Deletes the specified `NSManagedObject`s. Deletes the specified `NSManagedObject`s or `CoreStoreObject`s.
- parameter object1: the `NSManagedObject` to be deleted - parameter object1: the `NSManagedObject` or `CoreStoreObject` to be deleted
- parameter object2: another `NSManagedObject` to be deleted - parameter object2: another `NSManagedObject` or `CoreStoreObject` to be deleted
- parameter objects: other `NSManagedObject`s to be deleted - parameter objects: other `NSManagedObject`s or `CoreStoreObject`s to be deleted
*/ */
public func delete(object1: NSManagedObject?, _ object2: NSManagedObject?, _ objects: NSManagedObject?...) { public func delete<D: DynamicObject>(_ object1: D?, _ object2: D?, _ objects: D?...) {
self.delete(([object1, object2] + objects).flatMap { $0 }) self.delete(([object1, object2] + objects).compactMap { $0 })
} }
/** /**
Deletes the specified `NSManagedObject`s. Deletes the specified `NSManagedObject`s or `CoreStoreObject`s.
- parameter objects: the `NSManagedObject`s to be deleted - parameter objects: the `NSManagedObject`s or `CoreStoreObject`s to be deleted
*/ */
public func delete<S: SequenceType where S.Generator.Element: NSManagedObject>(objects: S) { public func delete<S: Sequence>(_ objects: S) where S.Iterator.Element: DynamicObject {
CoreStore.assert( CoreStore.assert(
self.isRunningInAllowedQueue(), self.isRunningInAllowedQueue(),
"Attempted to delete entities outside their designated queue." "Attempted to delete entities outside their designated queue."
) )
let context = self.context let context = self.context
objects.forEach { context.fetchExisting($0)?.deleteFromContext() } objects.forEach { context.fetchExisting($0).flatMap({ context.delete($0.cs_toRaw()) }) }
} }
/** /**
@@ -209,7 +208,6 @@ public /*abstract*/ class BaseDataTransaction {
self.isRunningInAllowedQueue(), self.isRunningInAllowedQueue(),
"Attempted to refresh entities outside their designated queue." "Attempted to refresh entities outside their designated queue."
) )
self.context.refreshAndMergeAllObjects() self.context.refreshAndMergeAllObjects()
} }
@@ -217,44 +215,22 @@ public /*abstract*/ class BaseDataTransaction {
// MARK: Inspecting Pending Objects // MARK: Inspecting Pending Objects
/** /**
Returns all pending `NSManagedObject`s that were inserted to the transaction. This method should not be called after the `commit()` method was called. Returns all pending `DynamicObject`s of the specified type that were inserted to the transaction. This method should not be called after the `commit()` method was called.
- returns: a `Set` of pending `NSManagedObject`s that were inserted to the transaction.
*/
@warn_unused_result
public func insertedObjects() -> Set<NSManagedObject> {
CoreStore.assert(
self.transactionQueue.isCurrentExecutionContext(),
"Attempted to access inserted objects from a \(cs_typeName(self)) outside its designated queue."
)
CoreStore.assert(
!self.isCommitted,
"Attempted to access inserted objects from an already committed \(cs_typeName(self))."
)
return self.context.insertedObjects
}
/**
Returns all pending `NSManagedObject`s of the specified type that were inserted to the transaction. This method should not be called after the `commit()` method was called.
- parameter entity: the `NSManagedObject` subclass to filter - parameter entity: the `DynamicObject` subclass to filter
- returns: a `Set` of pending `NSManagedObject`s of the specified type that were inserted to the transaction. - returns: a `Set` of pending `DynamicObject`s of the specified type that were inserted to the transaction.
*/ */
@warn_unused_result public func insertedObjects<D: DynamicObject>(_ entity: D.Type) -> Set<D> {
public func insertedObjects<T: NSManagedObject>(entity: T.Type) -> Set<T> {
CoreStore.assert( CoreStore.assert(
self.transactionQueue.isCurrentExecutionContext(), self.isRunningInAllowedQueue(),
"Attempted to access inserted objects from a \(cs_typeName(self)) outside its designated queue." "Attempted to access inserted objects from a \(cs_typeName(self)) outside its designated queue."
) )
CoreStore.assert( CoreStore.assert(
!self.isCommitted, !self.isCommitted,
"Attempted to access inserted objects from an already committed \(cs_typeName(self))." "Attempted to access inserted objects from an already committed \(cs_typeName(self))."
) )
return Set(self.context.insertedObjects.compactMap({ entity.cs_matches(object: $0) ? entity.cs_fromRaw(object: $0) : nil }))
return Set(self.context.insertedObjects.flatMap { $0 as? T })
} }
/** /**
@@ -262,81 +238,55 @@ public /*abstract*/ class BaseDataTransaction {
- returns: a `Set` of pending `NSManagedObjectID`s that were inserted to the transaction. - returns: a `Set` of pending `NSManagedObjectID`s that were inserted to the transaction.
*/ */
@warn_unused_result
public func insertedObjectIDs() -> Set<NSManagedObjectID> { public func insertedObjectIDs() -> Set<NSManagedObjectID> {
CoreStore.assert( CoreStore.assert(
self.transactionQueue.isCurrentExecutionContext(), self.isRunningInAllowedQueue(),
"Attempted to access inserted object IDs from a \(cs_typeName(self)) outside its designated queue." "Attempted to access inserted object IDs from a \(cs_typeName(self)) outside its designated queue."
) )
CoreStore.assert( CoreStore.assert(
!self.isCommitted, !self.isCommitted,
"Attempted to access inserted objects IDs from an already committed \(cs_typeName(self))." "Attempted to access inserted objects IDs from an already committed \(cs_typeName(self))."
) )
return Set(self.context.insertedObjects.map { $0.objectID }) return Set(self.context.insertedObjects.map { $0.objectID })
} }
/** /**
Returns all pending `NSManagedObjectID`s of the specified type that were inserted to the transaction. This method should not be called after the `commit()` method was called. Returns all pending `NSManagedObjectID`s of the specified type that were inserted to the transaction. This method should not be called after the `commit()` method was called.
- parameter entity: the `NSManagedObject` subclass to filter - parameter entity: the `DynamicObject` subclass to filter
- returns: a `Set` of pending `NSManagedObjectID`s of the specified type that were inserted to the transaction. - returns: a `Set` of pending `NSManagedObjectID`s of the specified type that were inserted to the transaction.
*/ */
@warn_unused_result public func insertedObjectIDs<D: DynamicObject>(_ entity: D.Type) -> Set<NSManagedObjectID> {
public func insertedObjectIDs<T: NSManagedObject>(entity: T.Type) -> Set<NSManagedObjectID> {
CoreStore.assert( CoreStore.assert(
self.transactionQueue.isCurrentExecutionContext(), self.isRunningInAllowedQueue(),
"Attempted to access inserted object IDs from a \(cs_typeName(self)) outside its designated queue." "Attempted to access inserted object IDs from a \(cs_typeName(self)) outside its designated queue."
) )
CoreStore.assert( CoreStore.assert(
!self.isCommitted, !self.isCommitted,
"Attempted to access inserted objects IDs from an already committed \(cs_typeName(self))." "Attempted to access inserted objects IDs from an already committed \(cs_typeName(self))."
) )
return Set(self.context.insertedObjects.compactMap({ entity.cs_matches(object: $0) ? $0.objectID : nil }))
return Set(self.context.insertedObjects.filter { $0.isKindOfClass(entity) }.map { $0.objectID })
} }
/** /**
Returns all pending `NSManagedObject`s that were updated in the transaction. This method should not be called after the `commit()` method was called. Returns all pending `DynamicObject`s of the specified type that were updated in the transaction. This method should not be called after the `commit()` method was called.
- returns: a `Set` of pending `NSManagedObject`s that were updated to the transaction. - parameter entity: the `DynamicObject` subclass to filter
- returns: a `Set` of pending `DynamicObject`s of the specified type that were updated in the transaction.
*/ */
@warn_unused_result public func updatedObjects<D: DynamicObject>(_ entity: D.Type) -> Set<D> {
public func updatedObjects() -> Set<NSManagedObject> {
CoreStore.assert( CoreStore.assert(
self.transactionQueue.isCurrentExecutionContext(), self.isRunningInAllowedQueue(),
"Attempted to access updated objects from a \(cs_typeName(self)) outside its designated queue." "Attempted to access updated objects from a \(cs_typeName(self)) outside its designated queue."
) )
CoreStore.assert( CoreStore.assert(
!self.isCommitted, !self.isCommitted,
"Attempted to access updated objects from an already committed \(cs_typeName(self))." "Attempted to access updated objects from an already committed \(cs_typeName(self))."
) )
return Set(self.context.updatedObjects.compactMap({ entity.cs_matches(object: $0) ? entity.cs_fromRaw(object: $0) : nil }))
return self.context.updatedObjects
}
/**
Returns all pending `NSManagedObject`s of the specified type that were updated in the transaction. This method should not be called after the `commit()` method was called.
- parameter entity: the `NSManagedObject` subclass to filter
- returns: a `Set` of pending `NSManagedObject`s of the specified type that were updated in the transaction.
*/
@warn_unused_result
public func updatedObjects<T: NSManagedObject>(entity: T.Type) -> Set<T> {
CoreStore.assert(
self.transactionQueue.isCurrentExecutionContext(),
"Attempted to access updated objects from a \(cs_typeName(self)) outside its designated queue."
)
CoreStore.assert(
!self.isCommitted,
"Attempted to access updated objects from an already committed \(cs_typeName(self))."
)
return Set(self.context.updatedObjects.filter { $0.isKindOfClass(entity) }.map { $0 as! T })
} }
/** /**
@@ -344,144 +294,127 @@ public /*abstract*/ class BaseDataTransaction {
- returns: a `Set` of pending `NSManagedObjectID`s that were updated in the transaction. - returns: a `Set` of pending `NSManagedObjectID`s that were updated in the transaction.
*/ */
@warn_unused_result
public func updatedObjectIDs() -> Set<NSManagedObjectID> { public func updatedObjectIDs() -> Set<NSManagedObjectID> {
CoreStore.assert( CoreStore.assert(
self.transactionQueue.isCurrentExecutionContext(), self.isRunningInAllowedQueue(),
"Attempted to access updated object IDs from a \(cs_typeName(self)) outside its designated queue." "Attempted to access updated object IDs from a \(cs_typeName(self)) outside its designated queue."
) )
CoreStore.assert( CoreStore.assert(
!self.isCommitted, !self.isCommitted,
"Attempted to access updated object IDs from an already committed \(cs_typeName(self))." "Attempted to access updated object IDs from an already committed \(cs_typeName(self))."
) )
return Set(self.context.updatedObjects.map { $0.objectID }) return Set(self.context.updatedObjects.map { $0.objectID })
} }
/** /**
Returns all pending `NSManagedObjectID`s of the specified type that were updated in the transaction. This method should not be called after the `commit()` method was called. Returns all pending `NSManagedObjectID`s of the specified type that were updated in the transaction. This method should not be called after the `commit()` method was called.
- parameter entity: the `NSManagedObject` subclass to filter - parameter entity: the `DynamicObject` subclass to filter
- returns: a `Set` of pending `NSManagedObjectID`s of the specified type that were updated in the transaction. - returns: a `Set` of pending `NSManagedObjectID`s of the specified type that were updated in the transaction.
*/ */
@warn_unused_result public func updatedObjectIDs<D: DynamicObject>(_ entity: D.Type) -> Set<NSManagedObjectID> {
public func updatedObjectIDs<T: NSManagedObject>(entity: T.Type) -> Set<NSManagedObjectID> {
CoreStore.assert( CoreStore.assert(
self.transactionQueue.isCurrentExecutionContext(), self.isRunningInAllowedQueue(),
"Attempted to access updated object IDs from a \(cs_typeName(self)) outside its designated queue." "Attempted to access updated object IDs from a \(cs_typeName(self)) outside its designated queue."
) )
CoreStore.assert( CoreStore.assert(
!self.isCommitted, !self.isCommitted,
"Attempted to access updated object IDs from an already committed \(cs_typeName(self))." "Attempted to access updated object IDs from an already committed \(cs_typeName(self))."
) )
return Set(self.context.updatedObjects.compactMap({ entity.cs_matches(object: $0) ? $0.objectID : nil }))
return Set(self.context.updatedObjects.filter { $0.isKindOfClass(entity) }.map { $0.objectID })
} }
/** /**
Returns all pending `NSManagedObject`s that were deleted from the transaction. This method should not be called after the `commit()` method was called. Returns all pending `DynamicObject`s of the specified type that were deleted from the transaction. This method should not be called after the `commit()` method was called.
- returns: a `Set` of pending `NSManagedObject`s that were deleted from the transaction. - parameter entity: the `DynamicObject` subclass to filter
- returns: a `Set` of pending `DynamicObject`s of the specified type that were deleted from the transaction.
*/ */
@warn_unused_result public func deletedObjects<D: DynamicObject>(_ entity: D.Type) -> Set<D> {
public func deletedObjects() -> Set<NSManagedObject> {
CoreStore.assert( CoreStore.assert(
self.transactionQueue.isCurrentExecutionContext(), self.isRunningInAllowedQueue(),
"Attempted to access deleted objects from a \(cs_typeName(self)) outside its designated queue." "Attempted to access deleted objects from a \(cs_typeName(self)) outside its designated queue."
) )
CoreStore.assert( CoreStore.assert(
!self.isCommitted, !self.isCommitted,
"Attempted to access deleted objects from an already committed \(cs_typeName(self))." "Attempted to access deleted objects from an already committed \(cs_typeName(self))."
) )
return Set(self.context.deletedObjects.compactMap({ entity.cs_matches(object: $0) ? entity.cs_fromRaw(object: $0) : nil }))
return self.context.deletedObjects
}
/**
Returns all pending `NSManagedObject`s of the specified type that were deleted from the transaction. This method should not be called after the `commit()` method was called.
- parameter entity: the `NSManagedObject` subclass to filter
- returns: a `Set` of pending `NSManagedObject`s of the specified type that were deleted from the transaction.
*/
@warn_unused_result
public func deletedObjects<T: NSManagedObject>(entity: T.Type) -> Set<T> {
CoreStore.assert(
self.transactionQueue.isCurrentExecutionContext(),
"Attempted to access deleted objects from a \(cs_typeName(self)) outside its designated queue."
)
CoreStore.assert(
!self.isCommitted,
"Attempted to access deleted objects from an already committed \(cs_typeName(self))."
)
return Set(self.context.deletedObjects.filter { $0.isKindOfClass(entity) }.map { $0 as! T })
} }
/** /**
Returns all pending `NSManagedObjectID`s of the specified type that were deleted from the transaction. This method should not be called after the `commit()` method was called. Returns all pending `NSManagedObjectID`s of the specified type that were deleted from the transaction. This method should not be called after the `commit()` method was called.
- parameter entity: the `NSManagedObject` subclass to filter - parameter entity: the `DynamicObject` subclass to filter
- returns: a `Set` of pending `NSManagedObjectID`s of the specified type that were deleted from the transaction. - returns: a `Set` of pending `NSManagedObjectID`s of the specified type that were deleted from the transaction.
*/ */
@warn_unused_result
public func deletedObjectIDs() -> Set<NSManagedObjectID> { public func deletedObjectIDs() -> Set<NSManagedObjectID> {
CoreStore.assert( CoreStore.assert(
self.transactionQueue.isCurrentExecutionContext(), self.isRunningInAllowedQueue(),
"Attempted to access deleted object IDs from a \(cs_typeName(self)) outside its designated queue." "Attempted to access deleted object IDs from a \(cs_typeName(self)) outside its designated queue."
) )
CoreStore.assert( CoreStore.assert(
!self.isCommitted, !self.isCommitted,
"Attempted to access deleted object IDs from an already committed \(cs_typeName(self))." "Attempted to access deleted object IDs from an already committed \(cs_typeName(self))."
) )
return Set(self.context.deletedObjects.map { $0.objectID }) return Set(self.context.deletedObjects.map { $0.objectID })
} }
/** /**
Returns all pending `NSManagedObjectID`s of the specified type that were deleted from the transaction. This method should not be called after the `commit()` method was called. Returns all pending `NSManagedObjectID`s of the specified type that were deleted from the transaction. This method should not be called after the `commit()` method was called.
- parameter entity: the `NSManagedObject` subclass to filter - parameter entity: the `DynamicObject` subclass to filter
- returns: a `Set` of pending `NSManagedObjectID`s of the specified type that were deleted from the transaction. - returns: a `Set` of pending `NSManagedObjectID`s of the specified type that were deleted from the transaction.
*/ */
@warn_unused_result public func deletedObjectIDs<D: DynamicObject>(_ entity: D.Type) -> Set<NSManagedObjectID> {
public func deletedObjectIDs<T: NSManagedObject>(entity: T.Type) -> Set<NSManagedObjectID> {
CoreStore.assert( CoreStore.assert(
self.transactionQueue.isCurrentExecutionContext(), self.isRunningInAllowedQueue(),
"Attempted to access deleted object IDs from a \(cs_typeName(self)) outside its designated queue." "Attempted to access deleted object IDs from a \(cs_typeName(self)) outside its designated queue."
) )
CoreStore.assert( CoreStore.assert(
!self.isCommitted, !self.isCommitted,
"Attempted to access deleted object IDs from an already committed \(cs_typeName(self))." "Attempted to access deleted object IDs from an already committed \(cs_typeName(self))."
) )
return Set(self.context.deletedObjects.compactMap({ entity.cs_matches(object: $0) ? $0.objectID : nil }))
return Set(self.context.deletedObjects.filter { $0.isKindOfClass(entity) }.map { $0.objectID })
} }
// MARK: 3rd Party Utilities
/**
Allow external libraries to store custom data in the transaction. App code should rarely have a need for this.
```
enum Static {
static var myDataKey: Void?
}
transaction.userInfo[&Static.myDataKey] = myObject
```
- Important: Do not use this method to store thread-sensitive data.
*/
public let userInfo = UserInfo()
// MARK: Internal // MARK: Internal
internal let context: NSManagedObjectContext internal let context: NSManagedObjectContext
internal let transactionQueue: GCDQueue internal let transactionQueue: DispatchQueue
internal let childTransactionQueue: GCDQueue = .createSerial("com.corestore.datastack.childtransactionqueue") internal let childTransactionQueue = DispatchQueue.serial("com.corestore.datastack.childTransactionQueue")
internal let supportsUndo: Bool internal let supportsUndo: Bool
internal let bypassesQueueing: Bool internal let bypassesQueueing: Bool
internal var isCommitted = false internal var isCommitted = false
internal var result: SaveResult? internal var result: (hasChanges: Bool, error: CoreStoreError?)?
internal init(mainContext: NSManagedObjectContext, queue: GCDQueue, supportsUndo: Bool, bypassesQueueing: Bool) { internal init(mainContext: NSManagedObjectContext, queue: DispatchQueue, supportsUndo: Bool, bypassesQueueing: Bool) {
let context = mainContext.temporaryContextInTransactionWithConcurrencyType( let context = mainContext.temporaryContextInTransactionWithConcurrencyType(
queue == .Main queue == .main
? .MainQueueConcurrencyType ? .mainQueueConcurrencyType
: .PrivateQueueConcurrencyType : .privateQueueConcurrencyType
) )
self.transactionQueue = queue self.transactionQueue = queue
self.context = context self.context = context
@@ -489,18 +422,69 @@ public /*abstract*/ class BaseDataTransaction {
self.bypassesQueueing = bypassesQueueing self.bypassesQueueing = bypassesQueueing
context.parentTransaction = self context.parentTransaction = self
context.isTransactionContext = true
if !supportsUndo { if !supportsUndo {
context.undoManager = nil context.undoManager = nil
} }
else if context.undoManager == nil { else if context.undoManager == nil {
context.undoManager = NSUndoManager() context.undoManager = UndoManager()
} }
} }
internal func isRunningInAllowedQueue() -> Bool { internal func isRunningInAllowedQueue() -> Bool {
return self.bypassesQueueing || self.transactionQueue.isCurrentExecutionContext() return self.bypassesQueueing || self.transactionQueue.cs_isCurrentExecutionContext()
}
deinit {
self.context.reset()
}
// MARK: Deprecated
@available(*, deprecated, message: "Use insertedObjects(_:) and pass the specific entity type")
public func insertedObjects() -> Set<NSManagedObject> {
CoreStore.assert(
self.transactionQueue.cs_isCurrentExecutionContext(),
"Attempted to access inserted objects from a \(cs_typeName(self)) outside its designated queue."
)
CoreStore.assert(
!self.isCommitted,
"Attempted to access inserted objects from an already committed \(cs_typeName(self))."
)
return self.context.insertedObjects
}
@available(*, deprecated, message: "Use updatedObjects(_:) and pass the specific entity type")
public func updatedObjects() -> Set<NSManagedObject> {
CoreStore.assert(
self.transactionQueue.cs_isCurrentExecutionContext(),
"Attempted to access updated objects from a \(cs_typeName(self)) outside its designated queue."
)
CoreStore.assert(
!self.isCommitted,
"Attempted to access updated objects from an already committed \(cs_typeName(self))."
)
return self.context.updatedObjects
}
@available(*, deprecated, message: "Use deletedObjects(_:) and pass the specific entity type")
public func deletedObjects() -> Set<NSManagedObject> {
CoreStore.assert(
self.transactionQueue.cs_isCurrentExecutionContext(),
"Attempted to access deleted objects from a \(cs_typeName(self)) outside its designated queue."
)
CoreStore.assert(
!self.isCommitted,
"Attempted to access deleted objects from an already committed \(cs_typeName(self))."
)
return self.context.deletedObjects
} }
} }

View File

@@ -2,7 +2,7 @@
// CSAsynchronousDataTransaction.swift // CSAsynchronousDataTransaction.swift
// CoreStore // CoreStore
// //
// Copyright © 2016 John Rommel Estropia // Copyright © 2018 John Rommel Estropia
// //
// Permission is hereby granted, free of charge, to any person obtaining a copy // Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal // of this software and associated documentation files (the "Software"), to deal
@@ -35,36 +35,34 @@ import CoreData
- SeeAlso: `AsynchronousDataTransaction` - SeeAlso: `AsynchronousDataTransaction`
*/ */
@objc @objc
public final class CSAsynchronousDataTransaction: CSBaseDataTransaction { public final class CSAsynchronousDataTransaction: CSBaseDataTransaction, CoreStoreObjectiveCType {
/** /**
Saves the transaction changes. This method should not be used after the `-commitWithCompletion:` method was already called once. Saves the transaction changes. This method should not be used after the `-commitWithCompletion:` method was already called once.
- parameter completion: the block executed after the save completes. Success or failure is reported by the `CSSaveResult` argument of the block. - parameter success: the block executed if the save succeeds.
- parameter failure: the block executed if the save fails. A `CSError` is reported as the argument of the block.
*/ */
@objc @objc
public func commitWithCompletion(completion: ((result: CSSaveResult) -> Void)?) { public func commitWithSuccess(_ success: (() -> Void)?, failure: ((CSError) -> Void)?) {
self.bridgeToSwift.commit { (result) in CoreStore.assert(
self.bridgeToSwift.transactionQueue.cs_isCurrentExecutionContext(),
"Attempted to commit a \(cs_typeName(self)) outside its designated queue."
)
CoreStore.assert(
!self.bridgeToSwift.isCommitted,
"Attempted to commit a \(cs_typeName(self)) more than once."
)
self.bridgeToSwift.autoCommit { (_, error) in
completion?(result: result.bridgeToObjectiveC) if let error = error {
}
}
/**
Begins a child transaction synchronously where `NSManagedObject` creates, updates, and deletes can be made. This method should not be used after the `-commitWithCompletion:` method was already called once.
- parameter closure: the block where creates, updates, and deletes can be made to the transaction. Transaction blocks are executed serially in a background queue, and all changes are made from a concurrent `NSManagedObjectContext`.
- returns: a `CSSaveResult` value indicating success or failure, or `nil` if the transaction was not comitted synchronously
*/
@objc
public func beginSynchronous(closure: (transaction: CSSynchronousDataTransaction) -> Void) -> CSSaveResult? {
return bridge {
self.bridgeToSwift.beginSynchronous { (transaction) in
closure(transaction: transaction.bridgeToObjectiveC) failure?(error.bridgeToObjectiveC)
}
else {
success?()
} }
} }
} }
@@ -74,7 +72,7 @@ public final class CSAsynchronousDataTransaction: CSBaseDataTransaction {
public override var description: String { public override var description: String {
return "(\(String(reflecting: self.dynamicType))) \(self.bridgeToSwift.coreStoreDumpString)" return "(\(String(reflecting: type(of: self)))) \(self.bridgeToSwift.coreStoreDumpString)"
} }
@@ -87,7 +85,7 @@ public final class CSAsynchronousDataTransaction: CSBaseDataTransaction {
- returns: a new `NSManagedObject` instance of the specified entity type. - returns: a new `NSManagedObject` instance of the specified entity type.
*/ */
@objc @objc
public override func createInto(into: CSInto) -> AnyObject { public override func createInto(_ into: CSInto) -> Any {
return self.bridgeToSwift.create(into.bridgeToSwift) return self.bridgeToSwift.create(into.bridgeToSwift)
} }
@@ -99,8 +97,7 @@ public final class CSAsynchronousDataTransaction: CSBaseDataTransaction {
- returns: an editable proxy for the specified `NSManagedObject`. - returns: an editable proxy for the specified `NSManagedObject`.
*/ */
@objc @objc
@warn_unused_result public override func editObject(_ object: NSManagedObject?) -> Any? {
public override func editObject(object: NSManagedObject?) -> AnyObject? {
return self.bridgeToSwift.edit(object) return self.bridgeToSwift.edit(object)
} }
@@ -113,8 +110,7 @@ public final class CSAsynchronousDataTransaction: CSBaseDataTransaction {
- returns: an editable proxy for the specified `NSManagedObject`. - returns: an editable proxy for the specified `NSManagedObject`.
*/ */
@objc @objc
@warn_unused_result public override func editInto(_ into: CSInto, objectID: NSManagedObjectID) -> Any? {
public override func editInto(into: CSInto, objectID: NSManagedObjectID) -> AnyObject? {
return self.bridgeToSwift.edit(into.bridgeToSwift, objectID) return self.bridgeToSwift.edit(into.bridgeToSwift, objectID)
} }
@@ -125,7 +121,7 @@ public final class CSAsynchronousDataTransaction: CSBaseDataTransaction {
- parameter object: the `NSManagedObject` type to be deleted - parameter object: the `NSManagedObject` type to be deleted
*/ */
@objc @objc
public override func deleteObject(object: NSManagedObject?) { public override func deleteObject(_ object: NSManagedObject?) {
self.bridgeToSwift.delete(object) self.bridgeToSwift.delete(object)
} }
@@ -136,7 +132,7 @@ public final class CSAsynchronousDataTransaction: CSBaseDataTransaction {
- parameter objects: the `NSManagedObject`s type to be deleted - parameter objects: the `NSManagedObject`s type to be deleted
*/ */
@objc @objc
public override func deleteObjects(objects: [NSManagedObject]) { public override func deleteObjects(_ objects: [NSManagedObject]) {
self.bridgeToSwift.delete(objects) self.bridgeToSwift.delete(objects)
} }
@@ -144,30 +140,68 @@ public final class CSAsynchronousDataTransaction: CSBaseDataTransaction {
// MARK: CoreStoreObjectiveCType // MARK: CoreStoreObjectiveCType
internal typealias SwiftType = AsynchronousDataTransaction public typealias SwiftType = AsynchronousDataTransaction
public override var bridgeToSwift: AsynchronousDataTransaction { public var bridgeToSwift: AsynchronousDataTransaction {
return super.bridgeToSwift as! AsynchronousDataTransaction return super.swiftTransaction as! AsynchronousDataTransaction
} }
public required init(_ swiftValue: AsynchronousDataTransaction) { public required init(_ swiftValue: AsynchronousDataTransaction) {
super.init(swiftValue as BaseDataTransaction)
}
public required override init(_ swiftValue: BaseDataTransaction) {
super.init(swiftValue) super.init(swiftValue)
} }
public required init(_ swiftValue: BaseDataTransaction) {
// MARK: Deprecated
@available(*, deprecated, message: "Use the new -[CSAsynchronousDataTransaction commitWithSuccess:failure:] method.")
@objc
public func commitWithCompletion(_ completion: ((_ result: CSSaveResult) -> Void)?) {
fatalError("init(_:) requires an AsynchronousDataTransaction instance") CoreStore.assert(
self.bridgeToSwift.transactionQueue.cs_isCurrentExecutionContext(),
"Attempted to commit a \(cs_typeName(self)) outside its designated queue."
)
CoreStore.assert(
!self.bridgeToSwift.isCommitted,
"Attempted to commit a \(cs_typeName(self)) more than once."
)
self.bridgeToSwift.commit { (result) in
completion?(result.bridgeToObjectiveC)
}
}
@available(*, deprecated, message: "Secondary tasks spawned from CSAsynchronousDataTransactions and CSSynchronousDataTransactions are no longer supported. ")
@objc
@discardableResult
public func beginSynchronous(_ closure: @escaping (_ transaction: CSSynchronousDataTransaction) -> Void) -> CSSaveResult? {
return bridge {
self.bridgeToSwift.beginSynchronous { (transaction) in
closure(transaction.bridgeToObjectiveC)
}
}
} }
} }
// MARK: - AsynchronousDataTransaction // MARK: - AsynchronousDataTransaction
extension AsynchronousDataTransaction { extension AsynchronousDataTransaction: CoreStoreSwiftType {
// MARK: CoreStoreSwiftType // MARK: CoreStoreSwiftType
internal typealias ObjectiveCType = CSAsynchronousDataTransaction public var bridgeToObjectiveC: CSAsynchronousDataTransaction {
return CSAsynchronousDataTransaction(self)
}
} }

View File

@@ -2,7 +2,7 @@
// CSBaseDataTransaction+Querying.swift // CSBaseDataTransaction+Querying.swift
// CoreStore // CoreStore
// //
// Copyright © 2016 John Rommel Estropia // Copyright © 2018 John Rommel Estropia
// //
// Permission is hereby granted, free of charge, to any person obtaining a copy // Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal // of this software and associated documentation files (the "Software"), to deal
@@ -38,17 +38,9 @@ public extension CSBaseDataTransaction {
- returns: the `NSManagedObject` instance if the object exists in the transaction, or `nil` if not found. - returns: the `NSManagedObject` instance if the object exists in the transaction, or `nil` if not found.
*/ */
@objc @objc
@warn_unused_result public func fetchExistingObject(_ object: NSManagedObject) -> Any? {
public func fetchExistingObject(object: NSManagedObject) -> AnyObject? {
do { return self.swiftTransaction.context.fetchExisting(object) as NSManagedObject?
return try self.bridgeToSwift.context.existingObjectWithID(object.objectID)
}
catch _ {
return nil
}
} }
/** /**
@@ -58,17 +50,9 @@ public extension CSBaseDataTransaction {
- returns: the `NSManagedObject` instance if the object exists in the transaction, or `nil` if not found. - returns: the `NSManagedObject` instance if the object exists in the transaction, or `nil` if not found.
*/ */
@objc @objc
@warn_unused_result public func fetchExistingObjectWithID(_ objectID: NSManagedObjectID) -> Any? {
public func fetchExistingObjectWithID(objectID: NSManagedObjectID) -> AnyObject? {
do { return self.swiftTransaction.context.fetchExisting(objectID) as NSManagedObject?
return try self.bridgeToSwift.context.existingObjectWithID(objectID)
}
catch _ {
return nil
}
} }
/** /**
@@ -78,10 +62,9 @@ public extension CSBaseDataTransaction {
- returns: the `NSManagedObject` array for objects that exists in the transaction - returns: the `NSManagedObject` array for objects that exists in the transaction
*/ */
@objc @objc
@warn_unused_result public func fetchExistingObjects(_ objects: [NSManagedObject]) -> [Any] {
public func fetchExistingObjects(objects: [NSManagedObject]) -> [AnyObject] {
return objects.flatMap { try? self.bridgeToSwift.context.existingObjectWithID($0.objectID) } return self.swiftTransaction.context.fetchExisting(objects) as [NSManagedObject]
} }
/** /**
@@ -91,10 +74,9 @@ public extension CSBaseDataTransaction {
- returns: the `NSManagedObject` array for objects that exists in the transaction - returns: the `NSManagedObject` array for objects that exists in the transaction
*/ */
@objc @objc
@warn_unused_result public func fetchExistingObjectsWithIDs(_ objectIDs: [NSManagedObjectID]) -> [Any] {
public func fetchExistingObjectsWithIDs(objectIDs: [NSManagedObjectID]) -> [AnyObject] {
return objectIDs.flatMap { try? self.bridgeToSwift.context.existingObjectWithID($0) } return self.swiftTransaction.context.fetchExisting(objectIDs) as [NSManagedObject]
} }
/** /**
@@ -105,14 +87,14 @@ public extension CSBaseDataTransaction {
- returns: the first `NSManagedObject` instance that satisfies the specified `CSFetchClause`s - returns: the first `NSManagedObject` instance that satisfies the specified `CSFetchClause`s
*/ */
@objc @objc
@warn_unused_result public func fetchOneFrom(_ from: CSFrom, fetchClauses: [CSFetchClause]) -> Any? {
public func fetchOneFrom(from: CSFrom, fetchClauses: [CSFetchClause]) -> AnyObject? {
CoreStore.assert( CoreStore.assert(
self.bridgeToSwift.isRunningInAllowedQueue(), self.swiftTransaction.isRunningInAllowedQueue(),
"Attempted to fetch from a \(cs_typeName(self)) outside its designated queue." "Attempted to fetch from a \(cs_typeName(self)) outside its designated queue."
) )
return self.bridgeToSwift.context.fetchOne(from, fetchClauses) return (try? self.swiftTransaction.context.fetchOne(from, fetchClauses))?
.flatMap({ $0 })
} }
/** /**
@@ -123,14 +105,14 @@ public extension CSBaseDataTransaction {
- returns: all `NSManagedObject` instances that satisfy the specified `CSFetchClause`s - returns: all `NSManagedObject` instances that satisfy the specified `CSFetchClause`s
*/ */
@objc @objc
@warn_unused_result public func fetchAllFrom(_ from: CSFrom, fetchClauses: [CSFetchClause]) -> [Any]? {
public func fetchAllFrom(from: CSFrom, fetchClauses: [CSFetchClause]) -> [AnyObject]? {
CoreStore.assert( CoreStore.assert(
self.bridgeToSwift.isRunningInAllowedQueue(), self.swiftTransaction.isRunningInAllowedQueue(),
"Attempted to fetch from a \(cs_typeName(self)) outside its designated queue." "Attempted to fetch from a \(cs_typeName(self)) outside its designated queue."
) )
return self.bridgeToSwift.context.fetchAll(from, fetchClauses) return (try? self.swiftTransaction.context.fetchAll(from, fetchClauses))
.flatMap({ $0 })
} }
/** /**
@@ -141,14 +123,14 @@ public extension CSBaseDataTransaction {
- returns: the number `NSManagedObject`s that satisfy the specified `CSFetchClause`s - returns: the number `NSManagedObject`s that satisfy the specified `CSFetchClause`s
*/ */
@objc @objc
@warn_unused_result public func fetchCountFrom(_ from: CSFrom, fetchClauses: [CSFetchClause]) -> NSNumber? {
public func fetchCountFrom(from: CSFrom, fetchClauses: [CSFetchClause]) -> NSNumber? {
CoreStore.assert( CoreStore.assert(
self.bridgeToSwift.isRunningInAllowedQueue(), self.swiftTransaction.isRunningInAllowedQueue(),
"Attempted to fetch from a \(cs_typeName(self)) outside its designated queue." "Attempted to fetch from a \(cs_typeName(self)) outside its designated queue."
) )
return self.bridgeToSwift.context.fetchCount(from, fetchClauses) return (try? self.swiftTransaction.context.fetchCount(from, fetchClauses))
.flatMap({ NSNumber(value: $0) })
} }
/** /**
@@ -159,14 +141,14 @@ public extension CSBaseDataTransaction {
- returns: the `NSManagedObjectID` for the first `NSManagedObject` that satisfies the specified `CSFetchClause`s - returns: the `NSManagedObjectID` for the first `NSManagedObject` that satisfies the specified `CSFetchClause`s
*/ */
@objc @objc
@warn_unused_result public func fetchObjectIDFrom(_ from: CSFrom, fetchClauses: [CSFetchClause]) -> NSManagedObjectID? {
public func fetchObjectIDFrom(from: CSFrom, fetchClauses: [CSFetchClause]) -> NSManagedObjectID? {
CoreStore.assert( CoreStore.assert(
self.bridgeToSwift.isRunningInAllowedQueue(), self.swiftTransaction.isRunningInAllowedQueue(),
"Attempted to fetch from a \(cs_typeName(self)) outside its designated queue." "Attempted to fetch from a \(cs_typeName(self)) outside its designated queue."
) )
return self.bridgeToSwift.context.fetchObjectID(from, fetchClauses) return (try? self.swiftTransaction.context.fetchObjectID(from, fetchClauses))
.flatMap({ $0 })
} }
/** /**
@@ -180,14 +162,14 @@ public extension CSBaseDataTransaction {
- returns: the result of the the query. The type of the return value is specified by the generic type of the `CSSelect` parameter. - returns: the result of the the query. The type of the return value is specified by the generic type of the `CSSelect` parameter.
*/ */
@objc @objc
@warn_unused_result public func queryValueFrom(_ from: CSFrom, selectClause: CSSelect, queryClauses: [CSQueryClause]) -> Any? {
public func queryValueFrom(from: CSFrom, selectClause: CSSelect, queryClauses: [CSQueryClause]) -> AnyObject? {
CoreStore.assert( CoreStore.assert(
self.bridgeToSwift.isRunningInAllowedQueue(), self.swiftTransaction.isRunningInAllowedQueue(),
"Attempted to query from a \(cs_typeName(self)) outside its designated queue." "Attempted to query from a \(cs_typeName(self)) outside its designated queue."
) )
return self.bridgeToSwift.context.queryValue(from, selectClause, queryClauses) return (try? self.swiftTransaction.context.queryValue(from, selectClause, queryClauses))
.flatMap({ $0 })
} }
/** /**
@@ -201,13 +183,13 @@ public extension CSBaseDataTransaction {
- returns: the result of the the query. The type of the return value is specified by the generic type of the `CSSelect` parameter. - returns: the result of the the query. The type of the return value is specified by the generic type of the `CSSelect` parameter.
*/ */
@objc @objc
@warn_unused_result public func queryAttributesFrom(_ from: CSFrom, selectClause: CSSelect, queryClauses: [CSQueryClause]) -> [[String: Any]]? {
public func queryAttributesFrom(from: CSFrom, selectClause: CSSelect, queryClauses: [CSQueryClause]) -> [[NSString: AnyObject]]? {
CoreStore.assert( CoreStore.assert(
self.bridgeToSwift.isRunningInAllowedQueue(), self.swiftTransaction.isRunningInAllowedQueue(),
"Attempted to query from a \(cs_typeName(self)) outside its designated queue." "Attempted to query from a \(cs_typeName(self)) outside its designated queue."
) )
return self.bridgeToSwift.context.queryAttributes(from, selectClause, queryClauses) return (try? self.swiftTransaction.context.queryAttributes(from, selectClause, queryClauses))
.flatMap({ $0 })
} }
} }

View File

@@ -2,7 +2,7 @@
// CSBaseDataTransaction.swift // CSBaseDataTransaction.swift
// CoreStore // CoreStore
// //
// Copyright © 2016 John Rommel Estropia // Copyright © 2018 John Rommel Estropia
// //
// Permission is hereby granted, free of charge, to any person obtaining a copy // Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal // of this software and associated documentation files (the "Software"), to deal
@@ -35,7 +35,7 @@ import CoreData
- SeeAlso: `BaseDataTransaction` - SeeAlso: `BaseDataTransaction`
*/ */
@objc @objc
public class CSBaseDataTransaction: NSObject, CoreStoreObjectiveCType { public class CSBaseDataTransaction: NSObject {
// MARK: Object management // MARK: Object management
@@ -45,7 +45,7 @@ public class CSBaseDataTransaction: NSObject, CoreStoreObjectiveCType {
@objc @objc
public var hasChanges: Bool { public var hasChanges: Bool {
return self.bridgeToSwift.hasChanges return self.swiftTransaction.hasChanges
} }
/** /**
@@ -55,9 +55,9 @@ public class CSBaseDataTransaction: NSObject, CoreStoreObjectiveCType {
- returns: a new `NSManagedObject` instance of the specified entity type. - returns: a new `NSManagedObject` instance of the specified entity type.
*/ */
@objc @objc
public func createInto(into: CSInto) -> AnyObject { public func createInto(_ into: CSInto) -> Any {
return self.bridgeToSwift.create(into.bridgeToSwift) return self.swiftTransaction.create(into.bridgeToSwift)
} }
/** /**
@@ -67,10 +67,9 @@ public class CSBaseDataTransaction: NSObject, CoreStoreObjectiveCType {
- returns: an editable proxy for the specified `NSManagedObject`. - returns: an editable proxy for the specified `NSManagedObject`.
*/ */
@objc @objc
@warn_unused_result public func editObject(_ object: NSManagedObject?) -> Any? {
public func editObject(object: NSManagedObject?) -> AnyObject? {
return self.bridgeToSwift.edit(object) return self.swiftTransaction.edit(object)
} }
/** /**
@@ -81,10 +80,9 @@ public class CSBaseDataTransaction: NSObject, CoreStoreObjectiveCType {
- returns: an editable proxy for the specified `NSManagedObject`. - returns: an editable proxy for the specified `NSManagedObject`.
*/ */
@objc @objc
@warn_unused_result public func editInto(_ into: CSInto, objectID: NSManagedObjectID) -> Any? {
public func editInto(into: CSInto, objectID: NSManagedObjectID) -> AnyObject? {
return self.bridgeToSwift.edit(into.bridgeToSwift, objectID) return self.swiftTransaction.edit(into.bridgeToSwift, objectID)
} }
/** /**
@@ -93,9 +91,9 @@ public class CSBaseDataTransaction: NSObject, CoreStoreObjectiveCType {
- parameter object: the `NSManagedObject` to be deleted - parameter object: the `NSManagedObject` to be deleted
*/ */
@objc @objc
public func deleteObject(object: NSManagedObject?) { public func deleteObject(_ object: NSManagedObject?) {
self.bridgeToSwift.delete(object) self.swiftTransaction.delete(object)
} }
/** /**
@@ -104,9 +102,9 @@ public class CSBaseDataTransaction: NSObject, CoreStoreObjectiveCType {
- parameter objects: the `NSManagedObject`s to be deleted - parameter objects: the `NSManagedObject`s to be deleted
*/ */
@objc @objc
public func deleteObjects(objects: [NSManagedObject]) { public func deleteObjects(_ objects: [NSManagedObject]) {
self.bridgeToSwift.delete(objects) self.swiftTransaction.delete(objects)
} }
/** /**
@@ -115,24 +113,12 @@ public class CSBaseDataTransaction: NSObject, CoreStoreObjectiveCType {
@objc @objc
public func refreshAndMergeAllObjects() { public func refreshAndMergeAllObjects() {
self.bridgeToSwift.refreshAndMergeAllObjects() self.swiftTransaction.refreshAndMergeAllObjects()
} }
// MARK: Inspecting Pending Objects // MARK: Inspecting Pending Objects
/**
Returns all pending `NSManagedObject`s that were inserted to the transaction. This method should not be called after the `-commit*:` method was called.
- returns: an `NSSet` of pending `NSManagedObject`s that were inserted to the transaction.
*/
@objc
@warn_unused_result
public func insertedObjects() -> Set<NSManagedObject> {
return self.bridgeToSwift.insertedObjects()
}
/** /**
Returns all pending `NSManagedObject`s of the specified type that were inserted to the transaction. This method should not be called after the `-commit*:` method was called. Returns all pending `NSManagedObject`s of the specified type that were inserted to the transaction. This method should not be called after the `-commit*:` method was called.
@@ -140,10 +126,9 @@ public class CSBaseDataTransaction: NSObject, CoreStoreObjectiveCType {
- returns: an `NSSet` of pending `NSManagedObject`s of the specified type that were inserted to the transaction. - returns: an `NSSet` of pending `NSManagedObject`s of the specified type that were inserted to the transaction.
*/ */
@objc @objc
@warn_unused_result public func insertedObjectsOfType(_ entity: NSManagedObject.Type) -> Set<NSManagedObject> {
public func insertedObjectsOfType(entity: NSManagedObject.Type) -> Set<NSManagedObject> {
return self.bridgeToSwift.insertedObjects(entity) return self.swiftTransaction.insertedObjects(entity)
} }
/** /**
@@ -152,10 +137,9 @@ public class CSBaseDataTransaction: NSObject, CoreStoreObjectiveCType {
- returns: an `NSSet` of pending `NSManagedObjectID`s that were inserted to the transaction. - returns: an `NSSet` of pending `NSManagedObjectID`s that were inserted to the transaction.
*/ */
@objc @objc
@warn_unused_result
public func insertedObjectIDs() -> Set<NSManagedObjectID> { public func insertedObjectIDs() -> Set<NSManagedObjectID> {
return self.bridgeToSwift.insertedObjectIDs() return self.swiftTransaction.insertedObjectIDs()
} }
/** /**
@@ -165,22 +149,9 @@ public class CSBaseDataTransaction: NSObject, CoreStoreObjectiveCType {
- returns: an `NSSet` of pending `NSManagedObjectID`s of the specified type that were inserted to the transaction. - returns: an `NSSet` of pending `NSManagedObjectID`s of the specified type that were inserted to the transaction.
*/ */
@objc @objc
@warn_unused_result public func insertedObjectIDsOfType(_ entity: NSManagedObject.Type) -> Set<NSManagedObjectID> {
public func insertedObjectIDsOfType(entity: NSManagedObject.Type) -> Set<NSManagedObjectID> {
return self.bridgeToSwift.insertedObjectIDs(entity) return self.swiftTransaction.insertedObjectIDs(entity)
}
/**
Returns all pending `NSManagedObject`s that were updated in the transaction. This method should not be called after the `-commit*:` method was called.
- returns: an `NSSet` of pending `NSManagedObject`s that were updated to the transaction.
*/
@objc
@warn_unused_result
public func updatedObjects() -> Set<NSManagedObject> {
return self.bridgeToSwift.updatedObjects()
} }
/** /**
@@ -190,10 +161,9 @@ public class CSBaseDataTransaction: NSObject, CoreStoreObjectiveCType {
- returns: an `NSSet` of pending `NSManagedObject`s of the specified type that were updated in the transaction. - returns: an `NSSet` of pending `NSManagedObject`s of the specified type that were updated in the transaction.
*/ */
@objc @objc
@warn_unused_result public func updatedObjectsOfType(_ entity: NSManagedObject.Type) -> Set<NSManagedObject> {
public func updatedObjectsOfType(entity: NSManagedObject.Type) -> Set<NSManagedObject> {
return self.bridgeToSwift.updatedObjects(entity) return self.swiftTransaction.updatedObjects(entity)
} }
/** /**
@@ -202,10 +172,9 @@ public class CSBaseDataTransaction: NSObject, CoreStoreObjectiveCType {
- returns: an `NSSet` of pending `NSManagedObjectID`s that were updated in the transaction. - returns: an `NSSet` of pending `NSManagedObjectID`s that were updated in the transaction.
*/ */
@objc @objc
@warn_unused_result
public func updatedObjectIDs() -> Set<NSManagedObjectID> { public func updatedObjectIDs() -> Set<NSManagedObjectID> {
return self.bridgeToSwift.updatedObjectIDs() return self.swiftTransaction.updatedObjectIDs()
} }
/** /**
@@ -215,22 +184,9 @@ public class CSBaseDataTransaction: NSObject, CoreStoreObjectiveCType {
- returns: an `NSSet` of pending `NSManagedObjectID`s of the specified type that were updated in the transaction. - returns: an `NSSet` of pending `NSManagedObjectID`s of the specified type that were updated in the transaction.
*/ */
@objc @objc
@warn_unused_result public func updatedObjectIDsOfType(_ entity: NSManagedObject.Type) -> Set<NSManagedObjectID> {
public func updatedObjectIDsOfType(entity: NSManagedObject.Type) -> Set<NSManagedObjectID> {
return self.bridgeToSwift.updatedObjectIDs(entity) return self.swiftTransaction.updatedObjectIDs(entity)
}
/**
Returns all pending `NSManagedObject`s that were deleted from the transaction. This method should not be called after the `-commit*:` method was called.
- returns: an `NSSet` of pending `NSManagedObject`s that were deleted from the transaction.
*/
@objc
@warn_unused_result
public func deletedObjects() -> Set<NSManagedObject> {
return self.bridgeToSwift.deletedObjects()
} }
/** /**
@@ -240,23 +196,20 @@ public class CSBaseDataTransaction: NSObject, CoreStoreObjectiveCType {
- returns: an `NSSet` of pending `NSManagedObject`s of the specified type that were deleted from the transaction. - returns: an `NSSet` of pending `NSManagedObject`s of the specified type that were deleted from the transaction.
*/ */
@objc @objc
@warn_unused_result public func deletedObjectsOfType(_ entity: NSManagedObject.Type) -> Set<NSManagedObject> {
public func deletedObjectsOfType(entity: NSManagedObject.Type) -> Set<NSManagedObject> {
return self.bridgeToSwift.deletedObjects(entity) return self.swiftTransaction.deletedObjects(entity)
} }
/** /**
Returns all pending `NSManagedObjectID`s of the specified type that were deleted from the transaction. This method should not be called after the `-commit*:` method was called. Returns all pending `NSManagedObjectID`s of the specified type that were deleted from the transaction. This method should not be called after the `-commit*:` method was called.
- parameter entity: the `NSManagedObject` subclass to filter
- returns: an `NSSet` of pending `NSManagedObjectID`s of the specified type that were deleted from the transaction. - returns: an `NSSet` of pending `NSManagedObjectID`s of the specified type that were deleted from the transaction.
*/ */
@objc @objc
@warn_unused_result
public func deletedObjectIDs() -> Set<NSManagedObjectID> { public func deletedObjectIDs() -> Set<NSManagedObjectID> {
return self.bridgeToSwift.deletedObjectIDs() return self.swiftTransaction.deletedObjectIDs()
} }
/** /**
@@ -266,10 +219,9 @@ public class CSBaseDataTransaction: NSObject, CoreStoreObjectiveCType {
- returns: a `Set` of pending `NSManagedObjectID`s of the specified type that were deleted from the transaction. - returns: a `Set` of pending `NSManagedObjectID`s of the specified type that were deleted from the transaction.
*/ */
@objc @objc
@warn_unused_result public func deletedObjectIDsOfType(_ entity: NSManagedObject.Type) -> Set<NSManagedObjectID> {
public func deletedObjectIDsOfType(entity: NSManagedObject.Type) -> Set<NSManagedObjectID> {
return self.bridgeToSwift.deletedObjectIDs(entity) return self.swiftTransaction.deletedObjectIDs(entity)
} }
@@ -277,46 +229,50 @@ public class CSBaseDataTransaction: NSObject, CoreStoreObjectiveCType {
public override var hash: Int { public override var hash: Int {
return ObjectIdentifier(self.bridgeToSwift).hashValue return ObjectIdentifier(self.swiftTransaction).hashValue
} }
public override func isEqual(object: AnyObject?) -> Bool { public override func isEqual(_ object: Any?) -> Bool {
guard let object = object as? CSBaseDataTransaction else { guard let object = object as? CSBaseDataTransaction else {
return false return false
} }
return self.bridgeToSwift === object.bridgeToSwift return self.swiftTransaction === object.swiftTransaction
} }
// MARK: CoreStoreObjectiveCType // MARK: Internal
public typealias SwiftType = BaseDataTransaction internal let swiftTransaction: BaseDataTransaction
public required init(_ swiftValue: BaseDataTransaction) { internal init(_ swiftValue: BaseDataTransaction) {
self.swiftTransaction = swiftValue self.swiftTransaction = swiftValue
super.init() super.init()
} }
public var bridgeToSwift: BaseDataTransaction {
// MARK: Deprecated
@available(*, deprecated, message: "Use -[insertedObjectsOfType:] and pass the specific entity class")
@objc
public func insertedObjects() -> Set<NSManagedObject> {
return self.swiftTransaction return self.swiftTransaction.insertedObjects()
} }
@available(*, deprecated, message: "Use -[updatedObjectsOfType:] and pass the specific entity class")
@objc
public func updatedObjects() -> Set<NSManagedObject> {
return self.swiftTransaction.updatedObjects()
}
// MARK: Private @available(*, deprecated, message: "Use -[deletedObjectsOfType:] and pass the specific entity class")
@objc
private let swiftTransaction: BaseDataTransaction public func deletedObjects() -> Set<NSManagedObject> {
}
return self.swiftTransaction.deletedObjects()
}
// MARK: - BaseDataTransaction
extension BaseDataTransaction: CoreStoreSwiftType {
// MARK: CoreStoreSwiftType
public typealias ObjectiveCType = CSBaseDataTransaction
} }

View File

@@ -2,7 +2,7 @@
// CSClauseTypes.swift // CSClauseTypes.swift
// CoreStore // CoreStore
// //
// Copyright © 2016 John Rommel Estropia // Copyright © 2018 John Rommel Estropia
// //
// Permission is hereby granted, free of charge, to any person obtaining a copy // Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal // of this software and associated documentation files (the "Software"), to deal
@@ -38,7 +38,7 @@ import CoreData
public protocol CSFetchClause { public protocol CSFetchClause {
@objc @objc
func applyToFetchRequest(fetchRequest: NSFetchRequest) func applyToFetchRequest(_ fetchRequest: NSFetchRequest<NSFetchRequestResult>)
} }
@@ -53,7 +53,7 @@ public protocol CSFetchClause {
public protocol CSQueryClause { public protocol CSQueryClause {
@objc @objc
func applyToFetchRequest(fetchRequest: NSFetchRequest) func applyToFetchRequest(_ fetchRequest: NSFetchRequest<NSFetchRequestResult>)
} }
@@ -68,5 +68,5 @@ public protocol CSQueryClause {
public protocol CSDeleteClause { public protocol CSDeleteClause {
@objc @objc
func applyToFetchRequest(fetchRequest: NSFetchRequest) func applyToFetchRequest(_ fetchRequest: NSFetchRequest<NSFetchRequestResult>)
} }

View File

@@ -2,7 +2,7 @@
// CSCoreStore+Migrating.swift // CSCoreStore+Migrating.swift
// CoreStore // CoreStore
// //
// Copyright © 2016 John Rommel Estropia // Copyright © 2018 John Rommel Estropia
// //
// Permission is hereby granted, free of charge, to any person obtaining a copy // Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal // of this software and associated documentation files (the "Software"), to deal
@@ -44,11 +44,10 @@ public extension CSCoreStore {
} }
error: &error]; error: &error];
``` ```
- parameter storage: the `CSInMemoryStore` instance - parameter storage: the `CSInMemoryStore` instance
- parameter completion: the closure to be executed on the main queue when the process completes, either due to success or failure. The closure's `CSSetupResult` argument indicates the result. This closure is NOT executed if an error is thrown, but will be executed with a failure `CSSetupResult` result if an error occurs asynchronously. - parameter completion: the closure to be executed on the main queue when the process completes, either due to success or failure. The closure's `CSSetupResult` argument indicates the result. This closure is NOT executed if an error is thrown, but will be executed with a failure `CSSetupResult` result if an error occurs asynchronously.
*/ */
public static func addInMemoryStorage(storage: CSInMemoryStore, completion: (CSSetupResult) -> Void) { public static func addInMemoryStorage(_ storage: CSInMemoryStore, completion: @escaping (CSSetupResult) -> Void) {
self.defaultStack.addInMemoryStorage(storage, completion: completion) self.defaultStack.addInMemoryStorage(storage, completion: completion)
} }
@@ -68,13 +67,12 @@ public extension CSCoreStore {
} }
error: &error]; error: &error];
``` ```
- parameter storage: the `CSSQLiteStore` instance - parameter storage: the `CSSQLiteStore` instance
- parameter completion: the closure to be executed on the main queue when the process completes, either due to success or failure. The closure's `CSSetupResult` argument indicates the result. This closure is NOT executed if an error is thrown, but will be executed with a failure `CSSetupResult` result if an error occurs asynchronously. Note that the `CSLocalStorage` associated to the `-[CSSetupResult storage]` may not always be the same instance as the parameter argument if a previous `CSLocalStorage` was already added at the same URL and with the same configuration. - parameter completion: the closure to be executed on the main queue when the process completes, either due to success or failure. The closure's `CSSetupResult` argument indicates the result. This closure is NOT executed if an error is thrown, but will be executed with a failure `CSSetupResult` result if an error occurs asynchronously. Note that the `CSLocalStorage` associated to the `-[CSSetupResult storage]` may not always be the same instance as the parameter argument if a previous `CSLocalStorage` was already added at the same URL and with the same configuration.
- parameter error: the `NSError` pointer that indicates the reason in case of an failure - parameter error: the `NSError` pointer that indicates the reason in case of an failure
- returns: an `NSProgress` instance if a migration has started. `nil` if no migrations are required or if `error` was set. - returns: an `NSProgress` instance if a migration has started. `nil` if no migrations are required or if `error` was set.
*/ */
public static func addSQLiteStorage(storage: CSSQLiteStore, completion: (CSSetupResult) -> Void, error: NSErrorPointer) -> NSProgress? { public static func addSQLiteStorage(_ storage: CSSQLiteStore, completion: @escaping (CSSetupResult) -> Void, error: NSErrorPointer) -> Progress? {
return self.defaultStack.addSQLiteStorage(storage, completion: completion, error: error) return self.defaultStack.addSQLiteStorage(storage, completion: completion, error: error)
} }
@@ -88,7 +86,7 @@ public extension CSCoreStore {
- returns: an `NSProgress` instance if a migration has started. `nil` if no migrations are required or if `error` was set. - returns: an `NSProgress` instance if a migration has started. `nil` if no migrations are required or if `error` was set.
*/ */
@objc @objc
public static func upgradeStorageIfNeeded(storage: CSSQLiteStore, completion: (CSMigrationResult) -> Void, error: NSErrorPointer) -> NSProgress? { public static func upgradeStorageIfNeeded(_ storage: CSSQLiteStore, completion: @escaping (CSMigrationResult) -> Void, error: NSErrorPointer) -> Progress? {
return self.defaultStack.upgradeStorageIfNeeded(storage, completion: completion, error: error) return self.defaultStack.upgradeStorageIfNeeded(storage, completion: completion, error: error)
} }
@@ -101,8 +99,7 @@ public extension CSCoreStore {
- returns: a `CSMigrationType` array indicating the migration steps required for the store, or an empty array if the file does not exist yet. Otherwise, `nil` is returned and the `error` argument is set if either inspection of the store failed, or if no mapping model was found/inferred. - returns: a `CSMigrationType` array indicating the migration steps required for the store, or an empty array if the file does not exist yet. Otherwise, `nil` is returned and the `error` argument is set if either inspection of the store failed, or if no mapping model was found/inferred.
*/ */
@objc @objc
@warn_unused_result public static func requiredMigrationsForSQLiteStore(_ storage: CSSQLiteStore, error: NSErrorPointer) -> [CSMigrationType]? {
public static func requiredMigrationsForSQLiteStore(storage: CSSQLiteStore, error: NSErrorPointer) -> [CSMigrationType]? {
return self.defaultStack.requiredMigrationsForSQLiteStore(storage, error: error) return self.defaultStack.requiredMigrationsForSQLiteStore(storage, error: error)
} }

View File

@@ -2,7 +2,7 @@
// CSCoreStore+Observing.swift // CSCoreStore+Observing.swift
// CoreStore // CoreStore
// //
// Copyright © 2015 John Rommel Estropia // Copyright © 2018 John Rommel Estropia
// //
// Permission is hereby granted, free of charge, to any person obtaining a copy // Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal // of this software and associated documentation files (the "Software"), to deal
@@ -27,10 +27,9 @@ import Foundation
import CoreData import CoreData
#if os(iOS) || os(watchOS) || os(tvOS)
// MARK: - CSCoreStore // MARK: - CSCoreStore
@available(macOS 10.12, *)
public extension CSCoreStore { public extension CSCoreStore {
/** /**
@@ -40,8 +39,7 @@ public extension CSCoreStore {
- returns: a `CSObjectMonitor` that monitors changes to `object` - returns: a `CSObjectMonitor` that monitors changes to `object`
*/ */
@objc @objc
@warn_unused_result public static func monitorObject(_ object: NSManagedObject) -> CSObjectMonitor {
public static func monitorObject(object: NSManagedObject) -> CSObjectMonitor {
return self.defaultStack.monitorObject(object) return self.defaultStack.monitorObject(object)
} }
@@ -54,8 +52,7 @@ public extension CSCoreStore {
- returns: a `CSListMonitor` instance that monitors changes to the list - returns: a `CSListMonitor` instance that monitors changes to the list
*/ */
@objc @objc
@warn_unused_result public static func monitorListFrom(_ from: CSFrom, fetchClauses: [CSFetchClause]) -> CSListMonitor {
public static func monitorListFrom(from: CSFrom, fetchClauses: [CSFetchClause]) -> CSListMonitor {
return self.defaultStack.monitorListFrom(from, fetchClauses: fetchClauses) return self.defaultStack.monitorListFrom(from, fetchClauses: fetchClauses)
} }
@@ -68,7 +65,7 @@ public extension CSCoreStore {
- parameter fetchClauses: a series of `CSFetchClause` instances for fetching the object list. Accepts `CSWhere`, `CSOrderBy`, and `CSTweak` clauses. - parameter fetchClauses: a series of `CSFetchClause` instances for fetching the object list. Accepts `CSWhere`, `CSOrderBy`, and `CSTweak` clauses.
*/ */
@objc @objc
public static func monitorListByCreatingAsynchronously(createAsynchronously: (CSListMonitor) -> Void, from: CSFrom, fetchClauses: [CSFetchClause]) { public static func monitorListByCreatingAsynchronously(_ createAsynchronously: @escaping (CSListMonitor) -> Void, from: CSFrom, fetchClauses: [CSFetchClause]) {
return self.defaultStack.monitorListByCreatingAsynchronously( return self.defaultStack.monitorListByCreatingAsynchronously(
createAsynchronously, createAsynchronously,
@@ -86,8 +83,7 @@ public extension CSCoreStore {
- returns: a `CSListMonitor` instance that monitors changes to the list - returns: a `CSListMonitor` instance that monitors changes to the list
*/ */
@objc @objc
@warn_unused_result public static func monitorSectionedListFrom(_ from: CSFrom, sectionBy: CSSectionBy, fetchClauses: [CSFetchClause]) -> CSListMonitor {
public static func monitorSectionedListFrom(from: CSFrom, sectionBy: CSSectionBy, fetchClauses: [CSFetchClause]) -> CSListMonitor {
return self.defaultStack.monitorSectionedListFrom( return self.defaultStack.monitorSectionedListFrom(
from, from,
@@ -105,7 +101,7 @@ public extension CSCoreStore {
- parameter fetchClauses: a series of `CSFetchClause` instances for fetching the object list. Accepts `CSWhere`, `CSOrderBy`, and `CSTweak` clauses. - parameter fetchClauses: a series of `CSFetchClause` instances for fetching the object list. Accepts `CSWhere`, `CSOrderBy`, and `CSTweak` clauses.
*/ */
@objc @objc
public static func monitorSectionedListByCreatingAsynchronously(createAsynchronously: (CSListMonitor) -> Void, from: CSFrom, sectionBy: CSSectionBy, fetchClauses: [CSFetchClause]) { public static func monitorSectionedListByCreatingAsynchronously(_ createAsynchronously: @escaping (CSListMonitor) -> Void, from: CSFrom, sectionBy: CSSectionBy, fetchClauses: [CSFetchClause]) {
self.defaultStack.monitorSectionedListByCreatingAsynchronously( self.defaultStack.monitorSectionedListByCreatingAsynchronously(
createAsynchronously, createAsynchronously,
@@ -115,5 +111,3 @@ public extension CSCoreStore {
) )
} }
} }
#endif

View File

@@ -2,7 +2,7 @@
// CSCoreStore+Querying.swift // CSCoreStore+Querying.swift
// CoreStore // CoreStore
// //
// Copyright © 2016 John Rommel Estropia // Copyright © 2018 John Rommel Estropia
// //
// Permission is hereby granted, free of charge, to any person obtaining a copy // Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal // of this software and associated documentation files (the "Software"), to deal
@@ -38,8 +38,7 @@ public extension CSCoreStore {
- returns: the `NSManagedObject` instance if the object exists in the transaction, or `nil` if not found. - returns: the `NSManagedObject` instance if the object exists in the transaction, or `nil` if not found.
*/ */
@objc @objc
@warn_unused_result public static func fetchExistingObject(_ object: NSManagedObject) -> Any? {
public static func fetchExistingObject(object: NSManagedObject) -> AnyObject? {
return self.defaultStack.fetchExistingObject(object) return self.defaultStack.fetchExistingObject(object)
} }
@@ -51,8 +50,7 @@ public extension CSCoreStore {
- returns: the `NSManagedObject` instance if the object exists in the transaction, or `nil` if not found. - returns: the `NSManagedObject` instance if the object exists in the transaction, or `nil` if not found.
*/ */
@objc @objc
@warn_unused_result public static func fetchExistingObjectWithID(_ objectID: NSManagedObjectID) -> Any? {
public static func fetchExistingObjectWithID(objectID: NSManagedObjectID) -> AnyObject? {
return self.defaultStack.fetchExistingObjectWithID(objectID) return self.defaultStack.fetchExistingObjectWithID(objectID)
} }
@@ -64,8 +62,7 @@ public extension CSCoreStore {
- returns: the `NSManagedObject` array for objects that exists in the transaction - returns: the `NSManagedObject` array for objects that exists in the transaction
*/ */
@objc @objc
@warn_unused_result public static func fetchExistingObjects(_ objects: [NSManagedObject]) -> [Any] {
public static func fetchExistingObjects(objects: [NSManagedObject]) -> [AnyObject] {
return self.defaultStack.fetchExistingObjects(objects) return self.defaultStack.fetchExistingObjects(objects)
} }
@@ -77,8 +74,7 @@ public extension CSCoreStore {
- returns: the `NSManagedObject` array for objects that exists in the transaction - returns: the `NSManagedObject` array for objects that exists in the transaction
*/ */
@objc @objc
@warn_unused_result public static func fetchExistingObjectsWithIDs(_ objectIDs: [NSManagedObjectID]) -> [Any] {
public static func fetchExistingObjectsWithIDs(objectIDs: [NSManagedObjectID]) -> [AnyObject] {
return self.defaultStack.fetchExistingObjectsWithIDs(objectIDs) return self.defaultStack.fetchExistingObjectsWithIDs(objectIDs)
} }
@@ -91,8 +87,7 @@ public extension CSCoreStore {
- returns: the first `NSManagedObject` instance that satisfies the specified `CSFetchClause`s - returns: the first `NSManagedObject` instance that satisfies the specified `CSFetchClause`s
*/ */
@objc @objc
@warn_unused_result public static func fetchOneFrom(_ from: CSFrom, fetchClauses: [CSFetchClause]) -> Any? {
public static func fetchOneFrom(from: CSFrom, fetchClauses: [CSFetchClause]) -> AnyObject? {
return self.defaultStack.fetchOneFrom(from, fetchClauses: fetchClauses) return self.defaultStack.fetchOneFrom(from, fetchClauses: fetchClauses)
} }
@@ -105,8 +100,7 @@ public extension CSCoreStore {
- returns: all `NSManagedObject` instances that satisfy the specified `CSFetchClause`s - returns: all `NSManagedObject` instances that satisfy the specified `CSFetchClause`s
*/ */
@objc @objc
@warn_unused_result public static func fetchAllFrom(_ from: CSFrom, fetchClauses: [CSFetchClause]) -> [Any]? {
public static func fetchAllFrom(from: CSFrom, fetchClauses: [CSFetchClause]) -> [AnyObject]? {
return self.defaultStack.fetchAllFrom(from, fetchClauses: fetchClauses) return self.defaultStack.fetchAllFrom(from, fetchClauses: fetchClauses)
} }
@@ -119,8 +113,7 @@ public extension CSCoreStore {
- returns: the number `NSManagedObject`s that satisfy the specified `CSFetchClause`s - returns: the number `NSManagedObject`s that satisfy the specified `CSFetchClause`s
*/ */
@objc @objc
@warn_unused_result public static func fetchCountFrom(_ from: CSFrom, fetchClauses: [CSFetchClause]) -> NSNumber? {
public static func fetchCountFrom(from: CSFrom, fetchClauses: [CSFetchClause]) -> NSNumber? {
return self.defaultStack.fetchCountFrom(from, fetchClauses: fetchClauses) return self.defaultStack.fetchCountFrom(from, fetchClauses: fetchClauses)
} }
@@ -133,8 +126,7 @@ public extension CSCoreStore {
- returns: the `NSManagedObjectID` for the first `NSManagedObject` that satisfies the specified `CSFetchClause`s - returns: the `NSManagedObjectID` for the first `NSManagedObject` that satisfies the specified `CSFetchClause`s
*/ */
@objc @objc
@warn_unused_result public static func fetchObjectIDFrom(_ from: CSFrom, fetchClauses: [CSFetchClause]) -> NSManagedObjectID? {
public static func fetchObjectIDFrom(from: CSFrom, fetchClauses: [CSFetchClause]) -> NSManagedObjectID? {
return self.defaultStack.fetchObjectIDFrom(from, fetchClauses: fetchClauses) return self.defaultStack.fetchObjectIDFrom(from, fetchClauses: fetchClauses)
} }
@@ -147,8 +139,7 @@ public extension CSCoreStore {
- returns: the `NSManagedObjectID` for all `NSManagedObject`s that satisfy the specified `CSFetchClause`s - returns: the `NSManagedObjectID` for all `NSManagedObject`s that satisfy the specified `CSFetchClause`s
*/ */
@objc @objc
@warn_unused_result public static func fetchObjectIDsFrom(_ from: CSFrom, fetchClauses: [CSFetchClause]) -> [NSManagedObjectID]? {
public static func fetchObjectIDsFrom(from: CSFrom, fetchClauses: [CSFetchClause]) -> [NSManagedObjectID]? {
return self.defaultStack.fetchObjectIDsFrom(from, fetchClauses: fetchClauses) return self.defaultStack.fetchObjectIDsFrom(from, fetchClauses: fetchClauses)
} }
@@ -164,8 +155,7 @@ public extension CSCoreStore {
- returns: the result of the the query. The type of the return value is specified by the generic type of the `CSSelect` parameter. - returns: the result of the the query. The type of the return value is specified by the generic type of the `CSSelect` parameter.
*/ */
@objc @objc
@warn_unused_result public static func queryValueFrom(_ from: CSFrom, selectClause: CSSelect, queryClauses: [CSQueryClause]) -> Any? {
public static func queryValueFrom(from: CSFrom, selectClause: CSSelect, queryClauses: [CSQueryClause]) -> AnyObject? {
return self.defaultStack.queryValueFrom(from, selectClause: selectClause, queryClauses: queryClauses) return self.defaultStack.queryValueFrom(from, selectClause: selectClause, queryClauses: queryClauses)
} }
@@ -181,8 +171,7 @@ public extension CSCoreStore {
- returns: the result of the the query. The type of the return value is specified by the generic type of the `CSSelect` parameter. - returns: the result of the the query. The type of the return value is specified by the generic type of the `CSSelect` parameter.
*/ */
@objc @objc
@warn_unused_result public static func queryAttributesFrom(_ from: CSFrom, selectClause: CSSelect, queryClauses: [CSQueryClause]) -> [[String: Any]]? {
public static func queryAttributesFrom(from: CSFrom, selectClause: CSSelect, queryClauses: [CSQueryClause]) -> [[NSString: AnyObject]]? {
return self.defaultStack.queryAttributesFrom(from, selectClause: selectClause, queryClauses: queryClauses) return self.defaultStack.queryAttributesFrom(from, selectClause: selectClause, queryClauses: queryClauses)
} }

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