Compare commits

...

176 Commits

Author SHA1 Message Date
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
ed0fdc76fe update podspec 2016-09-06 11:19:38 +09:00
John Estropia
58f4907575 Prevent retain cycles in NSManagedObjectContext (fixes #87) 2016-09-06 11:13:16 +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
1950224863 version bump 2016-07-22 00:33:15 +09:00
John Rommel Estropia
f0cd288657 allow querying on relationship attributes (fixes #83) 2016-07-22 00:29:48 +09:00
John Rommel Estropia
2f39f9188b WIP: the great renaming 2016-07-21 23:12:24 +09:00
John Estropia
3344e42d7c version bump 2016-07-21 11:51:57 +09:00
John Estropia
e4b6c06401 fixed internal errors getting thrown as .Unknown instead of .InternalError (fixes #84) 2016-07-21 11:51:49 +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
John Estropia
7fc3ad2890 Tidy up, version bump 2016-07-14 19:59:15 +09:00
John Estropia
556f6d13b3 Merge pull request #81 from jannon/mark-app-extension-safe
Mark app extension safe
2016-07-14 19:41:55 +09:00
Jannon Frank
a088fe3817 mark iOS and tvOS safe for app extensions 2016-07-12 18:39:23 -07:00
Jannon Frank
c4391a8d0c Merge remote-tracking branch 'JohnEstropia/master' into upstream 2016-07-12 18:36:53 -07:00
229 changed files with 22855 additions and 14439 deletions

3
.gitmodules vendored
View File

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

1
.swift-version Normal file
View File

@@ -0,0 +1 @@
3.1

View File

@@ -1,5 +1,5 @@
language: objective-c language: objective-c
osx_image: xcode7.3 osx_image: xcode8.3
sudo: false sudo: false
git: git:
submodules: false submodules: false
@@ -9,21 +9,23 @@ env:
global: global:
- 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="OS=10.3,name=iPhone 7" SCHEME="CoreStore iOS" SDK=iphonesimulator10.3 RUN_TESTS="YES" POD_LINT="NO"
- DESTINATION="OS=9.0,name=iPhone 6 Plus" SCHEME="CoreStore iOS" SDK=iphonesimulator9.3 RUN_TESTS="YES" POD_LINT="NO" - DESTINATION="OS=10.1,name=iPhone 7" SCHEME="CoreStore iOS" SDK=iphonesimulator10.3 RUN_TESTS="YES" POD_LINT="NO"
- DESTINATION="OS=8.4,name=iPhone 6" SCHEME="CoreStore iOS" SDK=iphonesimulator9.3 RUN_TESTS="YES" POD_LINT="NO" - DESTINATION="OS=9.0,name=iPhone 6 Plus" SCHEME="CoreStore iOS" SDK=iphonesimulator10.3 RUN_TESTS="YES" POD_LINT="NO"
- DESTINATION="OS=8.3,name=iPhone 5S" SCHEME="CoreStore iOS" SDK=iphonesimulator9.3 RUN_TESTS="YES" POD_LINT="NO" - DESTINATION="OS=8.4,name=iPhone 6" SCHEME="CoreStore iOS" SDK=iphonesimulator10.3 RUN_TESTS="YES" POD_LINT="NO"
- DESTINATION="OS=8.2,name=iPhone 5" SCHEME="CoreStore iOS" SDK=iphonesimulator9.3 RUN_TESTS="YES" POD_LINT="NO" - DESTINATION="OS=8.3,name=iPhone 5S" SCHEME="CoreStore iOS" SDK=iphonesimulator10.3 RUN_TESTS="YES" POD_LINT="NO"
- DESTINATION="OS=8.1,name=iPhone 4S" SCHEME="CoreStore iOS" SDK=iphonesimulator9.3 RUN_TESTS="YES" POD_LINT="YES" - DESTINATION="OS=8.3,name=iPhone 5" SCHEME="CoreStore iOS" SDK=iphonesimulator10.3 RUN_TESTS="YES" POD_LINT="NO"
- DESTINATION="OS=8.1,name=iPhone 4S" SCHEME="CoreStore iOS7" SDK=iphonesimulator9.3 RUN_TESTS="YES" POD_LINT="YES" - DESTINATION="OS=8.3,name=iPhone 4S" SCHEME="CoreStore iOS" SDK=iphonesimulator10.3 RUN_TESTS="YES" POD_LINT="NO"
- DESTINATION="arch=x86_64" SCHEME="CoreStore OSX" SDK=macosx10.11 RUN_TESTS="YES" POD_LINT="NO" - DESTINATION="arch=x86_64" SCHEME="CoreStore OSX" SDK=macosx10.12 RUN_TESTS="YES" POD_LINT="NO"
- DESTINATION="OS=2.2,name=Apple Watch - 42mm" SCHEME="CoreStore watchOS" SDK=watchsimulator2.2 RUN_TESTS="NO" POD_LINT="NO" - DESTINATION="OS=3.2,name=Apple Watch - 42mm" SCHEME="CoreStore watchOS" SDK=watchsimulator3.2 RUN_TESTS="NO" POD_LINT="NO"
- DESTINATION="OS=9.2,name=Apple TV 1080p" SCHEME="CoreStore tvOS" SDK=appletvsimulator9.2 RUN_TESTS="YES" POD_LINT="NO" - DESTINATION="OS=2.2,name=Apple Watch - 42mm" SCHEME="CoreStore watchOS" SDK=watchsimulator3.2 RUN_TESTS="NO" POD_LINT="NO"
- DESTINATION="OS=10.2,name=Apple TV 1080p" SCHEME="CoreStore tvOS" SDK=appletvsimulator10.2 RUN_TESTS="YES" POD_LINT="NO"
- DESTINATION="OS=9.2,name=Apple TV 1080p" SCHEME="CoreStore tvOS" SDK=appletvsimulator10.2 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.20.1/Carthage.pkg"
- sudo installer -pkg "Carthage.pkg" -target / - sudo installer -pkg "Carthage.pkg" -target /
- rm "Carthage.pkg" - rm "Carthage.pkg"
before_script: before_script:
@@ -36,8 +38,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 "CoreStore iOS" -sdk "iphonesimulator10.3" -destination "OS=10.3,name=iPhone 7" -configuration Debug ONLY_ACTIVE_ARCH=NO clean test | xcpretty -c;
- xcodebuild -workspace "CoreStore.xcworkspace" -scheme "CoreStore iOS" -sdk "iphonesimulator9.3" -destination "OS=9.3,name=iPhone 6s" -configuration Release ONLY_ACTIVE_ARCH=NO clean test | xcpretty -c; - xcodebuild -workspace "CoreStore.xcworkspace" -scheme "CoreStore iOS" -sdk "iphonesimulator10.3" -destination "OS=10.3,name=iPhone 7" -configuration Release ONLY_ACTIVE_ARCH=NO clean test | 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.5

View File

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

View File

@@ -1,6 +1,6 @@
Pod::Spec.new do |s| Pod::Spec.new do |s|
s.name = "CoreStore" s.name = "CoreStore"
s.version = "2.0.0" s.version = "4.0.0-beta2"
s.license = "MIT" s.license = "MIT"
s.summary = "Unleashing the real power of Core Data with the elegance and safety of Swift" s.summary = "Unleashing the real power of Core Data with the elegance and safety of Swift"
s.homepage = "https://github.com/JohnEstropia/CoreStore" s.homepage = "https://github.com/JohnEstropia/CoreStore"
@@ -16,8 +16,5 @@ Pod::Spec.new do |s|
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.5"
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

@@ -1,6 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?> <?xml version="1.0" encoding="UTF-8"?>
<Scheme <Scheme
LastUpgradeVersion = "0710" LastUpgradeVersion = "0800"
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 = "0800"
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

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 = "0800"
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 = "0800"
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

@@ -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 = 0800;
ORGANIZATIONNAME = "John Rommel Estropia"; ORGANIZATIONNAME = "John Rommel Estropia";
TargetAttributes = { TargetAttributes = {
B54AAD481AF4D26E00848AE0 = { B54AAD481AF4D26E00848AE0 = {
CreatedOnToolsVersion = 6.3; CreatedOnToolsVersion = 6.3;
LastSwiftMigration = 0800;
}; };
}; };
}; };
@@ -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 */,
@@ -383,8 +376,10 @@
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_OBJC_ROOT_CLASS = YES_ERROR; CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
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";
@@ -428,8 +423,10 @@
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_OBJC_ROOT_CLASS = YES_ERROR; CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
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";
@@ -461,6 +458,7 @@
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_VERSION = 3.0;
}; };
name = Debug; name = Debug;
}; };
@@ -473,6 +471,8 @@
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_VERSION = 3.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 = "0800"
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

@@ -8,6 +8,7 @@
import UIKit import UIKit
import CoreStore
// MARK: - AppDelegate // MARK: - AppDelegate
@@ -18,10 +19,9 @@ 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
application.statusBarStyle = .lightContent
return true return true
} }
} }

View File

@@ -1,39 +1,28 @@
<?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="12113" systemVersion="16C67" 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="12078"/>
<capability name="Aspect ratio constraints" minToolsVersion="5.1"/> <capability name="Aspect ratio constraints" minToolsVersion="5.1"/>
<capability name="Constraints to layout margins" minToolsVersion="6.0"/> <capability name="Constraints to layout margins" minToolsVersion="6.0"/>
<capability name="Constraints with non-1.0 multipliers" minToolsVersion="5.1"/> <capability name="Constraints with non-1.0 multipliers" minToolsVersion="5.1"/>
<capability name="documents saved in the Xcode 8 format" minToolsVersion="8.0"/>
</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 +30,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 +71,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="15" 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="308" 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 +120,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="295" y="8" width="72" height="27.5"/>
<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 +145,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="15" y="8" width="270" height="27.5"/>
<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 +173,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 +226,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 +235,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 +265,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="342" 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="15" 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="15" 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 +299,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="342" 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="15" 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="15" 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 +326,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="342" 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="15" 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="15" 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 +353,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="342" 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="15" 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="15" 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 +380,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="342" 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="15" 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="15" 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 +407,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="342" 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="15" 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="15" 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 +456,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" misplaced="YES" translatesAutoresizingMaskIntoConstraints="NO" id="NhC-oM-bkd">
<rect key="frame" x="20" y="69.5" width="552" height="36.5"/> <rect key="frame" x="20" y="69.5" width="552" height="36.5"/>
<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" misplaced="YES" 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="20" y="49" width="552" 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 +580,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"/>
@@ -636,11 +625,11 @@
<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="0.0" width="320" 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,19 +646,19 @@
<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="342" 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="8" y="8" width="27" height="27"/>
<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>
@@ -677,7 +666,7 @@
<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="45" y="8" width="34.5" height="27"/>
<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,20 +705,20 @@
<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="342" 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="8" y="8" width="27" height="27"/>
<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>
@@ -737,7 +726,7 @@
<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="45" y="8" width="34.5" height="27"/>
<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>
@@ -780,11 +769,11 @@
<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="320" 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,17 +794,17 @@
<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="64" 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 clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="scaleToFill" ambiguous="YES" 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="536"/>
<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="GcS-Jz-Wcm"/>
<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"/>
@@ -842,30 +831,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"/>
@@ -901,11 +890,11 @@
<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="320" 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,15 +915,15 @@
<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">
@@ -943,13 +932,13 @@
<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 +947,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 +970,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 +995,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="15" 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="15" 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 +1041,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="15" 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="15" 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

@@ -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)! 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 = [
@@ -167,8 +165,8 @@ class FetchingAndQueryingDemoViewController: UIViewController, UITableViewDataSo
fetch: { () -> [TimeZone] in fetch: { () -> [TimeZone] in
return Static.timeZonesStack.fetchAll( return Static.timeZonesStack.fetchAll(
From(TimeZone), From<TimeZone>(),
OrderBy(.Ascending("name")) OrderBy(.ascending(#keyPath(TimeZone.name)))
)! )!
} }
), ),
@@ -177,9 +175,9 @@ class FetchingAndQueryingDemoViewController: UIViewController, UITableViewDataSo
fetch: { () -> [TimeZone] in fetch: { () -> [TimeZone] in
return Static.timeZonesStack.fetchAll( return Static.timeZonesStack.fetchAll(
From(TimeZone), From<TimeZone>(),
Where("%K BEGINSWITH[c] %@", "name", "Asia"), Where("%K BEGINSWITH[c] %@", #keyPath(TimeZone.name), "Asia"),
OrderBy(.Ascending("secondsFromGMT")) OrderBy(.ascending(#keyPath(TimeZone.secondsFromGMT)))
)! )!
} }
), ),
@@ -188,10 +186,10 @@ class FetchingAndQueryingDemoViewController: UIViewController, UITableViewDataSo
fetch: { () -> [TimeZone] in fetch: { () -> [TimeZone] in
return Static.timeZonesStack.fetchAll( return Static.timeZonesStack.fetchAll(
From(TimeZone), From<TimeZone>(),
Where("%K BEGINSWITH[c] %@", "name", "America") Where("%K BEGINSWITH[c] %@", #keyPath(TimeZone.name), "America")
|| Where("%K BEGINSWITH[c] %@", "name", "Europe"), || Where("%K BEGINSWITH[c] %@", #keyPath(TimeZone.name), "Europe"),
OrderBy(.Ascending("secondsFromGMT")) OrderBy(.ascending(#keyPath(TimeZone.secondsFromGMT)))
)! )!
} }
), ),
@@ -200,9 +198,9 @@ class FetchingAndQueryingDemoViewController: UIViewController, UITableViewDataSo
fetch: { () -> [TimeZone] in fetch: { () -> [TimeZone] in
return Static.timeZonesStack.fetchAll( return Static.timeZonesStack.fetchAll(
From(TimeZone), From<TimeZone>(),
!Where("%K BEGINSWITH[c] %@", "name", "America"), !Where("%K BEGINSWITH[c] %@", #keyPath(TimeZone.name), "America"),
OrderBy(.Ascending("secondsFromGMT")) OrderBy(.ascending(#keyPath(TimeZone.secondsFromGMT)))
)! )!
} }
), ),
@@ -211,9 +209,9 @@ class FetchingAndQueryingDemoViewController: UIViewController, UITableViewDataSo
fetch: { () -> [TimeZone] in fetch: { () -> [TimeZone] in
return Static.timeZonesStack.fetchAll( return Static.timeZonesStack.fetchAll(
From(TimeZone), From<TimeZone>(),
Where("hasDaylightSavingTime", isEqualTo: true), Where("hasDaylightSavingTime", isEqualTo: true),
OrderBy(.Ascending("name")) OrderBy(.ascending(#keyPath(TimeZone.name)))
)! )!
} }
) )
@@ -222,60 +220,60 @@ class FetchingAndQueryingDemoViewController: UIViewController, UITableViewDataSo
private let queryingItems = [ private let queryingItems = [
( (
title: "Number of Time Zones", title: "Number of Time Zones",
query: { () -> AnyObject in query: { () -> Any in
return Static.timeZonesStack.queryValue( return Static.timeZonesStack.queryValue(
From(TimeZone), From<TimeZone>(),
Select<NSNumber>(.Count("name")) Select<NSNumber>(.count(#keyPath(TimeZone.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 Static.timeZonesStack.queryValue(
From(TimeZone), From<TimeZone>(),
Select<String>("abbreviation"), Select<String>(#keyPath(TimeZone.abbreviation)),
Where("%K ENDSWITH[c] %@", "name", "Tokyo") Where("%K ENDSWITH[c] %@", #keyPath(TimeZone.name), "Tokyo")
)! )!
} }
), ),
( (
title: "All Abbreviations", title: "All Abbreviations",
query: { () -> AnyObject in query: { () -> Any in
return Static.timeZonesStack.queryAttributes( return Static.timeZonesStack.queryAttributes(
From(TimeZone), From<TimeZone>(),
Select<NSDictionary>("name", "abbreviation"), Select<NSDictionary>(#keyPath(TimeZone.name), #keyPath(TimeZone.abbreviation)),
OrderBy(.Ascending("name")) OrderBy(.ascending(#keyPath(TimeZone.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 Static.timeZonesStack.queryAttributes(
From(TimeZone), From<TimeZone>(),
Select<NSDictionary>(.Count("abbreviation"), "abbreviation"), Select<NSDictionary>(.count(#keyPath(TimeZone.abbreviation)), #keyPath(TimeZone.abbreviation)),
GroupBy("abbreviation"), GroupBy(#keyPath(TimeZone.abbreviation)),
OrderBy(.Ascending("secondsFromGMT"), .Ascending("name")) OrderBy(.ascending(#keyPath(TimeZone.secondsFromGMT)), .ascending(#keyPath(TimeZone.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 Static.timeZonesStack.queryAttributes(
From(TimeZone), From<TimeZone>(),
Select<NSDictionary>( Select<NSDictionary>(
.Count("hasDaylightSavingTime", As: "numberOfCountries"), .count(#keyPath(TimeZone.hasDaylightSavingTime), as: "numberOfCountries"),
"hasDaylightSavingTime" #keyPath(TimeZone.hasDaylightSavingTime)
), ),
GroupBy("hasDaylightSavingTime"), GroupBy(#keyPath(TimeZone.hasDaylightSavingTime)),
OrderBy(.Descending("hasDaylightSavingTime")) OrderBy(.descending(#keyPath(TimeZone.hasDaylightSavingTime)))
)! )!
} }
) )
@@ -286,7 +284,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

@@ -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

@@ -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

@@ -14,17 +14,17 @@ private struct Static {
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
} }
} }
@@ -32,18 +32,21 @@ private struct Static {
switch self { switch self {
case .All: return Where(true) case .all: return Where(true)
case .Light: return Where("brightness >= 0.9") case .light: return Where("%K >= %@", #keyPath(Palette.brightness), 0.9)
case .Dark: return Where("brightness <= 0.4") case .dark: return Where("%K <= %@", #keyPath(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(.ascending(#keyPath(Palette.hue)))
)
} }
} }
@@ -53,14 +56,14 @@ private struct Static {
SQLiteStore( SQLiteStore(
fileName: "ColorsDemo.sqlite", fileName: "ColorsDemo.sqlite",
configuration: "ObservingDemo", configuration: "ObservingDemo",
localStorageOptions: .RecreateStoreOnModelMismatch localStorageOptions: .recreateStoreOnModelMismatch
) )
) )
return CoreStore.monitorSectionedList( return CoreStore.monitorSectionedList(
From(Palette), From<Palette>(),
SectionBy("colorName"), SectionBy(#keyPath(Palette.colorName)),
OrderBy(.Ascending("hue")) OrderBy(.ascending(#keyPath(Palette.hue)))
) )
}() }()
} }
@@ -86,9 +89,9 @@ 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(_:))
) )
@@ -96,13 +99,13 @@ class ListObserverDemoViewController: UITableViewController, ListSectionObserver
let filterBarButton = UIBarButtonItem( let filterBarButton = UIBarButtonItem(
title: Static.filter.rawValue, title: Static.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(_:))
), ),
@@ -112,14 +115,14 @@ class ListObserverDemoViewController: UITableViewController, ListSectionObserver
Static.palettes.addObserver(self) Static.palettes.addObserver(self)
self.setTableEnabled(!Static.palettes.isPendingRefetch) self.setTable(enabled: !Static.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,19 +135,19 @@ 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 Static.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 Static.palettes.numberOfObjectsInSection(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 = Static.palettes[indexPath]
cell.colorView?.backgroundColor = palette.color cell.colorView?.backgroundColor = palette.color
@@ -156,34 +159,36 @@ 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: Static.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 = Static.palettes[indexPath]
CoreStore.beginAsynchronous{ (transaction) -> Void in CoreStore.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 Static.palettes.sectionInfoAtIndex(section).name
} }
@@ -191,44 +196,44 @@ class ListObserverDemoViewController: UITableViewController, ListSectionObserver
// 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 = Static.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 = Static.palettes[indexPath]
cell.colorView?.backgroundColor = palette.color cell.colorView?.backgroundColor = palette.color
@@ -236,23 +241,24 @@ class ListObserverDemoViewController: UITableViewController, ListSectionObserver
} }
} }
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 +266,46 @@ 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 CoreStore.perform(
asynchronous: { (transaction) in
transaction.deleteAll(From(Palette))
transaction.commit() 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() Static.filter = Static.filter.next()
} }
@IBAction private dynamic func addBarButtonItemTouched(sender: AnyObject?) { @IBAction private dynamic func addBarButtonItemTouched(_ sender: AnyObject?) {
CoreStore.beginAsynchronous { (transaction) -> Void in CoreStore.perform(
asynchronous: { (transaction) in
let palette = transaction.create(Into(Palette))
palette.setInitialValues() let palette = transaction.create(Into<Palette>())
palette.setInitialValues()
transaction.commit() },
} 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

@@ -50,21 +50,21 @@ 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 = CoreStore.fetchOne(From<Palette>(), OrderBy(.ascending(#keyPath(Palette.hue)))) {
self.monitor = CoreStore.monitorObject(palette) self.monitor = CoreStore.monitorObject(palette)
} }
else { else {
CoreStore.beginSynchronous { (transaction) -> Void in _ = try? CoreStore.perform(
synchronous: { (transaction) in
let palette = transaction.create(Into(Palette))
palette.setInitialValues() let palette = transaction.create(Into(Palette.self))
palette.setInitialValues()
transaction.commitAndWait() }
} )
let palette = CoreStore.fetchOne(From(Palette), OrderBy(.Ascending("hue")))! let palette = CoreStore.fetchOne(From<Palette>(), OrderBy(.ascending(#keyPath(Palette.hue))))!
self.monitor = CoreStore.monitorObject(palette) self.monitor = CoreStore.monitorObject(palette)
} }
@@ -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<KeyPath>) {
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,55 +118,63 @@ 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 CoreStore.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 = Int32(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 CoreStore.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 CoreStore.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 CoreStore.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
@@ -176,15 +184,15 @@ 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(#keyPath(Palette.hue)) == true {
self.hueSlider?.value = Float(palette.hue) self.hueSlider?.value = Float(palette.hue)
} }
if changedKeys == nil || changedKeys?.contains("saturation") == true { if changedKeys == nil || changedKeys?.contains(#keyPath(Palette.saturation)) == true {
self.saturationSlider?.value = palette.saturation self.saturationSlider?.value = palette.saturation
} }
if changedKeys == nil || changedKeys?.contains("brightness") == true { if changedKeys == nil || changedKeys?.contains(#keyPath(Palette.brightness)) == true {
self.brightnessSlider?.value = palette.brightness self.brightnessSlider?.value = palette.brightness
} }

View File

@@ -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

@@ -24,8 +24,8 @@ class Palette: NSManagedObject {
get { get {
let KVCKey = "colorName" let KVCKey = #keyPath(Palette.colorName)
if let colorName = self.accessValueForKVCKey(KVCKey) as? String { if let colorName = self.getValue(forKvcKey: KVCKey) as? String {
return colorName return colorName
} }
@@ -49,7 +49,7 @@ class Palette: NSManagedObject {
} }
set { set {
self.setValue(newValue, forKVCKey: "colorName") self.setValue(newValue.cs_toImportableNativeType(), forKvcKey: #keyPath(Palette.colorName))
} }
} }

View File

@@ -8,7 +8,6 @@
import UIKit import UIKit
import CoreStore import CoreStore
import GCDKit
// MARK: - CustomLoggerViewController // MARK: - CustomLoggerViewController
@@ -34,47 +33,47 @@ class CustomLoggerViewController: UIViewController, CoreStoreLogger {
CoreStore.logger = self CoreStore.logger = self
} }
override func viewDidAppear(animated: Bool) { override func viewDidAppear(_ animated: Bool) {
super.viewDidAppear(animated) super.viewDidAppear(animated)
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)
} }
// 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 +81,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 +93,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(true).applyToFetchRequest(request)
transaction.create(Into(Palette)) Where(false).applyToFetchRequest(request)
}
case 1?: case 1?:
_ = try? dataStack.addStorageAndWait( _ = try? dataStack.addStorageAndWait(
@@ -113,10 +111,9 @@ class CustomLoggerViewController: UIViewController, CoreStoreLogger {
) )
case 2?: case 2?:
self.dataStack.beginAsynchronous { (transaction) -> Void in DispatchQueue.global(qos: .background).async {
transaction.commit() _ = self.dataStack.fetchOne(From<Palette>())
transaction.commit()
} }
default: default:

View File

@@ -12,7 +12,7 @@ import CoreStore
// MARK: - MigrationsDemoViewController // MARK: - MigrationsDemoViewController
class MigrationsDemoViewController: UIViewController { class MigrationsDemoViewController: UIViewController, ListObserver, UITableViewDataSource, UITableViewDelegate {
// MARK: UIViewController // MARK: UIViewController
@@ -22,28 +22,28 @@ 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(modelName: "MigrationDemo")) {
@@ -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,104 @@ 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?.numberOfObjectsInSection(0),
numberOfObjectsInSection > 0 {
self.tableView?.reloadData()
self.setSelectedIndexPath(IndexPath(row: 0, section: 0), scrollToSelection: false)
}
else {
self.updateDisplay(reloadData: true, scrollToSelection: true, animated: true)
}
}
// MARK: UITableViewDataSource
@objc dynamic func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return self.listMonitor?.numberOfObjectsInSection(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(
modelName: "MigrationDemo",
migrationChain: ["MigrationDemoV3", "MigrationDemoV2", "MigrationDemo"]
)
), ),
( (
label: "Model V2", label: "Model V2",
version: "MigrationDemoV2",
entityType: OrganismV2.self, entityType: OrganismV2.self,
migrationChain: [ schemaHistory: SchemaHistory(
"MigrationDemo": "MigrationDemoV2", modelName: "MigrationDemo",
"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(
modelName: "MigrationDemo",
migrationChain: ["MigrationDemo", "MigrationDemoV2", "MigrationDemoV3"]
)
) )
] ]
@@ -113,13 +185,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 +204,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 +214,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 +261,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 = dataStack.queryValue(
From(model.entityType), From(model.entityType),
Select<Int>(.Count("dna")) Select<Int>(.count(#keyPath(OrganismV1.dna))))!
)
if count > 0 { if count > 0 {
self.setEnabled(true) self.setEnabled(true)
@@ -186,25 +280,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,39 +313,45 @@ 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: { (_, _, schemaHistory) -> Bool in
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(.descending("dna")))
listMonitor.addObserver(self) listMonitor.addObserver(self)
self._listMonitor = listMonitor self._listMonitor = listMonitor
@@ -258,7 +359,7 @@ class MigrationsDemoViewController: UIViewController {
if listMonitor.numberOfObjectsInSection(0) > 0 { if listMonitor.numberOfObjectsInSection(0) > 0 {
self.setSelectedIndexPath(NSIndexPath(forRow: 0, inSection: 0), scrollToSelection: true) self.setSelectedIndexPath(IndexPath(row: 0, section: 0), scrollToSelection: true)
} }
} }
} }
@@ -272,14 +373,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 +388,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 +412,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

@@ -13,4 +13,4 @@ protocol OrganismProtocol: class {
var dna: Int64 { get set } var dna: Int64 { get set }
func mutate() func mutate()
} }

View File

@@ -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

@@ -10,14 +10,20 @@ 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

@@ -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

@@ -22,33 +22,33 @@ private struct Static {
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))
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
}() }()
@@ -60,34 +60,33 @@ private struct Static {
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))
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)) ?? [], Static.facebookStack.fetchAll(From(UserAccount.self)) ?? [],
Static.twitterStack.fetchAll(From(UserAccount)) ?? [] Static.twitterStack.fetchAll(From(UserAccount.self)) ?? []
] ]
// 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

@@ -11,7 +11,6 @@ import CoreLocation
import MapKit import MapKit
import AddressBookUI import AddressBookUI
import CoreStore import CoreStore
import GCDKit
private struct Static { private struct Static {
@@ -22,21 +21,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 = 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 = CoreStore.fetchOne(From<Place>())
} }
return CoreStore.monitorObject(place!) return CoreStore.monitorObject(place!)
@@ -71,33 +70,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 +104,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 +126,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<KeyPath>) {
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 +159,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()

View File

@@ -36,11 +36,12 @@ class BaseTestCase: XCTestCase {
// MARK: Internal // MARK: Internal
@nonobjc @nonobjc
func prepareStack<T>(configurations configurations: [String?] = [nil], @noescape _ closure: (dataStack: DataStack) -> T) -> T { @discardableResult
func prepareStack<T>(configurations: [ModelConfiguration] = [nil], _ closure: (_ dataStack: DataStack) -> T) -> T {
let stack = DataStack( let stack = DataStack(
modelName: "Model", modelName: "Model",
bundle: NSBundle(forClass: self.dynamicType) bundle: Bundle(for: type(of: self))
) )
do { do {
@@ -49,10 +50,10 @@ 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
) )
) )
} }
@@ -61,11 +62,11 @@ class BaseTestCase: XCTestCase {
XCTFail(error.coreStoreDumpString) XCTFail(error.coreStoreDumpString)
} }
return closure(dataStack: stack) return closure(stack)
} }
@nonobjc @nonobjc
func expectLogger<T>(expectations: [TestLogger.Expectation], @noescape closure: () -> T) -> T { func expectLogger<T>(_ expectations: [TestLogger.Expectation], closure: () -> T) -> T {
CoreStore.logger = TestLogger(self.prepareLoggerExpectations(expectations)) CoreStore.logger = TestLogger(self.prepareLoggerExpectations(expectations))
defer { defer {
@@ -77,18 +78,18 @@ class BaseTestCase: XCTestCase {
} }
@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 +97,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 +127,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 +138,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 +153,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 +189,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

@@ -17,60 +17,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

@@ -197,4 +197,93 @@
XCTAssertNil(sqliteError); XCTAssertNil(sqliteError);
} }
- (void)test_ThatTransactions_BridgeCorrectly {
[CSCoreStore
setDefaultStack:[[CSDataStack alloc]
initWithModelName:@"Model"
bundle:[NSBundle bundleForClass:[self class]]
versionChain:nil]];
[CSCoreStore
addInMemoryStorageAndWait:[CSInMemoryStore new]
error:nil];
{
CSUnsafeDataTransaction *transaction = [CSCoreStore beginUnsafe];
XCTAssertNotNil(transaction);
XCTAssert([transaction isKindOfClass:[CSUnsafeDataTransaction class]]);
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];
}
#if TARGET_OS_IOS || TARGET_OS_WATCHOS || TARGET_OS_TV
- (void)test_ThatDataStacks_CanCreateCustomFetchedResultsControllers {
[CSCoreStore
setDefaultStack:[[CSDataStack alloc]
initWithModelName:@"Model"
bundle:[NSBundle bundleForClass:[self class]]
versionChain:nil]];
[CSCoreStore
addInMemoryStorageAndWait:[CSInMemoryStore new]
error:nil];
NSFetchedResultsController *controller =
[[CSCoreStore defaultStack]
createFetchedResultsControllerFrom:CSFromClass([TestEntity1 class])
sectionBy:[CSSectionBy keyPath:CSKeyPath(TestEntity1, testString)]
fetchClauses:@[CSWhereFormat(@"%K > %d", CSKeyPath(TestEntity1, testEntityID), 100),
CSOrderByKeys(CSSortAscending(CSKeyPath(TestEntity1, testString)), nil),
CSTweakRequest(^(NSFetchRequest *fetchRequest) { fetchRequest.fetchLimit = 10; })]];
XCTAssertNotNil(controller);
XCTAssertEqualObjects(controller.fetchRequest.entity.managedObjectClassName, [[TestEntity1 class] description]);
XCTAssertEqualObjects(controller.sectionNameKeyPath, CSKeyPath(TestEntity1, testString));
XCTAssertEqualObjects(controller.fetchRequest.predicate,
CSWhereFormat(@"%K > %d", CSKeyPath(TestEntity1, testEntityID), 100).predicate);
XCTAssertEqualObjects(controller.fetchRequest.sortDescriptors,
CSOrderByKeys(CSSortAscending(CSKeyPath(TestEntity1, testString)), nil).sortDescriptors);
XCTAssertEqual(controller.fetchRequest.fetchLimit, 10);
}
#endif
@end @end

View File

@@ -0,0 +1,91 @@
//
// ConvenienceTests.swift
// CoreStore
//
// Copyright © 2016 John Rommel Estropia
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in all
// copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
// SOFTWARE.
//
@testable
import CoreStore
// MARK: - ConvenienceTests
@available(OSX 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("%@ > %d", #keyPath(TestEntity1.testEntityID), 100),
OrderBy(.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(.ascending(#keyPath(TestEntity1.testString))).sortDescriptors
)
XCTAssertEqual(
controller.fetchRequest.predicate,
Where("%@ > %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("%@ > %d", #keyPath(TestEntity1.testEntityID), 100),
OrderBy(.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(.ascending(#keyPath(TestEntity1.testString))).sortDescriptors
)
XCTAssertEqual(
controller.fetchRequest.predicate,
Where("%@ > %d", #keyPath(TestEntity1.testEntityID), 100).predicate
)
XCTAssertEqual(controller.fetchRequest.fetchLimit, 10)
}
}
}
}

View File

@@ -0,0 +1,206 @@
//
// DynamicModelTests.swift
// CoreStore
//
// Copyright © 2017 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
class Animal: CoreStoreObject {
let species = Value.Required<String>("species", default: "Swift")
let master = Relationship.ToOne<Person>("master")
let color = Transformable.Optional<UIColor>("color")
}
class Dog: Animal {
let nickname = Value.Optional<String>("nickname")
let age = Value.Required<Int>("age", default: 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", default: "Mr.")
let name = Value.Required<String>(
"name",
customGetter: { (`self`, getValue) in
return "\(self.title.value) \(getValue())"
}
)
let pets = Relationship.ToManyUnordered<Animal>("pets", inverse: { $0.master })
}
// MARK: - DynamicModelTests
class DynamicModelTests: BaseTestDataTestCase {
func testDynamicModels_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 = Animal.keyPath({ $0.species })
XCTAssertEqual(k1, "species")
let k2 = Dog.keyPath({ $0.species })
XCTAssertEqual(k2, "species")
let k3 = Dog.keyPath({ $0.nickname })
XCTAssertEqual(k3, "nickname")
let updateDone = self.expectation(description: "update-done")
let fetchDone = self.expectation(description: "fetch-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, UIColor.yellow)
let dog = transaction.create(Into<Dog>())
XCTAssertEqual(dog.species.value, "Swift")
XCTAssertEqual(dog.nickname.value, nil)
XCTAssertEqual(dog.age.value, 1)
dog.species .= "Dog"
XCTAssertEqual(dog.species.value, "Dog")
dog.nickname .= "Spot"
XCTAssertEqual(dog.nickname.value, "Spot")
let person = transaction.create(Into<Person>())
XCTAssertTrue(person.pets.value.isEmpty)
person.name .= "John"
XCTAssertEqual(person.name.value, "Mr. John") // Custom getter
person.title .= "Sir"
XCTAssertEqual(person.name.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: {
updateDone.fulfill()
},
failure: { _ in
XCTFail()
}
)
stack.perform(
asynchronous: { (transaction) in
let p1 = Animal.where({ $0.species == "Sparrow" })
XCTAssertEqual(p1.predicate, NSPredicate(format: "%K == %@", "species", "Sparrow"))
let bird = transaction.fetchOne(From<Animal>(), p1)
XCTAssertNotNil(bird)
XCTAssertEqual(bird!.species.value, "Sparrow")
let p2 = Dog.where({ $0.nickname == "Spot" })
XCTAssertEqual(p2.predicate, NSPredicate(format: "%K == %@", "nickname", "Spot"))
let dog = transaction.fetchOne(From<Dog>(), p2)
XCTAssertNotNil(dog)
XCTAssertEqual(dog!.nickname.value, "Spot")
XCTAssertEqual(dog!.species.value, "Dog")
let person = transaction.fetchOne(From<Person>())
XCTAssertNotNil(person)
XCTAssertEqual(person!.pets.value.first, dog)
let p3 = Dog.where({ $0.age == 10 })
XCTAssertEqual(p3.predicate, NSPredicate(format: "%K == %d", "age", 10))
},
success: {
fetchDone.fulfill()
withExtendedLifetime(stack, {})
},
failure: { _ in
XCTFail()
}
)
self.waitAndCheckExpectations()
}
}
@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

@@ -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(NSError: 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

@@ -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,33 @@ 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 = from.applyToFetchRequest(request, context: dataStack.mainContext)
XCTAssertTrue(storesFound) 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 = self.expectLogger([.logWarning]) {
from.applyToFetchRequest(request, context: dataStack.mainContext) from.applyToFetchRequest(request, context: dataStack.mainContext)
} }
XCTAssertFalse(storesFound) XCTAssertFalse(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 +115,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 = from.applyToFetchRequest(request, context: dataStack.mainContext)
XCTAssertTrue(storesFound) 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, ["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 = from.applyToFetchRequest(request, context: dataStack.mainContext)
XCTAssertTrue(storesFound) 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, ["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 = self.expectLogger([.logWarning]) {
from.applyToFetchRequest(request, context: dataStack.mainContext) from.applyToFetchRequest(request, context: dataStack.mainContext)
} }
XCTAssertFalse(storesFound) XCTAssertFalse(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 = self.expectLogger([.logWarning]) {
from.applyToFetchRequest(request, context: dataStack.mainContext) from.applyToFetchRequest(request, context: dataStack.mainContext)
} }
XCTAssertFalse(storesFound) XCTAssertFalse(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 = self.expectLogger([.logWarning]) {
from.applyToFetchRequest(request, context: dataStack.mainContext) from.applyToFetchRequest(request, context: dataStack.mainContext)
} }
XCTAssertFalse(storesFound) XCTAssertFalse(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 = self.expectLogger([.logWarning]) {
from.applyToFetchRequest(request, context: dataStack.mainContext) from.applyToFetchRequest(request, context: dataStack.mainContext)
} }
XCTAssertFalse(storesFound) XCTAssertFalse(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 +225,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 = from.applyToFetchRequest(request, context: dataStack.mainContext)
XCTAssertTrue(storesFound) 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(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 = from.applyToFetchRequest(request, context: dataStack.mainContext)
XCTAssertTrue(storesFound) 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, ["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 = self.expectLogger([.logWarning]) {
from.applyToFetchRequest(request, context: dataStack.mainContext) from.applyToFetchRequest(request, context: dataStack.mainContext)
} }
XCTAssertFalse(storesFound) XCTAssertFalse(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 = from.applyToFetchRequest(request, context: dataStack.mainContext)
XCTAssertTrue(storesFound) 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<TestEntity2>("Config1") let from = From<TestEntity2>("Config1")
let request = NSFetchRequest() let request = CoreStoreFetchRequest()
let storesFound = self.expectLogger([.LogWarning]) { let storesFound = self.expectLogger([.logWarning]) {
from.applyToFetchRequest(request, context: dataStack.mainContext) from.applyToFetchRequest(request, context: dataStack.mainContext)
} }
XCTAssertFalse(storesFound) XCTAssertFalse(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 = self.expectLogger([.logWarning]) {
from.applyToFetchRequest(request, context: dataStack.mainContext) from.applyToFetchRequest(request, context: dataStack.mainContext)
} }
XCTAssertFalse(storesFound) XCTAssertFalse(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 +332,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 = from.applyToFetchRequest(request, context: dataStack.mainContext)
XCTAssertTrue(storesFound) 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, ["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 = from.applyToFetchRequest(request, context: dataStack.mainContext)
XCTAssertTrue(storesFound) 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, ["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 = self.expectLogger([.logWarning]) {
from.applyToFetchRequest(request, context: dataStack.mainContext) from.applyToFetchRequest(request, context: dataStack.mainContext)
} }
XCTAssertFalse(storesFound) XCTAssertFalse(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 = from.applyToFetchRequest(request, context: dataStack.mainContext)
XCTAssertTrue(storesFound) 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, ["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 = self.expectLogger([.logWarning]) {
from.applyToFetchRequest(request, context: dataStack.mainContext) from.applyToFetchRequest(request, context: dataStack.mainContext)
} }
XCTAssertFalse(storesFound) XCTAssertFalse(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 = from.applyToFetchRequest(request, context: dataStack.mainContext)
XCTAssertTrue(storesFound) 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, ["Config2"]) XCTAssertEqual(affectedConfigurations, ["Config2"])
} }
} }

View File

@@ -66,10 +66,10 @@ final class GroupByTests: BaseTestCase {
self.prepareStack { (dataStack) in self.prepareStack { (dataStack) in
let groupBy = GroupBy("testString") let groupBy = GroupBy(#keyPath(TestEntity1.testString))
let request = NSFetchRequest() let request = CoreStoreFetchRequest()
_ = From(TestEntity1).applyToFetchRequest(request, context: dataStack.mainContext) _ = 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

@@ -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

@@ -29,10 +29,9 @@ import XCTest
import CoreStore import CoreStore
#if os(iOS) || os(watchOS) || os(tvOS)
// MARK: - ListObserverTests // MARK: - ListObserverTests
@available(OSX 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(.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: "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,14 +67,14 @@ class ListObserverTests: BaseTestDataTestCase {
return events == 0 return events == 0
} }
) )
let didInsertSectionExpectation = self.expectationForNotification( let didInsertSectionExpectation = self.expectation(
"listMonitor:didInsertSection:toSectionIndex:", forNotification: "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.sectionInfoAtIndex(0),
"sectionIndex": 0 "sectionIndex": 0
@@ -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: "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: "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,9 +169,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(.ascending(#keyPath(TestEntity1.testBoolean)), .ascending(#keyPath(TestEntity1.testEntityID)))
) )
monitor.addObserver(observer) monitor.addObserver(observer)
@@ -185,13 +184,13 @@ class ListObserverTests: BaseTestDataTestCase {
var events = 0 var events = 0
let willChangeExpectation = self.expectationForNotification( let willChangeExpectation = self.expectation(
"listMonitorWillChange:", forNotification: "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
@@ -201,8 +200,8 @@ class ListObserverTests: BaseTestDataTestCase {
) )
for _ in 1 ... 2 { for _ in 1 ... 2 {
let didUpdateObjectExpectation = self.expectationForNotification( let didUpdateObjectExpectation = self.expectation(
"listMonitor:didUpdateObject:atIndexPath:", forNotification: "listMonitor:didUpdateObject:atIndexPath:",
object: observer, object: observer,
handler: { (note) -> Bool in handler: { (note) -> Bool in
@@ -211,7 +210,7 @@ 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"]
) )
@@ -220,27 +219,27 @@ class ListObserverTests: BaseTestDataTestCase {
switch object?.testEntityID { switch object?.testEntityID {
case NSNumber(integer: 101)?: case NSNumber(value: 101)?:
XCTAssertEqual(indexPath?.section, 1) XCTAssertEqual(indexPath?.index(atPosition: 0), 1)
XCTAssertEqual(indexPath?.row, 0) XCTAssertEqual(indexPath?.index(atPosition: 1), 0)
XCTAssertEqual(object?.testBoolean, NSNumber(bool: true)) XCTAssertEqual(object?.testBoolean, NSNumber(value: true))
XCTAssertEqual(object?.testNumber, NSNumber(integer: 11)) XCTAssertEqual(object?.testNumber, NSNumber(value: 11))
XCTAssertEqual(object?.testDecimal, NSDecimalNumber(string: "11")) XCTAssertEqual(object?.testDecimal, NSDecimalNumber(string: "11"))
XCTAssertEqual(object?.testString, "nil:TestEntity1:11") XCTAssertEqual(object?.testString, "nil:TestEntity1:11")
XCTAssertEqual(object?.testData, ("nil:TestEntity1:11" as NSString).dataUsingEncoding(NSUTF8StringEncoding)!) XCTAssertEqual(object?.testData, ("nil:TestEntity1:11" as NSString).data(using: String.Encoding.utf8.rawValue)!)
XCTAssertEqual(object?.testDate, self.dateFormatter.dateFromString("2000-01-11T00:00:00Z")!) XCTAssertEqual(object?.testDate, self.dateFormatter.date(from: "2000-01-11T00:00:00Z")!)
case NSNumber(integer: 102)?: case NSNumber(value: 102)?:
XCTAssertEqual(indexPath?.section, 0) XCTAssertEqual(indexPath?.index(atPosition: 0), 0)
XCTAssertEqual(indexPath?.row, 0) XCTAssertEqual(indexPath?.index(atPosition: 1), 0)
XCTAssertEqual(object?.testBoolean, NSNumber(bool: false)) XCTAssertEqual(object?.testBoolean, NSNumber(value: false))
XCTAssertEqual(object?.testNumber, NSNumber(integer: 22)) XCTAssertEqual(object?.testNumber, NSNumber(value: 22))
XCTAssertEqual(object?.testDecimal, NSDecimalNumber(string: "22")) XCTAssertEqual(object?.testDecimal, NSDecimalNumber(string: "22"))
XCTAssertEqual(object?.testString, "nil:TestEntity1:22") XCTAssertEqual(object?.testString, "nil:TestEntity1:22")
XCTAssertEqual(object?.testData, ("nil:TestEntity1:22" as NSString).dataUsingEncoding(NSUTF8StringEncoding)!) XCTAssertEqual(object?.testData, ("nil:TestEntity1:22" as NSString).data(using: String.Encoding.utf8.rawValue)!)
XCTAssertEqual(object?.testDate, self.dateFormatter.dateFromString("2000-01-22T00:00:00Z")!) XCTAssertEqual(object?.testDate, self.dateFormatter.date(from: "2000-01-22T00:00:00Z")!)
default: default:
XCTFail() XCTFail()
@@ -253,13 +252,13 @@ class ListObserverTests: BaseTestDataTestCase {
} }
) )
} }
let didChangeExpectation = self.expectationForNotification( let didChangeExpectation = self.expectation(
"listMonitorDidChange:", forNotification: "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 +266,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 = transaction.fetchOne(
object.testDecimal = NSDecimalNumber(string: "11") From<TestEntity1>(),
object.testString = "nil:TestEntity1:11" Where(#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 = transaction.fetchOne(
From<TestEntity1>(),
Where(#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 +323,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(.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: "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 +345,8 @@ class ListObserverTests: BaseTestDataTestCase {
return events == 0 return events == 0
} }
) )
let didMoveObjectExpectation = self.expectationForNotification( let didMoveObjectExpectation = self.expectation(
"listMonitor:didMoveObject:fromIndexPath:toIndexPath:", forNotification: "listMonitor:didMoveObject:fromIndexPath:toIndexPath:",
object: observer, object: observer,
handler: { (note) -> Bool in handler: { (note) -> Bool in
@@ -356,21 +355,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 +378,13 @@ class ListObserverTests: BaseTestDataTestCase {
return events == 1 return events == 1
} }
) )
let didChangeExpectation = self.expectationForNotification( let didChangeExpectation = self.expectation(
"listMonitorDidChange:", forNotification: "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 +392,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 = transaction.fetchOne(
} From<TestEntity1>(),
else { Where(#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 +431,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(.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: "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
@@ -456,8 +455,8 @@ class ListObserverTests: BaseTestDataTestCase {
) )
for _ in 1 ... 2 { for _ in 1 ... 2 {
let didUpdateObjectExpectation = self.expectationForNotification( let didUpdateObjectExpectation = self.expectation(
"listMonitor:didDeleteObject:fromIndexPath:", forNotification: "listMonitor:didDeleteObject:fromIndexPath:",
object: observer, object: observer,
handler: { (note) -> Bool in handler: { (note) -> Bool in
@@ -466,17 +465,17 @@ 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?.section, 0)
XCTAssert(indexPath?.row == 0 || indexPath?.row == 1) XCTAssert(indexPath?.index(atPosition: 1) == 0 || indexPath?.index(atPosition: 1) == 1)
let object = userInfo?["object"] as? TestEntity1 let object = userInfo?["object"] as? TestEntity1
XCTAssertEqual(object?.deleted, true) XCTAssertEqual(object?.isDeleted, true)
defer { defer {
@@ -486,8 +485,8 @@ class ListObserverTests: BaseTestDataTestCase {
} }
) )
} }
let didDeleteSectionExpectation = self.expectationForNotification( let didDeleteSectionExpectation = self.expectation(
"listMonitor:didDeleteSection:fromSectionIndex:", forNotification: "listMonitor:didDeleteSection:fromSectionIndex:",
object: observer, object: observer,
handler: { (note) -> Bool in handler: { (note) -> Bool in
@@ -496,16 +495,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 +513,13 @@ class ListObserverTests: BaseTestDataTestCase {
return events == 3 return events == 3
} }
) )
let didChangeExpectation = self.expectationForNotification( let didChangeExpectation = self.expectation(
"listMonitorDidChange:", forNotification: "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 +527,26 @@ 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 { transaction.deleteAll(
From<TestEntity1>(),
case .Success(let hasChanges): Where(#keyPath(TestEntity1.testBoolean), isEqualTo: false)
XCTAssertTrue(hasChanges) )
saveExpectation.fulfill() return transaction.hasChanges
},
case .Failure: success: { (hasChanges) in
XCTFail()
} XCTAssertTrue(hasChanges)
saveExpectation.fulfill()
},
failure: { _ in
XCTFail()
} }
} )
self.waitAndCheckExpectations() self.waitAndCheckExpectations()
} }
} }
@@ -556,43 +555,44 @@ class ListObserverTests: BaseTestDataTestCase {
// MARK: TestListObserver // MARK: TestListObserver
@available(OSX 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 +601,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 +613,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 +625,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 +638,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 +654,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 +666,10 @@ class TestListObserver: ListSectionObserver {
) )
} }
func listMonitor(monitor: ListMonitor<TestEntity1>, didDeleteSection sectionInfo: NSFetchedResultsSectionInfo, fromSectionIndex sectionIndex: Int) { func listMonitor(_ monitor: ListMonitor<TestEntity1>, didDeleteSection sectionInfo: NSFetchedResultsSectionInfo, fromSectionIndex sectionIndex: Int) {
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 +678,3 @@ class TestListObserver: ListSectionObserver {
) )
} }
} }
#endif

View File

@@ -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

@@ -29,10 +29,9 @@ import XCTest
import CoreStore import CoreStore
#if os(iOS) || os(watchOS) || os(tvOS)
// MARK: - ObjectObserverTests // MARK: - ObjectObserverTests
@available(OSX 10.12, *)
class ObjectObserverTests: BaseTestDataTestCase { class ObjectObserverTests: BaseTestDataTestCase {
@objc @objc
@@ -43,8 +42,8 @@ class ObjectObserverTests: BaseTestDataTestCase {
self.prepareTestDataForStack(stack) self.prepareTestDataForStack(stack)
guard let object = stack.fetchOne( guard let object = stack.fetchOne(
From(TestEntity1), From<TestEntity1>(),
Where("testEntityID", isEqualTo: 101)) else { Where(#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: "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: "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()
} }
} }
@@ -140,8 +139,8 @@ class ObjectObserverTests: BaseTestDataTestCase {
self.prepareTestDataForStack(stack) self.prepareTestDataForStack(stack)
guard let object = stack.fetchOne( guard let object = stack.fetchOne(
From(TestEntity1), From<TestEntity1>(),
Where("testEntityID", isEqualTo: 101)) else { Where(#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: "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(OSX 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<KeyPath>) {
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

@@ -39,7 +39,7 @@ final class OrderByTests: XCTestCase {
do { do {
let orderBy = OrderBy() let orderBy = OrderBy()
XCTAssertEqual(orderBy, OrderBy([] as [NSSortDescriptor])) XCTAssertEqual(orderBy, OrderBy([NSSortDescriptor]()))
XCTAssertNotEqual(orderBy, OrderBy(NSSortDescriptor(key: "key", ascending: false))) XCTAssertNotEqual(orderBy, OrderBy(NSSortDescriptor(key: "key", ascending: false)))
XCTAssertTrue(orderBy.sortDescriptors.isEmpty) XCTAssertTrue(orderBy.sortDescriptors.isEmpty)
} }
@@ -48,9 +48,9 @@ final class OrderByTests: XCTestCase {
let sortDescriptor = NSSortDescriptor(key: "key1", ascending: true) let sortDescriptor = NSSortDescriptor(key: "key1", ascending: true)
let orderBy = OrderBy(sortDescriptor) let orderBy = OrderBy(sortDescriptor)
XCTAssertEqual(orderBy, OrderBy(sortDescriptor)) XCTAssertEqual(orderBy, OrderBy(sortDescriptor))
XCTAssertEqual(orderBy, OrderBy(.Ascending("key1"))) XCTAssertEqual(orderBy, OrderBy(.ascending("key1")))
XCTAssertNotEqual(orderBy, OrderBy(.Ascending("key2"))) XCTAssertNotEqual(orderBy, OrderBy(.ascending("key2")))
XCTAssertNotEqual(orderBy, OrderBy(.Descending("key1"))) XCTAssertNotEqual(orderBy, OrderBy(.descending("key1")))
XCTAssertNotEqual(orderBy, OrderBy(NSSortDescriptor(key: "key1", ascending: false))) XCTAssertNotEqual(orderBy, OrderBy(NSSortDescriptor(key: "key1", ascending: false)))
XCTAssertEqual(orderBy, OrderBy([sortDescriptor])) XCTAssertEqual(orderBy, OrderBy([sortDescriptor]))
XCTAssertEqual(orderBy.sortDescriptors, [sortDescriptor]) XCTAssertEqual(orderBy.sortDescriptors, [sortDescriptor])
@@ -63,7 +63,7 @@ final class OrderByTests: XCTestCase {
] ]
let orderBy = OrderBy(sortDescriptors) let orderBy = OrderBy(sortDescriptors)
XCTAssertEqual(orderBy, OrderBy(sortDescriptors)) XCTAssertEqual(orderBy, OrderBy(sortDescriptors))
XCTAssertEqual(orderBy, OrderBy(.Ascending("key1"), .Descending("key2"))) XCTAssertEqual(orderBy, OrderBy(.ascending("key1"), .descending("key2")))
XCTAssertNotEqual( XCTAssertNotEqual(
orderBy, orderBy,
OrderBy( OrderBy(
@@ -73,30 +73,30 @@ final class OrderByTests: XCTestCase {
] ]
) )
) )
XCTAssertNotEqual(orderBy, OrderBy(.Ascending("key1"), .Ascending("key2"))) XCTAssertNotEqual(orderBy, OrderBy(.ascending("key1"), .ascending("key2")))
XCTAssertNotEqual(orderBy, OrderBy(.Ascending("key1"), .Descending("key3"))) XCTAssertNotEqual(orderBy, OrderBy(.ascending("key1"), .descending("key3")))
XCTAssertEqual(orderBy.sortDescriptors, sortDescriptors) XCTAssertEqual(orderBy.sortDescriptors, sortDescriptors)
} }
do { do {
let orderBy = OrderBy(.Ascending("key1")) let orderBy = OrderBy(.ascending("key1"))
let sortDescriptor = NSSortDescriptor(key: "key1", ascending: true) let sortDescriptor = NSSortDescriptor(key: "key1", ascending: true)
XCTAssertEqual(orderBy, OrderBy(sortDescriptor)) XCTAssertEqual(orderBy, OrderBy(sortDescriptor))
XCTAssertEqual(orderBy, OrderBy(.Ascending("key1"))) XCTAssertEqual(orderBy, OrderBy(.ascending("key1")))
XCTAssertNotEqual(orderBy, OrderBy(.Descending("key1"))) XCTAssertNotEqual(orderBy, OrderBy(.descending("key1")))
XCTAssertNotEqual(orderBy, OrderBy(.Ascending("key2"))) XCTAssertNotEqual(orderBy, OrderBy(.ascending("key2")))
XCTAssertEqual(orderBy, OrderBy([sortDescriptor])) XCTAssertEqual(orderBy, OrderBy([sortDescriptor]))
XCTAssertEqual(orderBy.sortDescriptors, [sortDescriptor]) XCTAssertEqual(orderBy.sortDescriptors, [sortDescriptor])
} }
do { do {
let orderBy = OrderBy(.Ascending("key1"), .Descending("key2")) let orderBy = OrderBy(.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(sortDescriptors))
XCTAssertEqual(orderBy, OrderBy(.Ascending("key1"), .Descending("key2"))) XCTAssertEqual(orderBy, OrderBy(.ascending("key1"), .descending("key2")))
XCTAssertNotEqual( XCTAssertNotEqual(
orderBy, orderBy,
OrderBy( OrderBy(
@@ -106,20 +106,20 @@ final class OrderByTests: XCTestCase {
] ]
) )
) )
XCTAssertNotEqual(orderBy, OrderBy(.Ascending("key1"), .Ascending("key2"))) XCTAssertNotEqual(orderBy, OrderBy(.ascending("key1"), .ascending("key2")))
XCTAssertNotEqual(orderBy, OrderBy(.Ascending("key1"), .Descending("key3"))) XCTAssertNotEqual(orderBy, OrderBy(.ascending("key1"), .descending("key3")))
XCTAssertEqual(orderBy.sortDescriptors, sortDescriptors) XCTAssertEqual(orderBy.sortDescriptors, sortDescriptors)
} }
do { do {
let sortKeys: [SortKey] = [.Ascending("key1"), .Descending("key2")] let sortKeys: [SortKey] = [.ascending("key1"), .descending("key2")]
let orderBy = OrderBy(sortKeys) let orderBy = OrderBy(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(sortDescriptors))
XCTAssertEqual(orderBy, OrderBy(.Ascending("key1"), .Descending("key2"))) XCTAssertEqual(orderBy, OrderBy(.ascending("key1"), .descending("key2")))
XCTAssertNotEqual( XCTAssertNotEqual(
orderBy, orderBy,
OrderBy( OrderBy(
@@ -129,8 +129,8 @@ final class OrderByTests: XCTestCase {
] ]
) )
) )
XCTAssertNotEqual(orderBy, OrderBy(.Ascending("key1"), .Ascending("key2"))) XCTAssertNotEqual(orderBy, OrderBy(.ascending("key1"), .ascending("key2")))
XCTAssertNotEqual(orderBy, OrderBy(.Ascending("key1"), .Descending("key3"))) XCTAssertNotEqual(orderBy, OrderBy(.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(.ascending("key1"))
let orderBy2 = OrderBy(.Descending("key2")) let orderBy2 = OrderBy(.descending("key2"))
let orderBy3 = OrderBy(.Ascending("key3")) let orderBy3 = OrderBy(.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(.ascending("key1"), .descending("key2"), .ascending("key3")))
XCTAssertEqual(plusOrderBy, OrderBy(.Ascending("key1")) + OrderBy(.Descending("key2"), .Ascending("key3"))) XCTAssertEqual(plusOrderBy, OrderBy(.ascending("key1")) + OrderBy(.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(.ascending("key1"), .descending("key2")))
XCTAssertEqual(plusOrderBy, OrderBy(.Ascending("key1")) + OrderBy(.Descending("key2"))) XCTAssertEqual(plusOrderBy, OrderBy(.ascending("key1")) + OrderBy(.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(.ascending("key1"), .descending("key2"), .ascending("key3")))
XCTAssertEqual(plusOrderBy, OrderBy(.Ascending("key1"), .Descending("key2")) + OrderBy(.Ascending("key3"))) XCTAssertEqual(plusOrderBy, OrderBy(.ascending("key1"), .descending("key2")) + OrderBy(.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(.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

@@ -29,10 +29,9 @@ import XCTest
import CoreStore import CoreStore
#if os(iOS) || os(watchOS) || os(tvOS)
//MARK: - SectionByTests //MARK: - SectionByTests
@available(OSX 10.12, *)
final class SectionByTests: XCTestCase { final class SectionByTests: XCTestCase {
@objc @objc
@@ -42,16 +41,14 @@ final class SectionByTests: XCTestCase {
let sectionBy = SectionBy("key") let sectionBy = SectionBy("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("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

@@ -39,17 +39,17 @@ final class SelectTests: XCTestCase {
do { do {
let term: SelectTerm = "attribute" let term: SelectTerm = "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.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.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.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.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.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.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.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.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.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.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.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.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.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,9 +393,9 @@ final class SelectTests: XCTestCase {
@objc @objc
dynamic func test_ThatSelectClauses_ConfigureCorrectly() { dynamic func test_ThatSelectClauses_ConfigureCorrectly() {
let term1 = SelectTerm.Attribute("attribute1") let term1 = SelectTerm.attribute("attribute1")
let term2 = SelectTerm.Attribute("attribute2") let term2 = SelectTerm.attribute("attribute2")
let term3 = SelectTerm.Attribute("attribute3") let term3 = SelectTerm.attribute("attribute3")
do { do {
let select = Select<Int>(term1, term2, term3) let select = Select<Int>(term1, term2, term3)

View File

@@ -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", modelName: "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)
@@ -77,7 +85,7 @@ class SetupTests: BaseTestCase {
let stack = DataStack( let stack = DataStack(
modelName: "Model", modelName: "Model",
bundle: NSBundle(forClass: self.dynamicType) bundle: Bundle(for: type(of: self))
) )
do { do {
@@ -132,7 +140,7 @@ class SetupTests: BaseTestCase {
let stack = DataStack( let stack = DataStack(
modelName: "Model", modelName: "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(
modelName: "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(
modelName: "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", modelName: "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(
modelName: "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(
modelName: "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

@@ -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,120 @@ 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) 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 = NSURL(fileURLWithPath: NSTemporaryDirectory())
.URLByAppendingPathComponent(NSUUID().UUIDString, isDirectory: false) .appendingPathComponent(NSUUID().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) 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) 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) 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) 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

@@ -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

@@ -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

@@ -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

@@ -29,6 +29,25 @@ import XCTest
import CoreStore import CoreStore
// MARK: - XCTAssertAllEqual
private func XCTAssertAllEqual(_ whereClauses: Where...) {
XCTAssertAllEqual(whereClauses)
}
private func XCTAssertAllEqual(_ whereClauses: [Where]) {
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 {
@@ -87,6 +106,123 @@ final class WhereTests: XCTestCase {
} }
} }
@objc
dynamic func test_ThatWhereClauses_BridgeArgumentsCorrectly() {
do {
let value: Int = 100
XCTAssertAllEqual(
Where("%K == %d", "key", value),
Where("%K == %d", "key", value as AnyObject),
Where("%K == %d", "key", NSNumber(value: value)),
Where("%K == %@", "key", value),
Where("%K == %@", "key", value as AnyObject),
Where("%K == %@", "key", NSNumber(value: value)),
Where("key", isEqualTo: value),
Where("key", isEqualTo: NSNumber(value: value))
)
}
do {
let value = NSNumber(value: 100)
XCTAssertAllEqual(
Where("%K == %d", "key", value),
Where("%K == %d", "key", value as AnyObject),
Where("%K == %d", "key", value.intValue),
Where("%K == %@", "key", value),
Where("%K == %@", "key", value as AnyObject),
Where("%K == %@", "key", value.intValue),
Where("key", isEqualTo: value),
Where("key", isEqualTo: value.intValue)
)
}
do {
let value: Int64 = Int64.max
XCTAssertAllEqual(
Where("%K == %d", "key", value),
Where("%K == %d", "key", value as AnyObject),
Where("%K == %d", "key", NSNumber(value: value)),
Where("%K == %@", "key", value),
Where("%K == %@", "key", value as AnyObject),
Where("%K == %@", "key", NSNumber(value: value)),
Where("key", isEqualTo: value),
Where("key", isEqualTo: NSNumber(value: value))
)
}
do {
let value = NSNumber(value: Int64.max)
XCTAssertAllEqual(
Where("%K == %d", "key", value),
Where("%K == %d", "key", value as AnyObject),
Where("%K == %d", "key", value.int64Value),
Where("%K == %@", "key", value),
Where("%K == %@", "key", value as AnyObject),
Where("%K == %@", "key", value.int64Value),
Where("key", isEqualTo: value),
Where("key", isEqualTo: value.int64Value)
)
}
do {
let value: String = "value"
XCTAssertAllEqual(
Where("%K == %s", "key", value),
Where("%K == %s", "key", value as AnyObject),
Where("%K == %s", "key", NSString(string: value)),
Where("%K == %@", "key", value),
Where("%K == %@", "key", value as AnyObject),
Where("%K == %@", "key", NSString(string: value)),
Where("key", isEqualTo: value),
Where("key", isEqualTo: value as NSString),
Where("key", isEqualTo: NSString(string: value))
)
}
do {
let value = NSString(string: "value")
XCTAssertAllEqual(
Where("%K == %s", "key", value),
Where("%K == %s", "key", value as String),
Where("%K == %s", "key", value as String as AnyObject),
Where("%K == %@", "key", value),
Where("%K == %@", "key", value as String),
Where("%K == %@", "key", value as String as AnyObject),
Where("key", isEqualTo: value),
Where("key", isEqualTo: value as String),
Where("key", isEqualTo: value as String as NSString)
)
}
do {
let value: [Int] = [100, 200]
XCTAssertAllEqual(
Where("%K IN %@", "key", value),
Where("%K IN %@", "key", value as AnyObject),
Where("%K IN %@", "key", value as [AnyObject]),
Where("%K IN %@", "key", value as NSArray),
Where("%K IN %@", "key", NSArray(array: value)),
Where("%K IN %@", "key", value as AnyObject as! NSArray),
Where("key", isMemberOf: value)
)
}
do {
let value: [Int64] = [Int64.min, 100, Int64.max]
XCTAssertAllEqual(
Where("%K IN %@", "key", value),
Where("%K IN %@", "key", value as AnyObject),
Where("%K IN %@", "key", value as [AnyObject]),
Where("%K IN %@", "key", value as NSArray),
Where("%K IN %@", "key", NSArray(array: value)),
Where("%K IN %@", "key", value as AnyObject as! NSArray),
Where("key", isMemberOf: value)
)
}
}
@objc @objc
dynamic func test_ThatWhereClauseOperations_ComputeCorrectly() { dynamic func test_ThatWhereClauseOperations_ComputeCorrectly() {
@@ -98,7 +234,7 @@ final class WhereTests: XCTestCase {
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 +244,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
@@ -124,10 +260,10 @@ final class WhereTests: XCTestCase {
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
@@ -142,7 +278,7 @@ final class WhereTests: XCTestCase {
dynamic func test_ThatWhereClauses_ApplyToFetchRequestsCorrectly() { dynamic func test_ThatWhereClauses_ApplyToFetchRequestsCorrectly() {
let whereClause = Where("key", isEqualTo: "value") let whereClause = Where("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

@@ -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",
majorVersion: 1, minor: 2
)
],
exclude: ["Carthage", "CoreStoreDemo", "Sources/libA/images"] exclude: ["Carthage", "CoreStoreDemo", "Sources/libA/images"]
) )

265
README.md
View File

@@ -17,11 +17,10 @@ Unleashing the real power of Core Data with the elegance and safety of Swift
<a href="https://twitter.com/JohnEstropia"><img alt="Reach me on Twitter!" src="https://img.shields.io/badge/twitter-%40JohnEstropia-3498db.svg" /></a> <a href="https://twitter.com/JohnEstropia"><img alt="Reach me on Twitter!" src="https://img.shields.io/badge/twitter-%40JohnEstropia-3498db.svg" /></a>
<br /> <br />
</p> </p>
* Swift 2.2 (Xcode 7.3)
* iOS 7+ / macOS 10.10+ / watchOS 2.0+ / tvOS 9.0+
* **New in CoreStore 2.0:** Objective-C support! All CoreStore types now have their corresponding Objective-C "bridging classes". Perfect for projects transitioning from Objective-C to Swift!
Upgrading from CoreStore 1.x to 2.x? Check out the [new features](#new-in-corestore-20) and make sure to read the [Migration guide](#upgrading-from-1xx-to-2xx). * **Swift 3.0.1:** iOS 8+ / macOS 10.10+ / watchOS 2.0+ / tvOS 9.0+
Upgrading from CoreStore 2.x to 3.x? Check out the [new features](#features) and make sure to read the [Migration guide](#upgrading-from-2xx-to-3xx).
## Why use CoreStore? ## Why use CoreStore?
@@ -40,12 +39,10 @@ CoreStore was (and is) heavily shaped by real-world needs of developing data-dep
- **Efficient importing utilities.** Map your entities once with their corresponding import source (JSON for example), and importing from *transactions* becomes elegant. Uniquing is also done with an efficient find-and-replace algorithm. *(See [Importing data](#importing-data))* - **Efficient importing utilities.** Map your entities once with their corresponding import source (JSON for example), and importing from *transactions* becomes elegant. Uniquing is also done with an efficient find-and-replace algorithm. *(See [Importing data](#importing-data))*
- **Tight design around Swifts code elegance and type safety.** CoreStore fully utilizes Swift's community-driven language features. - **Tight design around Swifts code elegance and type safety.** CoreStore fully utilizes Swift's community-driven language features.
- **Full Documentation.** No magic here; all public classes, functions, properties, etc. have detailed *Apple Docs*. This *README* also introduces a lot of concepts and explains a lot of CoreStore's behavior. - **Full Documentation.** No magic here; all public classes, functions, properties, etc. have detailed *Apple Docs*. This *README* also introduces a lot of concepts and explains a lot of CoreStore's behavior.
### New in CoreStore 2.0
- **Informative (and pretty) logs.** All CoreStore and Core Data-related types now have very informative and pretty print outputs! *(See [Logging and error reporting](#logging-and-error-reporting))* - **Informative (and pretty) logs.** All CoreStore and Core Data-related types now have very informative and pretty print outputs! *(See [Logging and error reporting](#logging-and-error-reporting))*
- **Objective-C support!** Is your project transitioning from Objective-C to Swift but still can't quite fully convert some huge classes to Swift yet? CoreStore 2.0 is the answer to the ever-increasing Swift adoption. While still written in pure Swift, all CoreStore types now have their corresponding Objective-C-visible "bridging classes". *(See [Objective-C support](#objective-c-support))* - **Objective-C support!** Is your project transitioning from Objective-C to Swift but still can't quite fully convert some huge classes to Swift yet? CoreStore adjusts to the ever-increasing Swift adoption. While still written in pure Swift, all CoreStore types have their corresponding Objective-C-visible "bridging classes". *(See [Objective-C support](#objective-c-support))*
- **iCloud storage (beta) support.** CoreStore now allows creation of iCloud persistent stores, as well as observing of iCloud-related events through the `ICloudStoreObserver`. *(See [iCloud storage](#icloud-storages))* - **iCloud storage (beta) support.** CoreStore allows creation of iCloud persistent stores, as well as observing of iCloud-related events through the `ICloudStoreObserver`. *(See [iCloud storage](#icloud-storages))*
- **More extensive Unit Tests.** Extending CoreStore is now safer without having to worry about breaking old behavior. - **More extensive Unit Tests.** Extending CoreStore is safe without having to worry about breaking old behavior.
*Have ideas that may benefit other Core Data users? [Feature Request](https://github.com/JohnEstropia/CoreStore/issues)s are welcome!* *Have ideas that may benefit other Core Data users? [Feature Request](https://github.com/JohnEstropia/CoreStore/issues)s are welcome!*
@@ -88,6 +85,7 @@ CoreStore was (and is) heavily shaped by real-world needs of developing data-dep
- [Roadmap](#roadmap) - [Roadmap](#roadmap)
- [Installation](#installation) - [Installation](#installation)
- [Changesets](#changesets) - [Changesets](#changesets)
- [Upgrading from 2.x.x to 3.x.x](#upgrading-from-2xx-to-3xx)
- [Upgrading from 1.x.x to 2.x.x](#upgrading-from-1xx-to-2xx) - [Upgrading from 1.x.x to 2.x.x](#upgrading-from-1xx-to-2xx)
- [Contact](#contact) - [Contact](#contact)
- [Who uses CoreStore?](#who-uses-corestore) - [Who uses CoreStore?](#who-uses-corestore)
@@ -118,14 +116,14 @@ CoreStore.addStorage(
Starting transactions: Starting transactions:
```swift ```swift
CoreStore.beginAsynchronous { (transaction) -> Void in CoreStore.beginAsynchronous { (transaction) -> Void in
let person = transaction.create(Into(MyPersonEntity)) let person = transaction.create(Into<MyPersonEntity>())
person.name = "John Smith" person.name = "John Smith"
person.age = 42 person.age = 42
transaction.commit { (result) -> Void in transaction.commit { (result) -> Void in
switch result { switch result {
case .Success(let hasChanges): print("success!") case .success(let hasChanges): print("success!")
case .Failure(let error): print(error) case .failure(let error): print(error)
} }
} }
} }
@@ -133,15 +131,15 @@ CoreStore.beginAsynchronous { (transaction) -> Void in
Fetching objects (simple): Fetching objects (simple):
```swift ```swift
let people = CoreStore.fetchAll(From(MyPersonEntity)) let people = CoreStore.fetchAll(From<MyPersonEntity>())
``` ```
Fetching objects (complex): Fetching objects (complex):
```swift ```swift
let people = CoreStore.fetchAll( let people = CoreStore.fetchAll(
From(MyPersonEntity), From<MyPersonEntity>(),
Where("age > 30"), Where("age > 30"),
OrderBy(.Ascending("name"), .Descending("age")), OrderBy(.ascending("name"), .descending("age")),
Tweak { (fetchRequest) -> Void in Tweak { (fetchRequest) -> Void in
fetchRequest.includesPendingChanges = false fetchRequest.includesPendingChanges = false
} }
@@ -151,8 +149,8 @@ let people = CoreStore.fetchAll(
Querying values: Querying values:
```swift ```swift
let maxAge = CoreStore.queryValue( let maxAge = CoreStore.queryValue(
From(MyPersonEntity), From<MyPersonEntity>(),
Select<Int>(.Maximum("age")) Select<Int>(.maximum("age"))
) )
``` ```
@@ -206,13 +204,13 @@ let migrationProgress = dataStack.addStorage(
SQLiteStore( SQLiteStore(
fileURL: sqliteFileURL, // set the target file URL for the sqlite file fileURL: sqliteFileURL, // set the target file URL for the sqlite file
configuration: "Config2", // use entities from the "Config2" configuration in the .xcdatamodeld file configuration: "Config2", // use entities from the "Config2" configuration in the .xcdatamodeld file
localStorageOptions: .RecreateStoreOnModelMismatch // if migration paths cannot be resolved, recreate the sqlite file localStorageOptions: .recreateStoreOnModelMismatch // if migration paths cannot be resolved, recreate the sqlite file
), ),
completion: { (result) -> Void in completion: { (result) -> Void in
switch result { switch result {
case .Success(let storage): case .success(let storage):
print("Successfully added sqlite store: \(storage)" print("Successfully added sqlite store: \(storage)"
case .Failure(let error): case .failure(let error):
print("Failed adding sqlite store with error: \(error)" print("Failed adding sqlite store with error: \(error)"
} }
} }
@@ -231,7 +229,7 @@ class MyViewController: UIViewController {
override func viewDidLoad() { override func viewDidLoad() {
super.viewDidLoad() super.viewDidLoad()
do { do {
try self.dataStack.addStorageAndWait(SQLiteStore) try self.dataStack.addStorageAndWait(SQLiteStore.self)
} }
catch { // ... catch { // ...
} }
@@ -249,7 +247,7 @@ class MyViewController: UIViewController {
override func viewDidLoad() { override func viewDidLoad() {
super.viewDidLoad() super.viewDidLoad()
do { do {
try CoreStore.addStorageAndWait(SQLiteStore) try CoreStore.addStorageAndWait(SQLiteStore.self)
} }
catch { // ... catch { // ...
} }
@@ -272,10 +270,6 @@ try CoreStore.addStorageAndWait(
) )
) )
``` ```
`InMemoryStore`s also implement the `DefaultInitializableStore` sugar protocol which tells CoreStore that this store can initialize without any arguments (`init()`). This lets us provide just the type instead of an instance:
```swift
try CoreStore.addStorageAndWait(InMemoryStore)
```
### Local Store ### Local Store
The most common `StorageInterface` you will probably use is the `SQLiteStore`, which saves data in a local SQLite file. The most common `StorageInterface` you will probably use is the `SQLiteStore`, which saves data in a local SQLite file.
@@ -285,16 +279,16 @@ let migrationProgress = CoreStore.addStorage(
fileName: "MyStore.sqlite", fileName: "MyStore.sqlite",
configuration: "Config2", // optional. Use entities from the "Config2" configuration in the .xcdatamodeld file configuration: "Config2", // optional. Use entities from the "Config2" configuration in the .xcdatamodeld file
mappingModelBundles: [NSBundle.mainBundle()], // optional. The bundles that contain required .xcmappingmodel files, if any mappingModelBundles: [NSBundle.mainBundle()], // optional. The bundles that contain required .xcmappingmodel files, if any
localStorageOptions: .RecreateStoreOnModelMismatch // optional. Provides settings that tells the DataStack how to setup the persistent store localStorageOptions: .recreateStoreOnModelMismatch // optional. Provides settings that tells the DataStack how to setup the persistent store
), ),
completion: { /* ... */ } completion: { /* ... */ }
) )
``` ```
Refer to the *SQLiteStore.swift* source documentation for detailed explanations for each of the default values. Refer to the *SQLiteStore.swift* source documentation for detailed explanations for each of the default values.
CoreStore can decide the default values for these properties, so `SQLiteStore`s also implement the `DefaultInitializableStore` sugar protocol which lets us write: CoreStore can decide the default values for these properties, so `SQLiteStore`s can be initialized with default arguments:
```swift ```swift
try CoreStore.addStorageAndWait(SQLiteStore) try CoreStore.addStorageAndWait(SQLiteStore())
``` ```
or or
```swift ```swift
@@ -307,8 +301,8 @@ public protocol LocalStorage: StorageInterface {
var fileURL: NSURL { get } var fileURL: NSURL { get }
var mappingModelBundles: [NSBundle] { get } var mappingModelBundles: [NSBundle] { get }
var localStorageOptions: LocalStorageOptions { get } var localStorageOptions: LocalStorageOptions { get }
func storeOptionsForOptions(options: LocalStorageOptions) -> [String: AnyObject]? func dictionary(forOptions: LocalStorageOptions) -> [String: AnyObject]?
func eraseStorageAndWait(soureModel soureModel: NSManagedObjectModel) throws func cs_eraseStorageAndWait(metadata: [String: Any], soureModelHint: NSManagedObjectModel?) throws
} }
``` ```
If you have custom `NSIncrementalStore` or `NSAtomicStore` subclasses, you can implement this protocol and use it similarly to `SQLiteStore`. If you have custom `NSIncrementalStore` or `NSAtomicStore` subclasses, you can implement this protocol and use it similarly to `SQLiteStore`.
@@ -324,7 +318,7 @@ guard let storage = ICloudStore(
ubiquitousContainerID: "iCloud.com.mycompany.myapp.containername", // optional. The container if your app has multiple ubiquity container identifiers in its entitlements ubiquitousContainerID: "iCloud.com.mycompany.myapp.containername", // optional. The container if your app has multiple ubiquity container identifiers in its entitlements
ubiquitousPeerToken: "9614d658014f4151a95d8048fb717cf0", // optional. A per-application salt to allow multiple apps on the same device to share a Core Data store integrated with iCloud ubiquitousPeerToken: "9614d658014f4151a95d8048fb717cf0", // optional. A per-application salt to allow multiple apps on the same device to share a Core Data store integrated with iCloud
configuration: "Config1", // optional. Use entities from the "Config1" configuration in the .xcdatamodeld file configuration: "Config1", // optional. Use entities from the "Config1" configuration in the .xcdatamodeld file
cloudStorageOptions: .RecreateLocalStoreOnModelMismatch // optional. Provides settings that tells the DataStack how to setup the persistent store cloudStorageOptions: .recreateLocalStoreOnModelMismatch // optional. Provides settings that tells the DataStack how to setup the persistent store
) else { ) else {
// The iCloud container could not be located or if iCloud is not available on the device. // The iCloud container could not be located or if iCloud is not available on the device.
// Handle appropriately // Handle appropriately
@@ -334,8 +328,8 @@ CoreStore.addStorage(,
storage, storage,
completion: { result in completion: { result in
switch result { switch result {
case .Success(let storage): // ... case .success(let storage): // ...
case .Failure(let error): // ... case .failure(let error): // ...
} }
} }
) )
@@ -365,8 +359,8 @@ CoreStore.addStorage(,
storage, storage,
completion: { result in completion: { result in
switch result { switch result {
case .Success(let storage): // ... You may also call storage.addObserver(_:) here case .success(let storage): // ... You may also call storage.addObserver(_:) here
case .Failure(let error): // ... case .failure(let error): // ...
} }
} }
) )
@@ -375,12 +369,12 @@ The `ICloudStore` only keeps weak references of the registered observers. You ma
## Migrations ## Migrations
We have seen `addStorageAndWait(...)` used to initialize our persistent store. As the method name's "AndWait" suffix suggests though, this method blocks so it should not do long tasks such as store migrations. In fact CoreStore will only attempt a synchronous **lightweight** migration if you explicitly provide the `.AllowSynchronousLightweightMigration` option: We have seen `addStorageAndWait(...)` used to initialize our persistent store. As the method name's "AndWait" suffix suggests though, this method blocks so it should not do long tasks such as store migrations. In fact CoreStore will only attempt a synchronous **lightweight** migration if you explicitly provide the `.allowSynchronousLightweightMigration` option:
```swift ```swift
try dataStack.addStorageAndWait( try dataStack.addStorageAndWait(
SQLiteStore( SQLiteStore(
fileURL: sqliteFileURL, fileURL: sqliteFileURL,
localStorageOptions: .AllowSynchronousLightweightMigration localStorageOptions: .allowSynchronousLightweightMigration
) )
} }
``` ```
@@ -388,16 +382,16 @@ if you do so, any model mismatch will be thrown as an error.
In general though, if migrations are expected the asynchronous variant `addStorage(_:completion:)` method is recommended instead: In general though, if migrations are expected the asynchronous variant `addStorage(_:completion:)` method is recommended instead:
```swift ```swift
let migrationProgress: NSProgress? = try dataStack.addStorage( let migrationProgress: Progress? = try dataStack.addStorage(
SQLiteStore( SQLiteStore(
fileName: "MyStore.sqlite", fileName: "MyStore.sqlite",
configuration: "Config2" configuration: "Config2"
), ),
completion: { (result) -> Void in completion: { (result) -> Void in
switch result { switch result {
case .Success(let storage): case .success(let storage):
print("Successfully added sqlite store: \(storage)") print("Successfully added sqlite store: \(storage)")
case .Failure(let error): case .failure(let error):
print("Failed adding sqlite store with error: \(error)") print("Failed adding sqlite store with error: \(error)")
} }
} }
@@ -405,7 +399,7 @@ let migrationProgress: NSProgress? = try dataStack.addStorage(
``` ```
The `completion` block reports a `SetupResult` that indicates success or failure. The `completion` block reports a `SetupResult` that indicates success or failure.
Notice that this method also returns an optional `NSProgress`. If `nil`, no migrations are needed, thus progress reporting is unnecessary as well. If not `nil`, you can use this to track migration progress by using standard KVO on the `"fractionCompleted"` key, or by using a closure-based utility exposed in *NSProgress+Convenience.swift*: Notice that this method also returns an optional `Progress`. If `nil`, no migrations are needed, thus progress reporting is unnecessary as well. If not `nil`, you can use this to track migration progress by using standard KVO on the `"fractionCompleted"` key, or by using a closure-based utility exposed in *Progress+Convenience.swift*:
```swift ```swift
migrationProgress?.setProgressHandler { [weak self] (progress) -> Void in migrationProgress?.setProgressHandler { [weak self] (progress) -> Void in
self?.progressView?.setProgress(Float(progress.fractionCompleted), animated: true) self?.progressView?.setProgress(Float(progress.fractionCompleted), animated: true)
@@ -521,7 +515,7 @@ are created from `beginSynchronous(...)`. While the syntax is similar to its asy
```swift ```swift
CoreStore.beginSynchronous { (transaction) -> Void in CoreStore.beginSynchronous { (transaction) -> Void in
// make changes // make changes
transaction.commit() _ = transaction.commit()
} }
``` ```
`transaction` above is a `SynchronousDataTransaction` instance. `transaction` above is a `SynchronousDataTransaction` instance.
@@ -555,7 +549,7 @@ You've seen how to create transactions, but we have yet to see how to make *crea
The `create(...)` method accepts an `Into` clause which specifies the entity for the object you want to create: The `create(...)` method accepts an `Into` clause which specifies the entity for the object you want to create:
```swift ```swift
let person = transaction.create(Into(MyPersonEntity)) let person = transaction.create(Into<MyPersonEntity>())
``` ```
While the syntax is straightforward, CoreStore does not just naively insert a new object. This single line does the following: While the syntax is straightforward, CoreStore does not just naively insert a new object. This single line does the following:
- Checks that the entity type exists in any of the transaction's parent persistent store - Checks that the entity type exists in any of the transaction's parent persistent store
@@ -578,7 +572,7 @@ Note that if you do explicitly specify the configuration name, CoreStore will on
After creating an object from the transaction, you can simply update its properties as normal: After creating an object from the transaction, you can simply update its properties as normal:
```swift ```swift
CoreStore.beginAsynchronous { (transaction) -> Void in CoreStore.beginAsynchronous { (transaction) -> Void in
let person = transaction.create(Into(MyPersonEntity)) let person = transaction.create(Into<MyPersonEntity>())
person.name = "John Smith" person.name = "John Smith"
person.age = 30 person.age = 30
transaction.commit() transaction.commit()
@@ -588,7 +582,7 @@ To update an existing object, fetch the object's instance from the transaction:
```swift ```swift
CoreStore.beginAsynchronous { (transaction) -> Void in CoreStore.beginAsynchronous { (transaction) -> Void in
let person = transaction.fetchOne( let person = transaction.fetchOne(
From(MyPersonEntity), From<MyPersonEntity>(),
Where("name", isEqualTo: "Jane Smith") Where("name", isEqualTo: "Jane Smith")
) )
person.age = person.age + 1 person.age = person.age + 1
@@ -650,7 +644,7 @@ If you do not have references yet to the objects to be deleted, transactions hav
```swift ```swift
CoreStore.beginAsynchronous { (transaction) -> Void in CoreStore.beginAsynchronous { (transaction) -> Void in
transaction.deleteAll( transaction.deleteAll(
From(MyPersonEntity) From<MyPersonEntity>(),
Where("age > 30") Where("age > 30")
) )
transaction.commit() transaction.commit()
@@ -688,7 +682,7 @@ var peopleIDs: [NSManagedObjectID] = // ...
CoreStore.beginAsynchronous { (transaction) -> Void in CoreStore.beginAsynchronous { (transaction) -> Void in
let jane = transaction.fetchOne( let jane = transaction.fetchOne(
From(MyPersonEntity), From<MyPersonEntity>(),
Where("name", isEqualTo: "Jane Smith") Where("name", isEqualTo: "Jane Smith")
) )
jane.friends = NSSet(array: transaction.fetchExisting(peopleIDs)!) jane.friends = NSSet(array: transaction.fetchExisting(peopleIDs)!)
@@ -710,7 +704,7 @@ If you have many attributes, you don't want to keep repeating this mapping every
CoreStore.beginAsynchronous { (transaction) -> Void in CoreStore.beginAsynchronous { (transaction) -> Void in
let json: [String: AnyObject] = // ... let json: [String: AnyObject] = // ...
try! transaction.importObject( try! transaction.importObject(
Into(MyPersonEntity), Into<MyPersonEntity>(),
source: json source: json
) )
transaction.commit() transaction.commit()
@@ -737,8 +731,8 @@ You can even use external types from popular 3rd-party JSON libraries ([SwiftyJS
```swift ```swift
public protocol ImportableObject: class { public protocol ImportableObject: class {
typealias ImportSource typealias ImportSource
static func shouldInsertFromImportSource(source: ImportSource, inTransaction transaction: BaseDataTransaction) -> Bool static func shouldInsert(from source: ImportSource, in transaction: BaseDataTransaction) -> Bool
func didInsertFromImportSource(source: ImportSource, inTransaction transaction: BaseDataTransaction) throws func didInsert(from source: ImportSource, in transaction: BaseDataTransaction) throws
} }
``` ```
First, set `ImportSource` to the expected type of the data source: First, set `ImportSource` to the expected type of the data source:
@@ -750,15 +744,15 @@ This lets us call `importObject(_:source:)` with any `[String: AnyObject]` type
CoreStore.beginAsynchronous { (transaction) -> Void in CoreStore.beginAsynchronous { (transaction) -> Void in
let json: [String: AnyObject] = // ... let json: [String: AnyObject] = // ...
try! transaction.importObject( try! transaction.importObject(
Into(MyPersonEntity), Into<MyPersonEntity>(),
source: json source: json
) )
// ... // ...
} }
``` ```
The actual extraction and assignment of values should be implemented in the `didInsertFromImportSource(...)` method of the `ImportableObject` protocol: The actual extraction and assignment of values should be implemented in the `didInsert(from:in:)` method of the `ImportableObject` protocol:
```swift ```swift
func didInsertFromImportSource(source: ImportSource, inTransaction transaction: BaseDataTransaction) throws { func didInsert(from source: ImportSource, in transaction: BaseDataTransaction) throws {
self.name = source["name"] as? NSString self.name = source["name"] as? NSString
self.age = source["age"] as? NSNumber self.age = source["age"] as? NSNumber
// ... // ...
@@ -769,17 +763,17 @@ Transactions also let you import multiple objects at once using the `importObjec
CoreStore.beginAsynchronous { (transaction) -> Void in CoreStore.beginAsynchronous { (transaction) -> Void in
let jsonArray: [[String: AnyObject]] = // ... let jsonArray: [[String: AnyObject]] = // ...
try! transaction.importObjects( try! transaction.importObjects(
Into(MyPersonEntity), Into<MyPersonEntity>(),
sourceArray: jsonArray sourceArray: jsonArray
) )
// ... // ...
} }
``` ```
Doing so tells the transaction to iterate through the array of import sources and calls `shouldInsertFromImportSource(...)` on the `ImportableObject` to determine which instances should be created. You can do validations and return `false` from `shouldInsertFromImportSource(...)` if you want to skip importing from a source and continue on with the other sources in the array. Doing so tells the transaction to iterate through the array of import sources and calls `shouldInsert(from:in:)` on the `ImportableObject` to determine which instances should be created. You can do validations and return `false` from `shouldInsert(from:in:)` if you want to skip importing from a source and continue on with the other sources in the array.
If on the other hand, your validation in one of the sources failed in such a manner that all other sources should also be cancelled, you can `throw` from within `didInsertFromImportSource(...)`: If on the other hand, your validation in one of the sources failed in such a manner that all other sources should also be cancelled, you can `throw` from within `didInsert(from:in:)`:
```swift ```swift
func didInsertFromImportSource(source: ImportSource, inTransaction transaction: BaseDataTransaction) throws { func didInsert(from source: ImportSource, in transaction: BaseDataTransaction) throws {
self.name = source["name"] as? NSString self.name = source["name"] as? NSString
self.age = source["age"] as? NSNumber self.age = source["age"] as? NSNumber
// ... // ...
@@ -794,7 +788,7 @@ CoreStore.beginAsynchronous { (transaction) -> Void in
let jsonArray: [[String: AnyObject]] = // ... let jsonArray: [[String: AnyObject]] = // ...
do { do {
try transaction.importObjects( try transaction.importObjects(
Into(MyPersonEntity), Into<MyPersonEntity>(),
sourceArray: jsonArray sourceArray: jsonArray
) )
} }
@@ -817,11 +811,11 @@ public protocol ImportableUniqueObject: ImportableObject {
static var uniqueIDKeyPath: String { get } static var uniqueIDKeyPath: String { get }
var uniqueIDValue: UniqueIDType { get set } var uniqueIDValue: UniqueIDType { get set }
static func shouldInsertFromImportSource(source: ImportSource, inTransaction transaction: BaseDataTransaction) -> Bool static func shouldInsert(from source: ImportSource, in transaction: BaseDataTransaction) -> Bool
static func shouldUpdateFromImportSource(source: ImportSource, inTransaction transaction: BaseDataTransaction) -> Bool static func shouldUpdate(from source: ImportSource, in transaction: BaseDataTransaction) -> Bool
static func uniqueIDFromImportSource(source: ImportSource, inTransaction transaction: BaseDataTransaction) throws -> UniqueIDType? static func uniqueID(from source: ImportSource, in transaction: BaseDataTransaction) throws -> UniqueIDType?
func didInsertFromImportSource(source: ImportSource, inTransaction transaction: BaseDataTransaction) throws func didInsert(from source: ImportSource, in transaction: BaseDataTransaction) throws
func updateFromImportSource(source: ImportSource, inTransaction transaction: BaseDataTransaction) throws func update(from source: ImportSource, in transaction: BaseDataTransaction) throws
} }
``` ```
Notice that it has the same insert methods as `ImportableObject`, with additional methods for updates and for specifying the unique ID: Notice that it has the same insert methods as `ImportableObject`, with additional methods for updates and for specifying the unique ID:
@@ -833,18 +827,18 @@ var uniqueIDValue: NSNumber {
get { return self.personID } get { return self.personID }
set { self.personID = newValue } set { self.personID = newValue }
} }
class func uniqueIDFromImportSource(source: ImportSource, inTransaction transaction: BaseDataTransaction) throws -> NSNumber? { class func uniqueID(from source: ImportSource, in transaction: BaseDataTransaction) throws -> NSNumber? {
return source["id"] as? NSNumber return source["id"] as? NSNumber
} }
``` ```
For `ImportableUniqueObject`, the extraction and assignment of values should be implemented from the `updateFromImportSource(...)` method. The `didInsertFromImportSource(...)` by default calls `updateFromImportSource(...)`, but you can separate the implementation for inserts and updates if needed. For `ImportableUniqueObject`, the extraction and assignment of values should be implemented from the `update(from:in:)` method. The `didInsert(from:in:)` by default calls `update(from:in:)`, but you can separate the implementation for inserts and updates if needed.
You can then create/update an object by calling a transaction's `importUniqueObject(...)` method: You can then create/update an object by calling a transaction's `importUniqueObject(...)` method:
```swift ```swift
CoreStore.beginAsynchronous { (transaction) -> Void in CoreStore.beginAsynchronous { (transaction) -> Void in
let json: [String: AnyObject] = // ... let json: [String: AnyObject] = // ...
try! transaction.importUniqueObject( try! transaction.importUniqueObject(
Into(MyPersonEntity), Into<MyPersonEntity>(),
source: json source: json
) )
// ... // ...
@@ -856,14 +850,14 @@ or multiple objects at once with the `importUniqueObjects(...)` method:
CoreStore.beginAsynchronous { (transaction) -> Void in CoreStore.beginAsynchronous { (transaction) -> Void in
let jsonArray: [[String: AnyObject]] = // ... let jsonArray: [[String: AnyObject]] = // ...
try! transaction.importUniqueObjects( try! transaction.importUniqueObjects(
Into(MyPersonEntity), Into<MyPersonEntity>(),
sourceArray: jsonArray sourceArray: jsonArray
) )
// ... // ...
} }
``` ```
As with `ImportableObject`, you can control wether to skip importing an object by implementing As with `ImportableObject`, you can control wether to skip importing an object by implementing
`shouldInsertFromImportSource(...)` and `shouldUpdateFromImportSource(...)`, or to cancel all objects by `throw`ing an error from the `uniqueIDFromImportSource(...)`, `didInsertFromImportSource(...)` or `updateFromImportSource(...)` methods. `shouldInsert(from:in:)` and `shouldUpdate(from:in:)`, or to cancel all objects by `throw`ing an error from the `uniqueID(from:in:)`, `didInsert(from:in:)` or `update(from:in:)` methods.
## Fetching and Querying ## Fetching and Querying
@@ -880,10 +874,10 @@ Before we dive in, be aware that CoreStore distinguishes between *fetching* and
#### `From` clause #### `From` clause
The search conditions for fetches and queries are specified using *clauses*. All fetches and queries require a `From` clause that indicates the target entity type: The search conditions for fetches and queries are specified using *clauses*. All fetches and queries require a `From` clause that indicates the target entity type:
```swift ```swift
let people = CoreStore.fetchAll(From(MyPersonEntity)) let people = CoreStore.fetchAll(From<MyPersonEntity>())
// CoreStore.fetchAll(From<MyPersonEntity>()) works as well // CoreStore.fetchAll(From<MyPersonEntity>()) works as well
``` ```
`people` in the example above will be of type `[MyPersonEntity]`. The `From(MyPersonEntity)` clause indicates a fetch to all persistent stores that `MyPersonEntity` belong to. `people` in the example above will be of type `[MyPersonEntity]`. The `From<MyPersonEntity>()` clause indicates a fetch to all persistent stores that `MyPersonEntity` belong to.
If the entity exists in multiple configurations and you need to only search from a particular configuration, indicate in the `From` clause the configuration name for the destination persistent store: If the entity exists in multiple configurations and you need to only search from a particular configuration, indicate in the `From` clause the configuration name for the destination persistent store:
```swift ```swift
@@ -912,11 +906,11 @@ Each method's purpose is straightforward, but we need to understand how to set t
The `Where` clause is CoreStore's `NSPredicate` wrapper. It specifies the search filter to use when fetching (or querying). It implements all initializers that `NSPredicate` does (except for `-predicateWithBlock:`, which Core Data does not support): The `Where` clause is CoreStore's `NSPredicate` wrapper. It specifies the search filter to use when fetching (or querying). It implements all initializers that `NSPredicate` does (except for `-predicateWithBlock:`, which Core Data does not support):
```swift ```swift
var people = CoreStore.fetchAll( var people = CoreStore.fetchAll(
From(MyPersonEntity), From<MyPersonEntity>(),
Where("%K > %d", "age", 30) // string format initializer Where("%K > %d", "age", 30) // string format initializer
) )
people = CoreStore.fetchAll( people = CoreStore.fetchAll(
From(MyPersonEntity), From<MyPersonEntity>(),
Where(true) // boolean initializer Where(true) // boolean initializer
) )
``` ```
@@ -924,14 +918,14 @@ If you do have an existing `NSPredicate` instance already, you can pass that to
```swift ```swift
let predicate = NSPredicate(...) let predicate = NSPredicate(...)
var people = CoreStore.fetchAll( var people = CoreStore.fetchAll(
From(MyPersonEntity), From<MyPersonEntity>(),
Where(predicate) // predicate initializer Where(predicate) // predicate initializer
) )
``` ```
`Where` clauses also implement the `&&`, `||`, and `!` logic operators, so you can provide logical conditions without writing too much `AND`, `OR`, and `NOT` strings: `Where` clauses also implement the `&&`, `||`, and `!` logic operators, so you can provide logical conditions without writing too much `AND`, `OR`, and `NOT` strings:
```swift ```swift
var people = CoreStore.fetchAll( var people = CoreStore.fetchAll(
From(MyPersonEntity), From<MyPersonEntity>(),
Where("age > %d", 30) && Where("gender == %@", "M") Where("age > %d", 30) && Where("gender == %@", "M")
) )
``` ```
@@ -942,20 +936,20 @@ If you do not provide a `Where` clause, all objects that belong to the specified
The `OrderBy` clause is CoreStore's `NSSortDescriptor` wrapper. Use it to specify attribute keys in which to sort the fetch (or query) results with. The `OrderBy` clause is CoreStore's `NSSortDescriptor` wrapper. Use it to specify attribute keys in which to sort the fetch (or query) results with.
```swift ```swift
var mostValuablePeople = CoreStore.fetchAll( var mostValuablePeople = CoreStore.fetchAll(
From(MyPersonEntity), From<MyPersonEntity>(),
OrderBy(.Descending("rating"), .Ascending("surname")) OrderBy(.descending("rating"), .ascending("surname"))
) )
``` ```
As seen above, `OrderBy` accepts a list of `SortKey` enumeration values, which can be either `.Ascending` or `.Descending`. As seen above, `OrderBy` accepts a list of `SortKey` enumeration values, which can be either `.ascending` or `.descending`.
You can use the `+` and `+=` operator to append `OrderBy`s together. This is useful when sorting conditionally: You can use the `+` and `+=` operator to append `OrderBy`s together. This is useful when sorting conditionally:
```swift ```swift
var orderBy = OrderBy(.Descending("rating")) var orderBy = OrderBy(.descending("rating"))
if sortFromYoungest { if sortFromYoungest {
orderBy += OrderBy(.Ascending("age")) orderBy += OrderBy(.ascending("age"))
} }
var mostValuablePeople = CoreStore.fetchAll( var mostValuablePeople = CoreStore.fetchAll(
From(MyPersonEntity), From<MyPersonEntity>(),
orderBy orderBy
) )
``` ```
@@ -965,9 +959,9 @@ var mostValuablePeople = CoreStore.fetchAll(
The `Tweak` clause lets you, uh, *tweak* the fetch (or query). `Tweak` exposes the `NSFetchRequest` in a closure where you can make changes to its properties: The `Tweak` clause lets you, uh, *tweak* the fetch (or query). `Tweak` exposes the `NSFetchRequest` in a closure where you can make changes to its properties:
```swift ```swift
var people = CoreStore.fetchAll( var people = CoreStore.fetchAll(
From(MyPersonEntity), From<MyPersonEntity>(),
Where("age > %d", 30), Where("age > %d", 30),
OrderBy(.Ascending("surname")), OrderBy(.ascending("surname")),
Tweak { (fetchRequest) -> Void in Tweak { (fetchRequest) -> Void in
fetchRequest.includesPendingChanges = false fetchRequest.includesPendingChanges = false
fetchRequest.returnsObjectsAsFaults = false fetchRequest.returnsObjectsAsFaults = false
@@ -996,7 +990,7 @@ Setting up the `From`, `Where`, `OrderBy`, and `Tweak` clauses is similar to how
The `Select<T>` clause specifies the target attribute/aggregate key, as well as the expected return type: The `Select<T>` clause specifies the target attribute/aggregate key, as well as the expected return type:
```swift ```swift
let johnsAge = CoreStore.queryValue( let johnsAge = CoreStore.queryValue(
From(MyPersonEntity), From<MyPersonEntity>(),
Select<Int>("age"), Select<Int>("age"),
Where("name == %@", "John Smith") Where("name == %@", "John Smith")
) )
@@ -1021,29 +1015,29 @@ The example above queries the "age" property for the first object that matches t
For `queryAttributes(...)`, only `NSDictionary` is valid for `Select`, thus you are allowed to omit the generic type: For `queryAttributes(...)`, only `NSDictionary` is valid for `Select`, thus you are allowed to omit the generic type:
```swift ```swift
let allAges = CoreStore.queryAttributes( let allAges = CoreStore.queryAttributes(
From(MyPersonEntity), From<MyPersonEntity>(),
Select("age") Select("age")
) )
``` ```
If you only need a value for a particular attribute, you can just specify the key name (like we did with `Select<Int>("age")`), but several aggregate functions can also be used as parameter to `Select`: If you only need a value for a particular attribute, you can just specify the key name (like we did with `Select<Int>("age")`), but several aggregate functions can also be used as parameter to `Select`:
- `.Average(...)` - `.average(...)`
- `.Count(...)` - `.count(...)`
- `.Maximum(...)` - `.maximum(...)`
- `.Minimum(...)` - `.minimum(...)`
- `.Sum(...)` - `.sum(...)`
```swift ```swift
let oldestAge = CoreStore.queryValue( let oldestAge = CoreStore.queryValue(
From(MyPersonEntity), From<MyPersonEntity>(),
Select<Int>(.Maximum("age")) Select<Int>(.maximum("age"))
) )
``` ```
For `queryAttributes(...)` which returns an array of dictionaries, you can specify multiple attributes/aggregates to `Select`: For `queryAttributes(...)` which returns an array of dictionaries, you can specify multiple attributes/aggregates to `Select`:
```swift ```swift
let personJSON = CoreStore.queryAttributes( let personJSON = CoreStore.queryAttributes(
From(MyPersonEntity), From<MyPersonEntity>(),
Select("name", "age") Select("name", "age")
) )
``` ```
@@ -1063,8 +1057,8 @@ let personJSON = CoreStore.queryAttributes(
You can also include an aggregate as well: You can also include an aggregate as well:
```swift ```swift
let personJSON = CoreStore.queryAttributes( let personJSON = CoreStore.queryAttributes(
From(MyPersonEntity), From<MyPersonEntity>(),
Select("name", .Count("friends")) Select("name", .count("friends"))
) )
``` ```
which returns: which returns:
@@ -1083,8 +1077,8 @@ which returns:
The `"count(friends)"` key name was automatically used by CoreStore, but you can specify your own key alias if you need: The `"count(friends)"` key name was automatically used by CoreStore, but you can specify your own key alias if you need:
```swift ```swift
let personJSON = CoreStore.queryAttributes( let personJSON = CoreStore.queryAttributes(
From(MyPersonEntity), From<MyPersonEntity>(),
Select("name", .Count("friends", As: "friendsCount")) Select("name", .count("friends", as: "friendsCount"))
) )
``` ```
which now returns: which now returns:
@@ -1106,8 +1100,8 @@ which now returns:
The `GroupBy` clause lets you group results by a specified attribute/aggregate. This is useful only for `queryAttributes(...)` since `queryValue(...)` just returns the first value. The `GroupBy` clause lets you group results by a specified attribute/aggregate. This is useful only for `queryAttributes(...)` since `queryValue(...)` just returns the first value.
```swift ```swift
let personJSON = CoreStore.queryAttributes( let personJSON = CoreStore.queryAttributes(
From(MyPersonEntity), From<MyPersonEntity>(),
Select("age", .Count("age", As: "count")), Select("age", .count("age", as: "count")),
GroupBy("age") GroupBy("age")
) )
``` ```
@@ -1153,7 +1147,7 @@ A couple of examples, `ListMonitor`:
<img width="369" alt="screen shot 2016-07-10 at 22 56 44" src="https://cloud.githubusercontent.com/assets/3029684/16713994/ae06e702-46f1-11e6-83a8-dee48b480bab.png" /> <img width="369" alt="screen shot 2016-07-10 at 22 56 44" src="https://cloud.githubusercontent.com/assets/3029684/16713994/ae06e702-46f1-11e6-83a8-dee48b480bab.png" />
`CoreStoreError.MappingModelNotFoundError`: `CoreStoreError.mappingModelNotFoundError`:
<img width="506" alt="MappingModelNotFoundError" src="https://cloud.githubusercontent.com/assets/3029684/16713962/e021f548-46f0-11e6-8100-f9b5ea6b4a08.png" /> <img width="506" alt="MappingModelNotFoundError" src="https://cloud.githubusercontent.com/assets/3029684/16713962/e021f548-46f0-11e6-8100-f9b5ea6b4a08.png" />
@@ -1232,9 +1226,9 @@ Including `ListObserver`, there are 3 observer protocols you can implement depen
We then need to create a `ListMonitor` instance and register our `ListObserver` as an observer: We then need to create a `ListMonitor` instance and register our `ListObserver` as an observer:
```swift ```swift
self.monitor = CoreStore.monitorList( self.monitor = CoreStore.monitorList(
From(MyPersonEntity), From<MyPersonEntity>(),
Where("age > 30"), Where("age > 30"),
OrderBy(.Ascending("name")), OrderBy(.ascending("name")),
Tweak { (fetchRequest) -> Void in Tweak { (fetchRequest) -> Void in
fetchRequest.fetchBatchSize = 20 fetchRequest.fetchBatchSize = 20
} }
@@ -1253,10 +1247,10 @@ let firstPerson = self.monitor[0]
If the list needs to be grouped into sections, create the `ListMonitor` instance with the `monitorSectionedList(...)` method and a `SectionBy` clause: If the list needs to be grouped into sections, create the `ListMonitor` instance with the `monitorSectionedList(...)` method and a `SectionBy` clause:
```swift ```swift
self.monitor = CoreStore.monitorSectionedList( self.monitor = CoreStore.monitorSectionedList(
From(MyPersonEntity), From<MyPersonEntity>(),
SectionBy("age"), SectionBy("age"),
Where("gender", isEqualTo: "M"), Where("gender", isEqualTo: "M"),
OrderBy(.Ascending("age"), .Ascending("name")), OrderBy(.ascending("age"), .ascending("name")),
Tweak { (fetchRequest) -> Void in Tweak { (fetchRequest) -> Void in
fetchRequest.fetchBatchSize = 20 fetchRequest.fetchBatchSize = 20
} }
@@ -1267,11 +1261,11 @@ A list controller created this way will group the objects by the attribute key i
The `SectionBy` clause can also be passed a closure to transform the section name into a displayable string: The `SectionBy` clause can also be passed a closure to transform the section name into a displayable string:
```swift ```swift
self.monitor = CoreStore.monitorSectionedList( self.monitor = CoreStore.monitorSectionedList(
From(MyPersonEntity), From<MyPersonEntity>(),
SectionBy("age") { (sectionName) -> String? in SectionBy("age") { (sectionName) -> String? in
"\(sectionName) years old" "\(sectionName) years old"
}, },
OrderBy(.Ascending("age"), .Ascending("name")) OrderBy(.ascending("age"), .ascending("name"))
) )
``` ```
This is useful when implementing a `UITableViewDelegate`'s section header: This is useful when implementing a `UITableViewDelegate`'s section header:
@@ -1300,7 +1294,7 @@ With 2.0, all CoreStore types are still written in pure Swift, but they now have
<tr><th>Swift</th><th>Objective-C</th></tr> <tr><th>Swift</th><th>Objective-C</th></tr>
<tr> <tr>
<td><pre lang=swift> <td><pre lang=swift>
try CoreStore.addStorageAndWait(SQLiteStore) try CoreStore.addStorageAndWait(SQLiteStore.self)
</pre></td> </pre></td>
<td><pre lang=objc> <td><pre lang=objc>
NSError *error NSError *error
@@ -1313,8 +1307,8 @@ CoreStore.beginAsynchronous { (transaction) in
// ... // ...
transaction.commit { (result) in transaction.commit { (result) in
switch result { switch result {
case .Success(let hasChanges): print(hasChanges) case .success(let hasChanges): print(hasChanges)
case .Failure(let error): print(error) case .failure(let error): print(error)
} }
} }
} }
@@ -1411,13 +1405,7 @@ NSArray<MYPerson *> *objects =
CSSortAscending(CSKeyPath(MYPerson, firstName)), nil)]]; CSSortAscending(CSKeyPath(MYPerson, firstName)), nil)]];
``` ```
To use these syntax sugars, include *CoreStoreBridge.h* in your Objective-C source files. For projects that support iOS 7 (and thus cannot build CoreStore as a module), you will need to add To use these syntax sugars, include *CoreStoreBridge.h* in your Objective-C source files.
```
SWIFT_OBJC_INTERFACE_HEADER_NAME=$(SWIFT_OBJC_INTERFACE_HEADER_NAME)
```
to your target's `GCC_PREPROCESSOR_DEFINITIONS` build setting.
<img width="797" alt="GCC_PREPROCESSOR_DEFINITIONS" src="https://cloud.githubusercontent.com/assets/3029684/16714547/92497fc4-4701-11e6-81db-6b1a11743cc5.png" />
# Roadmap # Roadmap
@@ -1429,14 +1417,14 @@ to your target's `GCC_PREPROCESSOR_DEFINITIONS` build setting.
# Installation # Installation
- Requires: - Requires:
- iOS 7 SDK and above - iOS 8 SDK and above
- Swift 2.2 (Xcode 7.3) - Swift 3.0.1 (Xcode 8.2)
- Dependencies: - Dependencies:
- [GCDKit](https://github.com/JohnEstropia/GCDKit) - *None*
- Other notes: - Other notes:
- The `com.apple.CoreData.ConcurrencyDebug` debug argument should be turned off for the app. CoreStore already guarantees safety for you by making the main context read-only, and by only executing transactions serially. - The `com.apple.CoreData.ConcurrencyDebug` debug argument should be turned off for the app. CoreStore already guarantees safety for you by making the main context read-only, and by only executing transactions serially.
### Install with CocoaPods (iOS 7 not supported) ### Install with CocoaPods
``` ```
pod 'CoreStore' pod 'CoreStore'
``` ```
@@ -1445,8 +1433,7 @@ This installs CoreStore as a framework. Declare `import CoreStore` in your swift
### Install with Carthage ### Install with Carthage
In your `Cartfile`, add In your `Cartfile`, add
``` ```
github "JohnEstropia/CoreStore" >= 2.0.0 github "JohnEstropia/CoreStore" >= 3.0.0
github "JohnEstropia/GCDKit" >= 1.2.5
``` ```
and run and run
``` ```
@@ -1459,7 +1446,7 @@ git submodule add https://github.com/JohnEstropia/CoreStore.git <destination dir
``` ```
Drag and drop **CoreStore.xcodeproj** to your project. Drag and drop **CoreStore.xcodeproj** to your project.
#### To install as a framework (iOS 7 not supported): #### To install as a framework:
Drag and drop **CoreStore.xcodeproj** to your project. Drag and drop **CoreStore.xcodeproj** to your project.
#### To include directly in your app module: #### To include directly in your app module:
@@ -1470,16 +1457,30 @@ Add all *.swift* files to your project.
To use the Objective-C syntax sugars, import *CoreStoreBridge.h* in your *.m* source files. To use the Objective-C syntax sugars, import *CoreStoreBridge.h* in your *.m* source files.
For projects that support iOS 7 (and thus cannot build CoreStore as a module), you will need to add
```
SWIFT_OBJC_INTERFACE_HEADER_NAME=$(SWIFT_OBJC_INTERFACE_HEADER_NAME)
```
to your target's `GCC_PREPROCESSOR_DEFINITIONS` build setting:
<img width="797" alt="GCC_PREPROCESSOR_DEFINITIONS" src="https://cloud.githubusercontent.com/assets/3029684/16714547/92497fc4-4701-11e6-81db-6b1a11743cc5.png" />
# Changesets # Changesets
### Upgrading from 2.x.x to 3.x.x
**Obsoleted**
- `UnsageDataTransaction.internalContext` was removed. Accessing the internal context (or more specifically, accessing context-level methods such as fetches) are now available through the `FetchableSource` and `QueryableProtocol` protocols, which are retrievable with `NSManagedObject.fetchSource()` and `NSManagedObject.querySource()` respectively. These protocols are implemented by `DataStack` and `BaseDataTransaction`.
**Deprecated**
Methods have been renamed to better fit the [Swift 3 naming conventions](https://swift.org/documentation/api-design-guidelines/).
- `entityDescriptionForType(_:)``entityDescription(for:)`
- `objectIDForURIRepresentation(_:)``objectID(for:)`
- `ImportableObject` and `ImportableUniqueObject` protocol methods (and their variants) have been renamed. The old methods are still available, but will be removed in a future update.
- `shouldInsertFromImportSource(_:inTransaction:)``shouldInsert(from:in:)`
- `didInsertFromImportSource(_:inTransaction:)``didInsert(from:in:)`
- `shouldUpdateFromImportSource(_:inTransaction :)``shouldUpdate(from:in:)`
- `uniqueIDFromImportSource(_:inTransaction :)``uniqueID(from:in:)`
- `updateFromImportSource(_:inTransaction:)``update(from:in:)`
**Miscellaneous**
- APIs obsoleted from 2.0.0 have been removed.
- CoreStore does not depend on [GCDKit](https://github.com/JohnEstropia/GCDKit) anymore, thanks to Swift 3's better Grand Central Dispatch API.
- All enum cases are now lowercased
- `CoreStoreError` now implements the new Swift `CustomNSError` protocol for better Objective-C
bridging.
- Some methods may emit warnings for unused return values. `@discardableResult` annotations have been set to better reflect the responsibility of API users to use/inspect return values.
### Upgrading from 1.x.x to 2.x.x ### Upgrading from 1.x.x to 2.x.x
**Obsoleted** **Obsoleted**
- `AsynchronousDataTransaction.rollback()` was removed. Undo and rollback functionality are now only allowed on `UnsafeDataTransaction`s - `AsynchronousDataTransaction.rollback()` was removed. Undo and rollback functionality are now only allowed on `UnsafeDataTransaction`s

View File

@@ -0,0 +1,274 @@
//
// AsynchronousDataTransaction.swift
// CoreStore
//
// Copyright © 2015 John Rommel Estropia
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in all
// copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
// SOFTWARE.
//
import Foundation
import CoreData
// MARK: - 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<T: DynamicObject>(_ into: Into<T>) -> T {
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<T: DynamicObject>(_ object: T?) -> T? {
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<T: DynamicObject>(_ into: Into<T>, _ objectID: NSManagedObjectID) -> T? {
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<T: DynamicObject>(_ object: T?) {
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<T: DynamicObject>(_ object1: T?, _ object2: T?, _ objects: T?...) {
CoreStore.assert(
!self.isCommitted,
"Attempted to delete an entities from an already committed \(cs_typeName(self))."
)
super.delete(([object1, object2] + objects).flatMap { $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 { (result) -> Void in
completion(result.0, result.1)
self.result = result
group.leave()
}
group.wait()
}
// 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 { (result) in
switch result {
case (let hasChanges, nil): completion(SaveResult(hasChanges: hasChanges))
case (_, let error?): completion(SaveResult(error))
}
}
}
@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 nil: return nil
case (let hasChanges, nil)?: return SaveResult(hasChanges: hasChanges)
case (_, let error?)?: return SaveResult(error)
}
}
}

View File

@@ -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<T: DynamicObject & ImportableObject>(
into: Into<T>, _ into: Into<T>,
source: T.ImportSource) throws -> T? { source: T.ImportSource) throws -> T? {
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,10 +67,10 @@ 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<T: DynamicObject & ImportableObject>(
object: T, _ object: T,
source: T.ImportSource) throws { source: T.ImportSource) throws {
CoreStore.assert( CoreStore.assert(
@@ -77,14 +78,14 @@ public extension BaseDataTransaction {
"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 = type(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<T: DynamicObject & ImportableObject, S: Sequence>(
into: Into<T>, _ into: Into<T>,
sourceArray: S) throws -> [T] { sourceArray: S) throws -> [T] where S.Iterator.Element == T.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.flatMap { (source) -> T? 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<T: DynamicObject & ImportableUniqueObject>(
into: Into<T>, _ into: Into<T>,
source: T.ImportSource) throws -> T? { source: T.ImportSource) throws -> T? {
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 = self.fetchOne(From(entityType), Where(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,79 @@ 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<T: DynamicObject & ImportableUniqueObject, S: Sequence>(
into: Into<T>, _ into: Into<T>,
sourceArray: S, sourceArray: S,
@noescape preProcess: (mapping: [T.UniqueIDType: T.ImportSource]) throws -> [T.UniqueIDType: T.ImportSource] = { $0 }) throws -> [T] { preProcess: @escaping (_ mapping: [T.UniqueIDType: T.ImportSource]) throws -> [T.UniqueIDType: T.ImportSource] = { $0 }) throws -> [T] where S.Iterator.Element == T.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<T.UniqueIDType, T.ImportSource>()
let sortedIDs = try autoreleasepool {
return try sourceArray.flatMap { (source) -> T.UniqueIDType? in return try sourceArray.flatMap { (source) -> T.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<T.UniqueIDType, T>()
for object in self.fetchAll(From(T), Where(T.uniqueIDKeyPath, isMemberOf: sortedIDs)) ?? [] { self.fetchAll(From(entityType), Where(entityType.uniqueIDKeyPath, isMemberOf: sortedIDs))?
.forEach { existingObjectsByID[$0.uniqueIDValue] = $0 }
var processedObjectIDs = Set<T.UniqueIDType>()
var result = [T]()
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

@@ -29,92 +29,99 @@ import CoreData
// MARK: - DataTransaction // MARK: - DataTransaction
public extension BaseDataTransaction { extension BaseDataTransaction: FetchableSource, QueryableSource {
/** /**
Fetches the `NSManagedObject` instance in the transaction's context from a reference created from a transaction or from a different managed object context. 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<T: DynamicObject>(_ from: From<T>, _ deleteClauses: DeleteClause...) -> Int? {
CoreStore.assert(
self.isRunningInAllowedQueue(),
"Attempted to delete from a \(cs_typeName(self)) outside its designated queue."
)
return 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<T: DynamicObject>(_ from: From<T>, _ deleteClauses: [DeleteClause]) -> Int? {
CoreStore.assert(
self.isRunningInAllowedQueue(),
"Attempted to delete from a \(cs_typeName(self)) outside its designated queue."
)
return self.context.deleteAll(from, deleteClauses)
}
// 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 - parameter object: a reference to the object created/fetched outside the transaction
- returns: the `NSManagedObject` instance if the object exists in the transaction, or `nil` if not found. - returns: the `DynamicObject` instance if the object exists in the transaction, or `nil` if not found.
*/ */
@warn_unused_result public func fetchExisting<T: DynamicObject>(_ object: T) -> T? {
public func fetchExisting<T: NSManagedObject>(object: T) -> T? {
do { return self.context.fetchExisting(object)
return (try self.context.existingObjectWithID(object.objectID) as! T)
}
catch _ {
return nil
}
} }
/** /**
Fetches the `NSManagedObject` instance in the transaction's context from an `NSManagedObjectID`. Fetches the `DynamicObject` instance in the transaction's context from an `NSManagedObjectID`.
- parameter objectID: the `NSManagedObjectID` for the object - parameter objectID: the `NSManagedObjectID` for the object
- returns: the `NSManagedObject` instance if the object exists in the transaction, or `nil` if not found. - returns: the `DynamicObject` instance if the object exists in the transaction, or `nil` if not found.
*/ */
@warn_unused_result public func fetchExisting<T: DynamicObject>(_ objectID: NSManagedObjectID) -> T? {
public func fetchExisting<T: NSManagedObject>(objectID: NSManagedObjectID) -> T? {
do { return self.context.fetchExisting(objectID)
return (try self.context.existingObjectWithID(objectID) as! T)
}
catch _ {
return nil
}
} }
/** /**
Fetches the `NSManagedObject` instances in the transaction's context from references created from a transaction or from a different managed object context. 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 `NSManagedObject`s created/fetched outside the transaction - parameter objects: an array of `DynamicObject`s created/fetched outside the transaction
- returns: the `NSManagedObject` array for objects that exists in the transaction - returns: the `DynamicObject` array for objects that exists in the transaction
*/ */
@warn_unused_result public func fetchExisting<T: DynamicObject, S: Sequence>(_ objects: S) -> [T] where S.Iterator.Element == T {
public func fetchExisting<T: NSManagedObject, S: SequenceType where S.Generator.Element == T>(objects: S) -> [T] {
return objects.flatMap { (try? self.context.existingObjectWithID($0.objectID)) as? T } return self.context.fetchExisting(objects)
} }
/** /**
Fetches the `NSManagedObject` instances in the transaction's context from a list of `NSManagedObjectID`. Fetches the `DynamicObject` instances in the transaction's context from a list of `NSManagedObjectID`.
- parameter objectIDs: the `NSManagedObjectID` array for the objects - parameter objectIDs: the `NSManagedObjectID` array for the objects
- returns: the `NSManagedObject` array for objects that exists in the transaction - returns: the `DynamicObject` array for objects that exists in the transaction
*/ */
@warn_unused_result public func fetchExisting<T: DynamicObject, S: Sequence>(_ objectIDs: S) -> [T] where S.Iterator.Element == NSManagedObjectID {
public func fetchExisting<T: NSManagedObject, S: SequenceType where S.Generator.Element == NSManagedObjectID>(objectIDs: S) -> [T] {
return objectIDs.flatMap { (try? self.context.existingObjectWithID($0)) as? T } return self.context.fetchExisting(objectIDs)
} }
/** /**
Fetches the first `NSManagedObject` instance that satisfies the specified `FetchClause`s. Accepts `Where`, `OrderBy`, and `Tweak` clauses. 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 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. - parameter fetchClauses: a series of `FetchClause` instances for the fetch request. Accepts `Where`, `OrderBy`, and `Tweak` clauses.
- returns: the first `NSManagedObject` instance that satisfies the specified `FetchClause`s - returns: the first `DynamicObject` instance that satisfies the specified `FetchClause`s
*/ */
@warn_unused_result public func fetchOne<T: DynamicObject>(_ from: From<T>, _ fetchClauses: FetchClause...) -> T? {
public func fetchOne<T: NSManagedObject>(from: From<T>, _ fetchClauses: FetchClause...) -> T? {
return self.fetchOne(from, fetchClauses)
}
/**
Fetches the first `NSManagedObject` 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 `NSManagedObject` instance that satisfies the specified `FetchClause`s
*/
@warn_unused_result
public func fetchOne<T: NSManagedObject>(from: From<T>, _ fetchClauses: [FetchClause]) -> T? {
CoreStore.assert( CoreStore.assert(
self.isRunningInAllowedQueue(), self.isRunningInAllowedQueue(),
@@ -124,27 +131,29 @@ public extension BaseDataTransaction {
} }
/** /**
Fetches all `NSManagedObject` instances that satisfy the specified `FetchClause`s. Accepts `Where`, `OrderBy`, and `Tweak` clauses. 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 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. - parameter fetchClauses: a series of `FetchClause` instances for the fetch request. Accepts `Where`, `OrderBy`, and `Tweak` clauses.
- returns: all `NSManagedObject` instances that satisfy the specified `FetchClause`s - returns: the first `DynamicObject` instance that satisfies the specified `FetchClause`s
*/ */
@warn_unused_result public func fetchOne<T: DynamicObject>(_ from: From<T>, _ fetchClauses: [FetchClause]) -> T? {
public func fetchAll<T: NSManagedObject>(from: From<T>, _ fetchClauses: FetchClause...) -> [T]? {
return self.fetchAll(from, fetchClauses) CoreStore.assert(
self.isRunningInAllowedQueue(),
"Attempted to fetch from a \(cs_typeName(self)) outside its designated queue."
)
return self.context.fetchOne(from, fetchClauses)
} }
/** /**
Fetches all `NSManagedObject` instances that satisfy the specified `FetchClause`s. Accepts `Where`, `OrderBy`, and `Tweak` clauses. 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 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. - parameter fetchClauses: a series of `FetchClause` instances for the fetch request. Accepts `Where`, `OrderBy`, and `Tweak` clauses.
- returns: all `NSManagedObject` instances that satisfy the specified `FetchClause`s - returns: all `DynamicObject` instances that satisfy the specified `FetchClause`s
*/ */
@warn_unused_result public func fetchAll<T: DynamicObject>(_ from: From<T>, _ fetchClauses: FetchClause...) -> [T]? {
public func fetchAll<T: NSManagedObject>(from: From<T>, _ fetchClauses: [FetchClause]) -> [T]? {
CoreStore.assert( CoreStore.assert(
self.isRunningInAllowedQueue(), self.isRunningInAllowedQueue(),
@@ -154,58 +163,61 @@ public extension BaseDataTransaction {
} }
/** /**
Fetches the number of `NSManagedObject`s that satisfy the specified `FetchClause`s. Accepts `Where`, `OrderBy`, and `Tweak` clauses. 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 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. - parameter fetchClauses: a series of `FetchClause` instances for the fetch request. Accepts `Where`, `OrderBy`, and `Tweak` clauses.
- returns: the number `NSManagedObject`s that satisfy the specified `FetchClause`s - returns: all `DynamicObject` instances that satisfy the specified `FetchClause`s
*/ */
@warn_unused_result public func fetchAll<T: DynamicObject>(_ from: From<T>, _ fetchClauses: [FetchClause]) -> [T]? {
public func fetchCount<T: NSManagedObject>(from: From<T>, _ fetchClauses: FetchClause...) -> Int? {
return self.fetchCount(from, fetchClauses)
}
/**
Fetches the number of `NSManagedObject`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 `NSManagedObject`s that satisfy the specified `FetchClause`s
*/
@warn_unused_result
public func fetchCount<T: NSManagedObject>(from: From<T>, _ fetchClauses: [FetchClause]) -> Int? {
CoreStore.assert( CoreStore.assert(
self.isRunningInAllowedQueue(), self.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.context.fetchAll(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 `DynamicObject`s that satisfy the specified `FetchClause`s
*/
public func fetchCount<T: DynamicObject>(_ from: From<T>, _ fetchClauses: FetchClause...) -> Int? {
CoreStore.assert(
self.isRunningInAllowedQueue(),
"Attempted to fetch from a \(cs_typeName(self)) outside its designated queue."
)
return self.context.fetchCount(from, fetchClauses) return self.context.fetchCount(from, fetchClauses)
} }
/** /**
Fetches the `NSManagedObjectID` for the first `NSManagedObject` that satisfies the specified `FetchClause`s. Accepts `Where`, `OrderBy`, and `Tweak` clauses. 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 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. - parameter fetchClauses: a series of `FetchClause` instances for the fetch request. Accepts `Where`, `OrderBy`, and `Tweak` clauses.
- returns: the `NSManagedObjectID` for the first `NSManagedObject` that satisfies the specified `FetchClause`s - returns: the number `DynamicObject`s that satisfy the specified `FetchClause`s
*/ */
@warn_unused_result public func fetchCount<T: DynamicObject>(_ from: From<T>, _ fetchClauses: [FetchClause]) -> Int? {
public func fetchObjectID<T: NSManagedObject>(from: From<T>, _ fetchClauses: FetchClause...) -> NSManagedObjectID? {
return self.fetchObjectID(from, fetchClauses) CoreStore.assert(
self.isRunningInAllowedQueue(),
"Attempted to fetch from a \(cs_typeName(self)) outside its designated queue."
)
return self.context.fetchCount(from, fetchClauses)
} }
/** /**
Fetches the `NSManagedObjectID` for the first `NSManagedObject` that satisfies the specified `FetchClause`s. Accepts `Where`, `OrderBy`, and `Tweak` clauses. 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 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. - parameter fetchClauses: a series of `FetchClause` instances for the fetch request. Accepts `Where`, `OrderBy`, and `Tweak` clauses.
- returns: the `NSManagedObjectID` for the first `NSManagedObject` that satisfies the specified `FetchClause`s - returns: the `NSManagedObjectID` for the first `DynamicObject` that satisfies the specified `FetchClause`s
*/ */
@warn_unused_result public func fetchObjectID<T: DynamicObject>(_ from: From<T>, _ fetchClauses: FetchClause...) -> NSManagedObjectID? {
public func fetchObjectID<T: NSManagedObject>(from: From<T>, _ fetchClauses: [FetchClause]) -> NSManagedObjectID? {
CoreStore.assert( CoreStore.assert(
self.isRunningInAllowedQueue(), self.isRunningInAllowedQueue(),
@@ -215,27 +227,29 @@ public extension BaseDataTransaction {
} }
/** /**
Fetches the `NSManagedObjectID` for all `NSManagedObject`s that satisfy the specified `FetchClause`s. Accepts `Where`, `OrderBy`, and `Tweak` clauses. 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 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. - parameter fetchClauses: a series of `FetchClause` instances for the fetch request. Accepts `Where`, `OrderBy`, and `Tweak` clauses.
- returns: the `NSManagedObjectID` for all `NSManagedObject`s that satisfy the specified `FetchClause`s - returns: the `NSManagedObjectID` for the first `DynamicObject` that satisfies the specified `FetchClause`s
*/ */
@warn_unused_result public func fetchObjectID<T: DynamicObject>(_ from: From<T>, _ fetchClauses: [FetchClause]) -> NSManagedObjectID? {
public func fetchObjectIDs<T: NSManagedObject>(from: From<T>, _ fetchClauses: FetchClause...) -> [NSManagedObjectID]? {
return self.fetchObjectIDs(from, fetchClauses) CoreStore.assert(
self.isRunningInAllowedQueue(),
"Attempted to fetch from a \(cs_typeName(self)) outside its designated queue."
)
return self.context.fetchObjectID(from, fetchClauses)
} }
/** /**
Fetches the `NSManagedObjectID` for all `NSManagedObject`s that satisfy the specified `FetchClause`s. Accepts `Where`, `OrderBy`, and `Tweak` clauses. 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 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. - parameter fetchClauses: a series of `FetchClause` instances for the fetch request. Accepts `Where`, `OrderBy`, and `Tweak` clauses.
- returns: the `NSManagedObjectID` for all `NSManagedObject`s that satisfy the specified `FetchClause`s - returns: the `NSManagedObjectID` for all `DynamicObject`s that satisfy the specified `FetchClause`s
*/ */
@warn_unused_result public func fetchObjectIDs<T: DynamicObject>(_ from: From<T>, _ fetchClauses: FetchClause...) -> [NSManagedObjectID]? {
public func fetchObjectIDs<T: NSManagedObject>(from: From<T>, _ fetchClauses: [FetchClause]) -> [NSManagedObjectID]? {
CoreStore.assert( CoreStore.assert(
self.isRunningInAllowedQueue(), self.isRunningInAllowedQueue(),
@@ -245,38 +259,23 @@ public extension BaseDataTransaction {
} }
/** /**
Deletes all `NSManagedObject`s that satisfy the specified `DeleteClause`s. Accepts `Where`, `OrderBy`, and `Tweak` clauses. 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 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. - parameter fetchClauses: a series of `FetchClause` instances for the fetch request. Accepts `Where`, `OrderBy`, and `Tweak` clauses.
- returns: the number of `NSManagedObject`s deleted - returns: the `NSManagedObjectID` for all `DynamicObject`s that satisfy the specified `FetchClause`s
*/ */
public func deleteAll<T: NSManagedObject>(from: From<T>, _ deleteClauses: DeleteClause...) -> Int? { public func fetchObjectIDs<T: DynamicObject>(_ from: From<T>, _ fetchClauses: [FetchClause]) -> [NSManagedObjectID]? {
CoreStore.assert( CoreStore.assert(
self.isRunningInAllowedQueue(), self.isRunningInAllowedQueue(),
"Attempted to delete from a \(cs_typeName(self)) outside its designated queue." "Attempted to fetch from a \(cs_typeName(self)) outside its designated queue."
) )
return self.context.fetchObjectIDs(from, fetchClauses)
return self.context.deleteAll(from, deleteClauses)
} }
/**
Deletes all `NSManagedObject`s that satisfy the specified `DeleteClause`s. Accepts `Where`, `OrderBy`, and `Tweak` clauses. // MARK: QueryableSource
- 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 `NSManagedObject`s deleted
*/
public func deleteAll<T: NSManagedObject>(from: From<T>, _ deleteClauses: [DeleteClause]) -> Int? {
CoreStore.assert(
self.isRunningInAllowedQueue(),
"Attempted to delete from a \(cs_typeName(self)) outside its designated queue."
)
return self.context.deleteAll(from, deleteClauses)
}
/** /**
Queries aggregate values as specified by the `QueryClause`s. Requires at least a `Select` clause, and optional `Where`, `OrderBy`, `GroupBy`, and `Tweak` clauses. Queries aggregate values as specified by the `QueryClause`s. Requires at least a `Select` clause, and optional `Where`, `OrderBy`, `GroupBy`, and `Tweak` clauses.
@@ -288,14 +287,12 @@ public extension BaseDataTransaction {
- parameter queryClauses: a series of `QueryClause` instances for the query request. Accepts `Where`, `OrderBy`, `GroupBy`, and `Tweak` clauses. - 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. - returns: the result of the the query. The type of the return value is specified by the generic type of the `Select<U>` parameter.
*/ */
@warn_unused_result public func queryValue<T: DynamicObject, U: QueryableAttributeType>(_ from: From<T>, _ selectClause: Select<U>, _ queryClauses: QueryClause...) -> U? {
public func queryValue<T: NSManagedObject, U: SelectValueResultType>(from: From<T>, _ selectClause: Select<U>, _ queryClauses: QueryClause...) -> U? {
CoreStore.assert( CoreStore.assert(
self.isRunningInAllowedQueue(), self.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.context.queryValue(from, selectClause, queryClauses) return self.context.queryValue(from, selectClause, queryClauses)
} }
@@ -309,14 +306,12 @@ public extension BaseDataTransaction {
- parameter queryClauses: a series of `QueryClause` instances for the query request. Accepts `Where`, `OrderBy`, `GroupBy`, and `Tweak` clauses. - 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. - returns: the result of the the query. The type of the return value is specified by the generic type of the `Select<U>` parameter.
*/ */
@warn_unused_result public func queryValue<T: DynamicObject, U: QueryableAttributeType>(_ from: From<T>, _ selectClause: Select<U>, _ queryClauses: [QueryClause]) -> U? {
public func queryValue<T: NSManagedObject, U: SelectValueResultType>(from: From<T>, _ selectClause: Select<U>, _ queryClauses: [QueryClause]) -> U? {
CoreStore.assert( CoreStore.assert(
self.isRunningInAllowedQueue(), self.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.context.queryValue(from, selectClause, queryClauses) return self.context.queryValue(from, selectClause, queryClauses)
} }
@@ -330,14 +325,12 @@ public extension BaseDataTransaction {
- parameter queryClauses: a series of `QueryClause` instances for the query request. Accepts `Where`, `OrderBy`, `GroupBy`, and `Tweak` clauses. - 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. - returns: the result of the the query. The type of the return value is specified by the generic type of the `Select<U>` parameter.
*/ */
@warn_unused_result public func queryAttributes<T: DynamicObject>(_ from: From<T>, _ selectClause: Select<NSDictionary>, _ queryClauses: QueryClause...) -> [[String: Any]]? {
public func queryAttributes<T: NSManagedObject>(from: From<T>, _ selectClause: Select<NSDictionary>, _ queryClauses: QueryClause...) -> [[NSString: AnyObject]]? {
CoreStore.assert( CoreStore.assert(
self.isRunningInAllowedQueue(), self.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.context.queryAttributes(from, selectClause, queryClauses) return self.context.queryAttributes(from, selectClause, queryClauses)
} }
@@ -351,14 +344,32 @@ public extension BaseDataTransaction {
- parameter queryClauses: a series of `QueryClause` instances for the query request. Accepts `Where`, `OrderBy`, `GroupBy`, and `Tweak` clauses. - 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. - returns: the result of the the query. The type of the return value is specified by the generic type of the `Select<U>` parameter.
*/ */
@warn_unused_result public func queryAttributes<T: DynamicObject>(_ from: From<T>, _ selectClause: Select<NSDictionary>, _ queryClauses: [QueryClause]) -> [[String: Any]]? {
public func queryAttributes<T: NSManagedObject>(from: From<T>, _ selectClause: Select<NSDictionary>, _ queryClauses: [QueryClause]) -> [[NSString: AnyObject]]? {
CoreStore.assert( CoreStore.assert(
self.isRunningInAllowedQueue(), self.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.context.queryAttributes(from, selectClause, queryClauses) return self.context.queryAttributes(from, selectClause, 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

@@ -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<T: DynamicObject>(_ into: Into<T>) -> T {
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.")
@@ -118,8 +121,7 @@ public /*abstract*/ class BaseDataTransaction {
- parameter object: the `NSManagedObject` type to be edited - parameter object: the `NSManagedObject` type to be edited
- returns: an editable proxy for the specified `NSManagedObject`. - returns: an editable proxy for the specified `NSManagedObject`.
*/ */
@warn_unused_result public func edit<T: DynamicObject>(_ object: T?) -> T? {
public func edit<T: NSManagedObject>(object: T?) -> T? {
CoreStore.assert( CoreStore.assert(
self.isRunningInAllowedQueue(), self.isRunningInAllowedQueue(),
@@ -139,19 +141,18 @@ public /*abstract*/ class BaseDataTransaction {
- 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`.
*/ */
@warn_unused_result public func edit<T: DynamicObject>(_ into: Into<T>, _ objectID: NSManagedObjectID) -> T? {
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)
} }
/** /**
@@ -159,17 +160,16 @@ public /*abstract*/ class BaseDataTransaction {
- parameter object: the `NSManagedObject` to be deleted - parameter object: the `NSManagedObject` to be deleted
*/ */
public func delete(object: NSManagedObject?) { public func delete<T: DynamicObject>(_ object: T?) {
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()
} }
/** /**
@@ -179,7 +179,7 @@ public /*abstract*/ class BaseDataTransaction {
- parameter object2: another `NSManagedObject` to be deleted - parameter object2: another `NSManagedObject` to be deleted
- parameter objects: other `NSManagedObject`s to be deleted - parameter objects: other `NSManagedObject`s to be deleted
*/ */
public func delete(object1: NSManagedObject?, _ object2: NSManagedObject?, _ objects: NSManagedObject?...) { public func delete<T: DynamicObject>(_ object1: T?, _ object2: T?, _ objects: T?...) {
self.delete(([object1, object2] + objects).flatMap { $0 }) self.delete(([object1, object2] + objects).flatMap { $0 })
} }
@@ -189,15 +189,14 @@ public /*abstract*/ class BaseDataTransaction {
- parameter objects: the `NSManagedObject`s to be deleted - parameter objects: the `NSManagedObject`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<T: DynamicObject>(_ entity: T.Type) -> Set<T> {
public func insertedObjects<T: NSManagedObject>(entity: T.Type) -> Set<T> {
CoreStore.assert( CoreStore.assert(
self.transactionQueue.isCurrentExecutionContext(), self.transactionQueue.cs_isCurrentExecutionContext(),
"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.flatMap({ 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.transactionQueue.cs_isCurrentExecutionContext(),
"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<T: DynamicObject>(_ entity: T.Type) -> Set<NSManagedObjectID> {
public func insertedObjectIDs<T: NSManagedObject>(entity: T.Type) -> Set<NSManagedObjectID> {
CoreStore.assert( CoreStore.assert(
self.transactionQueue.isCurrentExecutionContext(), self.transactionQueue.cs_isCurrentExecutionContext(),
"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.flatMap({ 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<T: DynamicObject>(_ entity: T.Type) -> Set<T> {
public func updatedObjects() -> Set<NSManagedObject> {
CoreStore.assert( CoreStore.assert(
self.transactionQueue.isCurrentExecutionContext(), self.transactionQueue.cs_isCurrentExecutionContext(),
"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.flatMap({ 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.transactionQueue.cs_isCurrentExecutionContext(),
"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<T: DynamicObject>(_ entity: T.Type) -> Set<NSManagedObjectID> {
public func updatedObjectIDs<T: NSManagedObject>(entity: T.Type) -> Set<NSManagedObjectID> {
CoreStore.assert( CoreStore.assert(
self.transactionQueue.isCurrentExecutionContext(), self.transactionQueue.cs_isCurrentExecutionContext(),
"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.flatMap({ 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<T: DynamicObject>(_ entity: T.Type) -> Set<T> {
public func deletedObjects() -> Set<NSManagedObject> {
CoreStore.assert( CoreStore.assert(
self.transactionQueue.isCurrentExecutionContext(), self.transactionQueue.cs_isCurrentExecutionContext(),
"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.flatMap({ 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.transactionQueue.cs_isCurrentExecutionContext(),
"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<T: DynamicObject>(_ entity: T.Type) -> Set<NSManagedObjectID> {
public func deletedObjectIDs<T: NSManagedObject>(entity: T.Type) -> Set<NSManagedObjectID> {
CoreStore.assert( CoreStore.assert(
self.transactionQueue.isCurrentExecutionContext(), self.transactionQueue.cs_isCurrentExecutionContext(),
"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.flatMap({ 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,64 @@ 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()
}
// 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

@@ -40,31 +40,26 @@ public final class CSAsynchronousDataTransaction: CSBaseDataTransaction {
/** /**
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 { (result) in
completion?(result: result.bridgeToObjectiveC) switch result {
}
}
/**
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) case (_, nil): success?()
case (_, let error?): failure?(error.bridgeToObjectiveC)
} }
} }
} }
@@ -74,7 +69,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 +82,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 +94,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 +107,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 +118,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 +129,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,7 +137,7 @@ public final class CSAsynchronousDataTransaction: CSBaseDataTransaction {
// MARK: CoreStoreObjectiveCType // MARK: CoreStoreObjectiveCType
internal typealias SwiftType = AsynchronousDataTransaction public typealias SwiftType = AsynchronousDataTransaction
public override var bridgeToSwift: AsynchronousDataTransaction { public override var bridgeToSwift: AsynchronousDataTransaction {
@@ -153,21 +146,59 @@ public final class CSAsynchronousDataTransaction: CSBaseDataTransaction {
public required init(_ swiftValue: AsynchronousDataTransaction) { public required init(_ swiftValue: AsynchronousDataTransaction) {
super.init(swiftValue) super.init(swiftValue as BaseDataTransaction)
} }
public required init(_ swiftValue: BaseDataTransaction) { public required init(_ swiftValue: BaseDataTransaction) {
fatalError("init(_:) requires an AsynchronousDataTransaction instance") super.init(swiftValue as! AsynchronousDataTransaction)
}
// MARK: Deprecated
@available(*, deprecated, message: "Use the new -[CSAsynchronousDataTransaction commitWithSuccess:failure:] method.")
@objc
public func commitWithCompletion(_ completion: ((_ result: CSSaveResult) -> Void)?) {
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

@@ -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.bridgeToSwift.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.bridgeToSwift.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.bridgeToSwift.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.bridgeToSwift.context.fetchExisting(objectIDs) as [NSManagedObject]
} }
/** /**
@@ -105,8 +87,7 @@ 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.bridgeToSwift.isRunningInAllowedQueue(),
@@ -123,8 +104,7 @@ 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.bridgeToSwift.isRunningInAllowedQueue(),
@@ -141,14 +121,15 @@ 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.bridgeToSwift.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 self.bridgeToSwift.context
.fetchCount(from, fetchClauses)
.flatMap { NSNumber(value: $0) }
} }
/** /**
@@ -159,8 +140,7 @@ 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.bridgeToSwift.isRunningInAllowedQueue(),
@@ -180,8 +160,7 @@ 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.bridgeToSwift.isRunningInAllowedQueue(),
@@ -201,8 +180,7 @@ 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.bridgeToSwift.isRunningInAllowedQueue(),

View File

@@ -55,7 +55,7 @@ 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.bridgeToSwift.create(into.bridgeToSwift)
} }
@@ -67,8 +67,7 @@ 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.bridgeToSwift.edit(object)
} }
@@ -81,8 +80,7 @@ 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.bridgeToSwift.edit(into.bridgeToSwift, objectID)
} }
@@ -93,7 +91,7 @@ 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.bridgeToSwift.delete(object)
} }
@@ -104,7 +102,7 @@ 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.bridgeToSwift.delete(objects)
} }
@@ -121,18 +119,6 @@ public class CSBaseDataTransaction: NSObject, CoreStoreObjectiveCType {
// 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,8 +126,7 @@ 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.bridgeToSwift.insertedObjects(entity)
} }
@@ -152,7 +137,6 @@ 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.bridgeToSwift.insertedObjectIDs()
@@ -165,24 +149,11 @@ 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.bridgeToSwift.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()
}
/** /**
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. 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.
@@ -190,8 +161,7 @@ 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.bridgeToSwift.updatedObjects(entity)
} }
@@ -202,7 +172,6 @@ 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.bridgeToSwift.updatedObjectIDs()
@@ -215,24 +184,11 @@ 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.bridgeToSwift.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()
}
/** /**
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. 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.
@@ -240,8 +196,7 @@ 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.bridgeToSwift.deletedObjects(entity)
} }
@@ -249,11 +204,9 @@ public class CSBaseDataTransaction: NSObject, CoreStoreObjectiveCType {
/** /**
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.bridgeToSwift.deletedObjectIDs()
@@ -266,8 +219,7 @@ 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.bridgeToSwift.deletedObjectIDs(entity)
} }
@@ -280,7 +232,7 @@ public class CSBaseDataTransaction: NSObject, CoreStoreObjectiveCType {
return ObjectIdentifier(self.bridgeToSwift).hashValue return ObjectIdentifier(self.bridgeToSwift).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 {
@@ -292,8 +244,6 @@ public class CSBaseDataTransaction: NSObject, CoreStoreObjectiveCType {
// MARK: CoreStoreObjectiveCType // MARK: CoreStoreObjectiveCType
public typealias SwiftType = BaseDataTransaction
public required init(_ swiftValue: BaseDataTransaction) { public required init(_ swiftValue: BaseDataTransaction) {
self.swiftTransaction = swiftValue self.swiftTransaction = swiftValue
@@ -309,14 +259,28 @@ public class CSBaseDataTransaction: NSObject, CoreStoreObjectiveCType {
// MARK: Private // MARK: Private
private let swiftTransaction: BaseDataTransaction private let swiftTransaction: BaseDataTransaction
}
// MARK: - BaseDataTransaction
extension BaseDataTransaction: CoreStoreSwiftType {
// MARK: CoreStoreSwiftType
public typealias ObjectiveCType = CSBaseDataTransaction // MARK: Deprecated
@available(*, deprecated, message: "Use -[insertedObjectsOfType:] and pass the specific entity class")
@objc
public func insertedObjects() -> Set<NSManagedObject> {
return self.bridgeToSwift.insertedObjects()
}
@available(*, deprecated, message: "Use -[updatedObjectsOfType:] and pass the specific entity class")
@objc
public func updatedObjects() -> Set<NSManagedObject> {
return self.bridgeToSwift.updatedObjects()
}
@available(*, deprecated, message: "Use -[deletedObjectsOfType:] and pass the specific entity class")
@objc
public func deletedObjects() -> Set<NSManagedObject> {
return self.bridgeToSwift.deletedObjects()
}
} }

View File

@@ -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

@@ -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

@@ -27,10 +27,9 @@ import Foundation
import CoreData import CoreData
#if os(iOS) || os(watchOS) || os(tvOS)
// MARK: - CSCoreStore // MARK: - CSCoreStore
@available(OSX 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

@@ -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)
} }

View File

@@ -44,30 +44,18 @@ public extension CSCoreStore {
Returns the entity name-to-class type mapping from the `defaultStack`'s model. Returns the entity name-to-class type mapping from the `defaultStack`'s model.
*/ */
@objc @objc
public static var entityClassesByName: [String: NSManagedObject.Type] { public static func entityTypesByNameForType(_ type: NSManagedObject.Type) -> [EntityName: NSManagedObject.Type] {
return CoreStore.entityTypesByName return CoreStore.entityTypesByName(for: type)
}
/**
Returns the entity class for the given entity name from the `defaultStack`'s model.
- parameter name: the entity name
- returns: the `NSManagedObject` class for the given entity name, or `nil` if not found
*/
@objc
public static func entityClassWithName(name: String) -> NSManagedObject.Type? {
return CoreStore.entityTypesByName[name]
} }
/** /**
Returns the `NSEntityDescription` for the specified `NSManagedObject` subclass from `defaultStack`'s model. Returns the `NSEntityDescription` for the specified `NSManagedObject` subclass from `defaultStack`'s model.
*/ */
@objc @objc
public static func entityDescriptionForClass(type: NSManagedObject.Type) -> NSEntityDescription? { public static func entityDescriptionForClass(_ type: NSManagedObject.Type) -> NSEntityDescription? {
return CoreStore.entityDescriptionForType(type) return CoreStore.entityDescription(for: type)
} }
/** /**
@@ -75,12 +63,12 @@ public extension CSCoreStore {
``` ```
CSSQLiteStore *storage = [CSCoreStore addInMemoryStorageAndWaitAndReturnError:&error]; CSSQLiteStore *storage = [CSCoreStore addInMemoryStorageAndWaitAndReturnError:&error];
``` ```
- 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: the `CSInMemoryStore` added to the `defaultStack` - returns: the `CSInMemoryStore` added to the `defaultStack`
*/ */
@objc @objc
public static func addInMemoryStorageAndWaitAndReturnError(error: NSErrorPointer) -> CSInMemoryStore? { @discardableResult
public static func addInMemoryStorageAndWaitAndReturnError(_ error: NSErrorPointer) -> CSInMemoryStore? {
return self.defaultStack.addInMemoryStorageAndWaitAndReturnError(error) return self.defaultStack.addInMemoryStorageAndWaitAndReturnError(error)
} }
@@ -90,12 +78,12 @@ public extension CSCoreStore {
``` ```
CSSQLiteStore *storage = [CSCoreStore addSQLiteStorageAndWaitAndReturnError:&error]; CSSQLiteStore *storage = [CSCoreStore addSQLiteStorageAndWaitAndReturnError:&error];
``` ```
- 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: the `CSSQLiteStore` added to the `defaultStack` - returns: the `CSSQLiteStore` added to the `defaultStack`
*/ */
@objc @objc
public static func addSQLiteStorageAndWaitAndReturnError(error: NSErrorPointer) -> CSSQLiteStore? { @discardableResult
public static func addSQLiteStorageAndWaitAndReturnError(_ error: NSErrorPointer) -> CSSQLiteStore? {
return self.defaultStack.addSQLiteStorageAndWaitAndReturnError(error) return self.defaultStack.addSQLiteStorageAndWaitAndReturnError(error)
} }
@@ -108,13 +96,13 @@ public extension CSCoreStore {
addStorageAndWait: [[CSInMemoryStore alloc] initWithConfiguration: @"Config1"] addStorageAndWait: [[CSInMemoryStore alloc] initWithConfiguration: @"Config1"]
error: &error]; error: &error];
``` ```
- parameter storage: the `CSInMemoryStore` - parameter storage: the `CSInMemoryStore`
- 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: the `CSInMemoryStore` added to the `defaultStack` - returns: the `CSInMemoryStore` added to the `defaultStack`
*/ */
@objc @objc
public static func addInMemoryStorageAndWait(storage: CSInMemoryStore, error: NSErrorPointer) -> CSInMemoryStore? { @discardableResult
public static func addInMemoryStorageAndWait(_ storage: CSInMemoryStore, error: NSErrorPointer) -> CSInMemoryStore? {
return self.defaultStack.addInMemoryStorageAndWait(storage, error: error) return self.defaultStack.addInMemoryStorageAndWait(storage, error: error)
} }
@@ -127,14 +115,31 @@ public extension CSCoreStore {
addStorageAndWait: [[CSSQLiteStore alloc] initWithConfiguration: @"Config1"] addStorageAndWait: [[CSSQLiteStore alloc] initWithConfiguration: @"Config1"]
error: &error]; error: &error];
``` ```
- parameter storage: the `CSSQLiteStore` - parameter storage: the `CSSQLiteStore`
- 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: the `CSSQLiteStore` added to the `defaultStack` - returns: the `CSSQLiteStore` added to the `defaultStack`
*/ */
@objc @objc
public static func addSQLiteStorageAndWait(storage: CSSQLiteStore, error: NSErrorPointer) -> CSSQLiteStore? { @discardableResult
public static func addSQLiteStorageAndWait(_ storage: CSSQLiteStore, error: NSErrorPointer) -> CSSQLiteStore? {
return self.defaultStack.addSQLiteStorageAndWait(storage, error: error) return self.defaultStack.addSQLiteStorageAndWait(storage, error: error)
} }
}
// MARK: Deprecated
@available(*, deprecated, message: "Use the new +entityTypesByNameForType: method passing `[NSManagedObject class]` as argument.")
@objc
public static var entityClassesByName: [EntityName: NSManagedObject.Type] {
return CoreStore.entityTypesByName
}
@available(*, deprecated, message: "Use the new +entityTypesByNameForType: method passing `[NSManagedObject class]` as argument.")
@objc
public static func entityClassWithName(_ name: EntityName) -> NSManagedObject.Type? {
return CoreStore.entityTypesByName[name]
}
}

View File

@@ -36,12 +36,9 @@ public extension CSCoreStore {
- 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`. - 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`.
*/ */
@objc @objc
public static func beginAsynchronous(closure: (transaction: CSAsynchronousDataTransaction) -> Void) { public static func beginAsynchronous(_ closure: @escaping (_ transaction: CSAsynchronousDataTransaction) -> Void) {
return CoreStore.beginAsynchronous { (transaction) in self.defaultStack.beginAsynchronous(closure)
closure(transaction: transaction.bridgeToObjectiveC)
}
} }
/** /**
@@ -51,15 +48,9 @@ public extension CSCoreStore {
- returns: a `CSSaveResult` value indicating success or failure, or `nil` if the transaction was not comitted synchronously - returns: a `CSSaveResult` value indicating success or failure, or `nil` if the transaction was not comitted synchronously
*/ */
@objc @objc
public static func beginSynchronous(closure: (transaction: CSSynchronousDataTransaction) -> Void) -> CSSaveResult? { public static func beginSynchronous(_ closure: @escaping (_ transaction: CSSynchronousDataTransaction) -> Void, error: NSErrorPointer) -> Bool {
return bridge { return self.defaultStack.beginSynchronous(closure, error: error)
CoreStore.beginSynchronous { (transaction) in
closure(transaction: transaction.bridgeToObjectiveC)
}
}
} }
/** /**
@@ -69,7 +60,6 @@ public extension CSCoreStore {
- returns: a `CSUnsafeDataTransaction` instance where creates, updates, and deletes can be made. - returns: a `CSUnsafeDataTransaction` instance where creates, updates, and deletes can be made.
*/ */
@objc @objc
@warn_unused_result
public static func beginUnsafe() -> CSUnsafeDataTransaction { public static func beginUnsafe() -> CSUnsafeDataTransaction {
return bridge { return bridge {
@@ -85,8 +75,7 @@ public extension CSCoreStore {
- returns: a `CSUnsafeDataTransaction` instance where creates, updates, and deletes can be made. - returns: a `CSUnsafeDataTransaction` instance where creates, updates, and deletes can be made.
*/ */
@objc @objc
@warn_unused_result public static func beginUnsafeWithSupportsUndo(_ supportsUndo: Bool) -> CSUnsafeDataTransaction {
public static func beginUnsafeWithSupportsUndo(supportsUndo: Bool) -> CSUnsafeDataTransaction {
return bridge { return bridge {
@@ -102,4 +91,15 @@ public extension CSCoreStore {
CoreStore.refreshAndMergeAllObjects() CoreStore.refreshAndMergeAllObjects()
} }
// MARK: Deprecated
@available(*, deprecated, message: "Use the new +[CSCoreStore beginSynchronous:error:] API that reports failure using an error instance.")
@objc
@discardableResult
public static func beginSynchronous(_ closure: @escaping (_ transaction: CSSynchronousDataTransaction) -> Void) -> CSSaveResult? {
return self.defaultStack.beginSynchronous(closure)
}
} }

View File

@@ -44,12 +44,11 @@ public extension CSDataStack {
} }
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.
*/ */
@objc @objc
public func addInMemoryStorage(storage: CSInMemoryStore, completion: (CSSetupResult) -> Void) { public func addInMemoryStorage(_ storage: CSInMemoryStore, completion: @escaping (CSSetupResult) -> Void) {
self.bridgeToSwift.addStorage( self.bridgeToSwift.addStorage(
storage.bridgeToSwift, storage.bridgeToSwift,
@@ -72,14 +71,13 @@ public extension CSDataStack {
} }
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.
*/ */
@objc @objc
public func addSQLiteStorage(storage: CSSQLiteStore, completion: (CSSetupResult) -> Void, error: NSErrorPointer) -> NSProgress? { public func addSQLiteStorage(_ storage: CSSQLiteStore, completion: @escaping (CSSetupResult) -> Void, error: NSErrorPointer) -> Progress? {
return bridge(error) { return bridge(error) {
@@ -99,7 +97,7 @@ public extension CSDataStack {
- 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 func upgradeStorageIfNeeded(storage: CSSQLiteStore, completion: (CSMigrationResult) -> Void, error: NSErrorPointer) -> NSProgress? { public func upgradeStorageIfNeeded(_ storage: CSSQLiteStore, completion: @escaping (CSMigrationResult) -> Void, error: NSErrorPointer) -> Progress? {
return bridge(error) { return bridge(error) {
@@ -118,12 +116,11 @@ public extension CSDataStack {
- 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 func requiredMigrationsForSQLiteStore(_ storage: CSSQLiteStore, error: NSErrorPointer) -> [CSMigrationType]? {
public func requiredMigrationsForSQLiteStore(storage: CSSQLiteStore, error: NSErrorPointer) -> [CSMigrationType]? {
return bridge(error) { return bridge(error) {
try self.bridgeToSwift.requiredMigrationsForStorage(storage.bridgeToSwift) try self.bridgeToSwift.requiredMigrationsForStorage(storage.bridgeToSwift)
} }
} }
} }

View File

@@ -27,10 +27,9 @@ import Foundation
import CoreData import CoreData
#if os(iOS) || os(watchOS) || os(tvOS)
// MARK: - CSDataStack // MARK: - CSDataStack
@available(OSX 10.12, *)
public extension CSDataStack { public extension CSDataStack {
/** /**
@@ -40,13 +39,9 @@ public extension CSDataStack {
- returns: a `ObjectMonitor` that monitors changes to `object` - returns: a `ObjectMonitor` that monitors changes to `object`
*/ */
@objc @objc
@warn_unused_result public func monitorObject(_ object: NSManagedObject) -> CSObjectMonitor {
public func monitorObject(object: NSManagedObject) -> CSObjectMonitor {
return bridge { return self.bridgeToSwift.monitorObject(object).bridgeToObjectiveC
self.bridgeToSwift.monitorObject(object)
}
} }
/** /**
@@ -57,29 +52,25 @@ public extension CSDataStack {
- 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 func monitorListFrom(_ from: CSFrom, fetchClauses: [CSFetchClause]) -> CSListMonitor {
public func monitorListFrom(from: CSFrom, fetchClauses: [CSFetchClause]) -> CSListMonitor {
CoreStore.assert( CoreStore.assert(
NSThread.isMainThread(), Thread.isMainThread,
"Attempted to observe objects from \(cs_typeName(self)) outside the main thread." "Attempted to observe objects from \(cs_typeName(self)) outside the main thread."
) )
CoreStore.assert( CoreStore.assert(
fetchClauses.contains { $0 is CSOrderBy }, fetchClauses.contains { $0 is CSOrderBy },
"A CSListMonitor requires a CSOrderBy clause." "A CSListMonitor requires a CSOrderBy clause."
) )
return bridge { return ListMonitor(
dataStack: self.bridgeToSwift,
ListMonitor( from: from.bridgeToSwift,
dataStack: self.bridgeToSwift, sectionBy: nil,
from: from.bridgeToSwift, applyFetchClauses: { (fetchRequest) in
sectionBy: nil,
applyFetchClauses: { fetchRequest in fetchClauses.forEach { $0.applyToFetchRequest(fetchRequest as! NSFetchRequest<NSFetchRequestResult>) }
}
fetchClauses.forEach { $0.applyToFetchRequest(fetchRequest) } ).bridgeToObjectiveC
}
)
}
} }
/** /**
@@ -90,10 +81,10 @@ public extension CSDataStack {
- 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 func monitorListByCreatingAsynchronously(createAsynchronously: (CSListMonitor) -> Void, from: CSFrom, fetchClauses: [CSFetchClause]) { public func monitorListByCreatingAsynchronously(_ createAsynchronously: @escaping (CSListMonitor) -> Void, from: CSFrom, fetchClauses: [CSFetchClause]) {
CoreStore.assert( CoreStore.assert(
NSThread.isMainThread(), Thread.isMainThread,
"Attempted to observe objects from \(cs_typeName(self)) outside the main thread." "Attempted to observe objects from \(cs_typeName(self)) outside the main thread."
) )
CoreStore.assert( CoreStore.assert(
@@ -104,9 +95,9 @@ public extension CSDataStack {
dataStack: self.bridgeToSwift, dataStack: self.bridgeToSwift,
from: from.bridgeToSwift, from: from.bridgeToSwift,
sectionBy: nil, sectionBy: nil,
applyFetchClauses: { fetchRequest in applyFetchClauses: { (fetchRequest) in
fetchClauses.forEach { $0.applyToFetchRequest(fetchRequest) } fetchClauses.forEach { $0.applyToFetchRequest(fetchRequest as! NSFetchRequest<NSFetchRequestResult>) }
}, },
createAsynchronously: { createAsynchronously: {
@@ -124,29 +115,25 @@ public extension CSDataStack {
- 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 func monitorSectionedListFrom(_ from: CSFrom, sectionBy: CSSectionBy, fetchClauses: [CSFetchClause]) -> CSListMonitor {
public func monitorSectionedListFrom(from: CSFrom, sectionBy: CSSectionBy, fetchClauses: [CSFetchClause]) -> CSListMonitor {
CoreStore.assert( CoreStore.assert(
NSThread.isMainThread(), Thread.isMainThread,
"Attempted to observe objects from \(cs_typeName(self)) outside the main thread." "Attempted to observe objects from \(cs_typeName(self)) outside the main thread."
) )
CoreStore.assert( CoreStore.assert(
fetchClauses.contains { $0 is CSOrderBy }, fetchClauses.contains { $0 is CSOrderBy },
"A CSListMonitor requires an CSOrderBy clause." "A CSListMonitor requires an CSOrderBy clause."
) )
return bridge { return ListMonitor(
dataStack: self.bridgeToSwift,
ListMonitor( from: from.bridgeToSwift,
dataStack: self.bridgeToSwift, sectionBy: sectionBy.bridgeToSwift,
from: from.bridgeToSwift, applyFetchClauses: { (fetchRequest) in
sectionBy: sectionBy.bridgeToSwift,
applyFetchClauses: { fetchRequest in fetchClauses.forEach { $0.applyToFetchRequest(fetchRequest as! NSFetchRequest<NSFetchRequestResult>) }
}
fetchClauses.forEach { $0.applyToFetchRequest(fetchRequest) } ).bridgeToObjectiveC
}
)
}
} }
/** /**
@@ -157,10 +144,10 @@ public extension CSDataStack {
- parameter sectionBy: a `CSSectionBy` clause indicating the keyPath for the attribute to use when sorting the list into sections. - parameter sectionBy: a `CSSectionBy` clause indicating the keyPath for the attribute to use when sorting the list into sections.
- 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.
*/ */
public func monitorSectionedListByCreatingAsynchronously(createAsynchronously: (CSListMonitor) -> Void, from: CSFrom, sectionBy: CSSectionBy, fetchClauses: [CSFetchClause]) { public func monitorSectionedListByCreatingAsynchronously(_ createAsynchronously: @escaping (CSListMonitor) -> Void, from: CSFrom, sectionBy: CSSectionBy, fetchClauses: [CSFetchClause]) {
CoreStore.assert( CoreStore.assert(
NSThread.isMainThread(), Thread.isMainThread,
"Attempted to observe objects from \(cs_typeName(self)) outside the main thread." "Attempted to observe objects from \(cs_typeName(self)) outside the main thread."
) )
CoreStore.assert( CoreStore.assert(
@@ -171,9 +158,9 @@ public extension CSDataStack {
dataStack: self.bridgeToSwift, dataStack: self.bridgeToSwift,
from: from.bridgeToSwift, from: from.bridgeToSwift,
sectionBy: sectionBy.bridgeToSwift, sectionBy: sectionBy.bridgeToSwift,
applyFetchClauses: { fetchRequest in applyFetchClauses: { (fetchRequest) in
fetchClauses.forEach { $0.applyToFetchRequest(fetchRequest) } fetchClauses.forEach { $0.applyToFetchRequest(fetchRequest as! NSFetchRequest<NSFetchRequestResult>) }
}, },
createAsynchronously: { createAsynchronously: {
@@ -182,5 +169,3 @@ public extension CSDataStack {
) )
} }
} }
#endif

View File

@@ -38,17 +38,9 @@ public extension CSDataStack {
- 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.bridgeToSwift.mainContext.fetchExisting(object) as NSManagedObject?
return try self.bridgeToSwift.mainContext.existingObjectWithID(object.objectID)
}
catch _ {
return nil
}
} }
/** /**
@@ -58,17 +50,9 @@ public extension CSDataStack {
- 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.bridgeToSwift.mainContext.fetchExisting(objectID) as NSManagedObject?
return try self.bridgeToSwift.mainContext.existingObjectWithID(objectID)
}
catch _ {
return nil
}
} }
/** /**
@@ -78,10 +62,9 @@ public extension CSDataStack {
- 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.mainContext.existingObjectWithID($0.objectID) } return self.bridgeToSwift.mainContext.fetchExisting(objects) as [NSManagedObject]
} }
/** /**
@@ -91,10 +74,9 @@ public extension CSDataStack {
- 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.mainContext.existingObjectWithID($0) } return self.bridgeToSwift.mainContext.fetchExisting(objectIDs) as [NSManagedObject]
} }
/** /**
@@ -105,11 +87,10 @@ public extension CSDataStack {
- 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(
NSThread.isMainThread(), Thread.isMainThread,
"Attempted to fetch from a \(cs_typeName(self)) outside the main thread." "Attempted to fetch from a \(cs_typeName(self)) outside the main thread."
) )
return self.bridgeToSwift.mainContext.fetchOne(from, fetchClauses) return self.bridgeToSwift.mainContext.fetchOne(from, fetchClauses)
@@ -123,11 +104,10 @@ public extension CSDataStack {
- 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(
NSThread.isMainThread(), Thread.isMainThread,
"Attempted to fetch from a \(cs_typeName(self)) outside the main thread." "Attempted to fetch from a \(cs_typeName(self)) outside the main thread."
) )
return self.bridgeToSwift.mainContext.fetchAll(from, fetchClauses) return self.bridgeToSwift.mainContext.fetchAll(from, fetchClauses)
@@ -141,14 +121,15 @@ public extension CSDataStack {
- 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(
NSThread.isMainThread(), Thread.isMainThread,
"Attempted to fetch from a \(cs_typeName(self)) outside the main thread." "Attempted to fetch from a \(cs_typeName(self)) outside the main thread."
) )
return self.bridgeToSwift.mainContext.fetchCount(from, fetchClauses) return self.bridgeToSwift.mainContext
.fetchCount(from, fetchClauses)
.flatMap { NSNumber(value: $0) }
} }
/** /**
@@ -159,11 +140,10 @@ public extension CSDataStack {
- 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(
NSThread.isMainThread(), Thread.isMainThread,
"Attempted to fetch from a \(cs_typeName(self)) outside the main thread." "Attempted to fetch from a \(cs_typeName(self)) outside the main thread."
) )
return self.bridgeToSwift.mainContext.fetchObjectID(from, fetchClauses) return self.bridgeToSwift.mainContext.fetchObjectID(from, fetchClauses)
@@ -177,11 +157,10 @@ public extension CSDataStack {
- 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 func fetchObjectIDsFrom(_ from: CSFrom, fetchClauses: [CSFetchClause]) -> [NSManagedObjectID]? {
public func fetchObjectIDsFrom(from: CSFrom, fetchClauses: [CSFetchClause]) -> [NSManagedObjectID]? {
CoreStore.assert( CoreStore.assert(
NSThread.isMainThread(), Thread.isMainThread,
"Attempted to fetch from a \(cs_typeName(self)) outside the main thread." "Attempted to fetch from a \(cs_typeName(self)) outside the main thread."
) )
return self.bridgeToSwift.mainContext.fetchObjectIDs(from, fetchClauses) return self.bridgeToSwift.mainContext.fetchObjectIDs(from, fetchClauses)
@@ -198,11 +177,10 @@ public extension CSDataStack {
- 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(
NSThread.isMainThread(), Thread.isMainThread,
"Attempted to query from a \(cs_typeName(self)) outside the main thread." "Attempted to query from a \(cs_typeName(self)) outside the main thread."
) )
return self.bridgeToSwift.mainContext.queryValue(from, selectClause, queryClauses) return self.bridgeToSwift.mainContext.queryValue(from, selectClause, queryClauses)
@@ -219,11 +197,10 @@ public extension CSDataStack {
- 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(
NSThread.isMainThread(), Thread.isMainThread,
"Attempted to query from a \(cs_typeName(self)) outside the main thread." "Attempted to query from a \(cs_typeName(self)) outside the main thread."
) )
return self.bridgeToSwift.mainContext.queryAttributes(from, selectClause, queryClauses) return self.bridgeToSwift.mainContext.queryAttributes(from, selectClause, queryClauses)

View File

@@ -36,28 +36,59 @@ public extension CSDataStack {
- 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`. - 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`.
*/ */
@objc @objc
public func beginAsynchronous(closure: (transaction: CSAsynchronousDataTransaction) -> Void) { public func beginAsynchronous(_ closure: @escaping (_ transaction: CSAsynchronousDataTransaction) -> Void) {
return self.bridgeToSwift.beginAsynchronous { (transaction) in self.bridgeToSwift.perform(
asynchronous: { (transaction) in
closure(transaction: transaction.bridgeToObjectiveC)
} let csTransaction = transaction.bridgeToObjectiveC
closure(csTransaction)
if !transaction.isCommitted && transaction.hasChanges {
CoreStore.log(
.warning,
message: "The closure for the \(cs_typeName(csTransaction)) completed without being committed. All changes made within the transaction were discarded."
)
}
try transaction.cancel()
},
completion: { _ in }
)
} }
/** /**
Begins a transaction synchronously where `NSManagedObject` creates, updates, and deletes can be made. Begins a transaction synchronously where `NSManagedObject` creates, updates, and deletes can be made.
- 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`. - 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 - parameter error: the `CSError` pointer that indicates the reason in case of an failure
- returns: `YES` if the commit succeeded, `NO` if the commit failed. If `NO`, the `error` argument will hold error information.
*/ */
@objc @objc
public func beginSynchronous(closure: (transaction: CSSynchronousDataTransaction) -> Void) -> CSSaveResult? { public func beginSynchronous(_ closure: @escaping (_ transaction: CSSynchronousDataTransaction) -> Void, error: NSErrorPointer) -> Bool {
return bridge { return bridge(error) {
self.bridgeToSwift.beginSynchronous { (transaction) in do {
closure(transaction: transaction.bridgeToObjectiveC) try self.bridgeToSwift.perform(
synchronous: { (transaction) in
let csTransaction = transaction.bridgeToObjectiveC
closure(csTransaction)
if !transaction.isCommitted && transaction.hasChanges {
CoreStore.log(
.warning,
message: "The closure for the \(cs_typeName(csTransaction)) completed without being committed. All changes made within the transaction were discarded."
)
}
try transaction.cancel()
}
)
}
catch CoreStoreError.userCancelled {
return
} }
} }
} }
@@ -69,7 +100,6 @@ public extension CSDataStack {
- returns: a `CSUnsafeDataTransaction` instance where creates, updates, and deletes can be made. - returns: a `CSUnsafeDataTransaction` instance where creates, updates, and deletes can be made.
*/ */
@objc @objc
@warn_unused_result
public func beginUnsafe() -> CSUnsafeDataTransaction { public func beginUnsafe() -> CSUnsafeDataTransaction {
return bridge { return bridge {
@@ -85,8 +115,7 @@ public extension CSDataStack {
- returns: a `CSUnsafeDataTransaction` instance where creates, updates, and deletes can be made. - returns: a `CSUnsafeDataTransaction` instance where creates, updates, and deletes can be made.
*/ */
@objc @objc
@warn_unused_result public func beginUnsafeWithSupportsUndo(_ supportsUndo: Bool) -> CSUnsafeDataTransaction {
public func beginUnsafeWithSupportsUndo(supportsUndo: Bool) -> CSUnsafeDataTransaction {
return bridge { return bridge {
@@ -102,4 +131,21 @@ public extension CSDataStack {
self.bridgeToSwift.refreshAndMergeAllObjects() self.bridgeToSwift.refreshAndMergeAllObjects()
} }
// MARK: Deprecated
@available(*, deprecated, message: "Use the new -[CSDataStack beginSynchronous:error:] API that reports failure using an error instance.")
@objc
@discardableResult
public func beginSynchronous(_ closure: @escaping (_ transaction: CSSynchronousDataTransaction) -> Void) -> CSSaveResult? {
return bridge {
self.bridgeToSwift.beginSynchronous { (transaction) in
closure(transaction.bridgeToObjectiveC)
}
}
}
} }

View File

@@ -54,12 +54,12 @@ public final class CSDataStack: NSObject, CoreStoreObjectiveCType {
- parameter versionChain: the version strings that indicate the sequence of model versions to be used as the order for progressive migrations. If not specified, will default to a non-migrating data stack. - parameter versionChain: the version strings that indicate the sequence of model versions to be used as the order for progressive migrations. If not specified, will default to a non-migrating data stack.
*/ */
@objc @objc
public convenience init(modelName: String?, bundle: NSBundle?, versionChain: [String]?) { public convenience init(modelName: XcodeDataModelFileName?, bundle: Bundle?, versionChain: [String]?) {
self.init( self.init(
DataStack( DataStack(
modelName: modelName ?? DataStack.applicationName, modelName: modelName ?? DataStack.applicationName,
bundle: bundle ?? NSBundle.mainBundle(), bundle: bundle ?? Bundle.main,
migrationChain: versionChain.flatMap { MigrationChain($0) } ?? nil migrationChain: versionChain.flatMap { MigrationChain($0) } ?? nil
) )
) )
@@ -73,46 +73,12 @@ public final class CSDataStack: NSObject, CoreStoreObjectiveCType {
- parameter versionTree: the version strings that indicate the sequence of model versions to be used as the order for progressive migrations. If not specified, will default to a non-migrating data stack. - parameter versionTree: the version strings that indicate the sequence of model versions to be used as the order for progressive migrations. If not specified, will default to a non-migrating data stack.
*/ */
@objc @objc
public convenience init(modelName: String?, bundle: NSBundle?, versionTree: [String: String]?) { public convenience init(modelName: XcodeDataModelFileName?, bundle: Bundle?, versionTree: [String: String]?) {
self.init( self.init(
DataStack( DataStack(
modelName: modelName ?? DataStack.applicationName, modelName: modelName ?? DataStack.applicationName,
bundle: bundle ?? NSBundle.mainBundle(), bundle: bundle ?? Bundle.main,
migrationChain: versionTree.flatMap { MigrationChain($0) } ?? nil
)
)
}
/**
Initializes a `DataStack` from an `NSManagedObjectModel`.
- parameter model: the `NSManagedObjectModel` for the stack
- parameter versionChain: the `MigrationChain` that indicates the sequence of model versions to be used as the order for progressive migrations. If not specified, will default to a non-migrating data stack.
*/
@objc
public convenience init(model: NSManagedObjectModel, versionChain: [String]?) {
self.init(
DataStack(
model: model,
migrationChain: versionChain.flatMap { MigrationChain($0) } ?? nil
)
)
}
/**
Initializes a `DataStack` from an `NSManagedObjectModel`.
- parameter model: the `NSManagedObjectModel` for the stack
- parameter versionTree: the `MigrationChain` that indicates the sequence of model versions to be used as the order for progressive migrations. If not specified, will default to a non-migrating data stack.
*/
@objc
public convenience init(model: NSManagedObjectModel, versionTree: [String]?) {
self.init(
DataStack(
model: model,
migrationChain: versionTree.flatMap { MigrationChain($0) } ?? nil migrationChain: versionTree.flatMap { MigrationChain($0) } ?? nil
) )
) )
@@ -128,32 +94,21 @@ public final class CSDataStack: NSObject, CoreStoreObjectiveCType {
} }
/** /**
Returns the entity name-to-class type mapping from the stack's model. Returns the entity name-to-class type mapping from the `CSDataStack`'s model.
*/ */
@objc @objc
public var entityClassesByName: [String: NSManagedObject.Type] { public func entityTypesByNameForType(_ type: NSManagedObject.Type) -> [EntityName: NSManagedObject.Type] {
return self.bridgeToSwift.entityTypesByName return self.bridgeToSwift.entityTypesByName(for: type)
}
/**
Returns the entity class for the given entity name from the stack's's model.
- parameter name: the entity name
- returns: the `NSManagedObject` class for the given entity name, or `nil` if not found
*/
@objc
public func entityClassWithName(name: String) -> NSManagedObject.Type? {
return self.bridgeToSwift.entityTypesByName[name]
} }
/** /**
Returns the `NSEntityDescription` for the specified `NSManagedObject` subclass from stack's model. Returns the `NSEntityDescription` for the specified `NSManagedObject` subclass from stack's model.
*/ */
@objc @objc
public func entityDescriptionForClass(type: NSManagedObject.Type) -> NSEntityDescription? { public func entityDescriptionForClass(_ type: NSManagedObject.Type) -> NSEntityDescription? {
return self.bridgeToSwift.entityDescriptionForType(type) return self.bridgeToSwift.entityDescription(for: type)
} }
/** /**
@@ -161,16 +116,16 @@ public final class CSDataStack: NSObject, CoreStoreObjectiveCType {
``` ```
CSSQLiteStore *storage = [dataStack addInMemoryStorageAndWaitAndReturnError:&error]; CSSQLiteStore *storage = [dataStack addInMemoryStorageAndWaitAndReturnError:&error];
``` ```
- 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: the `CSInMemoryStore` added to the stack - returns: the `CSInMemoryStore` added to the stack
*/ */
@objc @objc
public func addInMemoryStorageAndWaitAndReturnError(error: NSErrorPointer) -> CSInMemoryStore? { @discardableResult
public func addInMemoryStorageAndWaitAndReturnError(_ error: NSErrorPointer) -> CSInMemoryStore? {
return bridge(error) { return bridge(error) {
try self.bridgeToSwift.addStorageAndWait(InMemoryStore) try self.bridgeToSwift.addStorageAndWait(InMemoryStore())
} }
} }
@@ -179,16 +134,16 @@ public final class CSDataStack: NSObject, CoreStoreObjectiveCType {
``` ```
CSSQLiteStore *storage = [dataStack addSQLiteStorageAndWaitAndReturnError:&error]; CSSQLiteStore *storage = [dataStack addSQLiteStorageAndWaitAndReturnError:&error];
``` ```
- 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: the `CSSQLiteStore` added to the stack - returns: the `CSSQLiteStore` added to the stack
*/ */
@objc @objc
public func addSQLiteStorageAndWaitAndReturnError(error: NSErrorPointer) -> CSSQLiteStore? { @discardableResult
public func addSQLiteStorageAndWaitAndReturnError(_ error: NSErrorPointer) -> CSSQLiteStore? {
return bridge(error) { return bridge(error) {
try self.bridgeToSwift.addStorageAndWait(SQLiteStore) try self.bridgeToSwift.addStorageAndWait(SQLiteStore())
} }
} }
@@ -200,13 +155,13 @@ public final class CSDataStack: NSObject, CoreStoreObjectiveCType {
addStorageAndWait: [[CSInMemoryStore alloc] initWithConfiguration: @"Config1"] addStorageAndWait: [[CSInMemoryStore alloc] initWithConfiguration: @"Config1"]
error: &error]; error: &error];
``` ```
- parameter storage: the `CSInMemoryStore` - parameter storage: the `CSInMemoryStore`
- 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: the `CSInMemoryStore` added to the stack - returns: the `CSInMemoryStore` added to the stack
*/ */
@objc @objc
public func addInMemoryStorageAndWait(storage: CSInMemoryStore, error: NSErrorPointer) -> CSInMemoryStore? { @discardableResult
public func addInMemoryStorageAndWait(_ storage: CSInMemoryStore, error: NSErrorPointer) -> CSInMemoryStore? {
return bridge(error) { return bridge(error) {
@@ -222,13 +177,13 @@ public final class CSDataStack: NSObject, CoreStoreObjectiveCType {
addStorageAndWait: [[CSSQLiteStore alloc] initWithConfiguration: @"Config1"] addStorageAndWait: [[CSSQLiteStore alloc] initWithConfiguration: @"Config1"]
error: &error]; error: &error];
``` ```
- parameter storage: the `CSSQLiteStore` - parameter storage: the `CSSQLiteStore`
- 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: the `CSSQLiteStore` added to the stack - returns: the `CSSQLiteStore` added to the stack
*/ */
@objc @objc
public func addSQLiteStorageAndWait(storage: CSSQLiteStore, error: NSErrorPointer) -> CSSQLiteStore? { @discardableResult
public func addSQLiteStorageAndWait(_ storage: CSSQLiteStore, error: NSErrorPointer) -> CSSQLiteStore? {
return bridge(error) { return bridge(error) {
@@ -244,7 +199,7 @@ public final class CSDataStack: NSObject, CoreStoreObjectiveCType {
return ObjectIdentifier(self.bridgeToSwift).hashValue return ObjectIdentifier(self.bridgeToSwift).hashValue
} }
public override func isEqual(object: AnyObject?) -> Bool { public override func isEqual(_ object: Any?) -> Bool {
guard let object = object as? CSDataStack else { guard let object = object as? CSDataStack else {
@@ -255,7 +210,7 @@ public final class CSDataStack: NSObject, CoreStoreObjectiveCType {
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)"
} }
@@ -268,6 +223,47 @@ public final class CSDataStack: NSObject, CoreStoreObjectiveCType {
self.bridgeToSwift = swiftValue self.bridgeToSwift = swiftValue
super.init() super.init()
} }
// MARK: Deprecated
@available(*, deprecated, message: "Use the -[initWithModelName:bundle:versionChain:] initializer.")
@objc
public convenience init(model: NSManagedObjectModel, versionChain: [String]?) {
self.init(
DataStack(
model: model,
migrationChain: versionChain.flatMap { MigrationChain($0) } ?? nil
)
)
}
@available(*, deprecated, message: "Use the -[initWithModelName:bundle:versionTree:] initializer.")
@objc
public convenience init(model: NSManagedObjectModel, versionTree: [String]?) {
self.init(
DataStack(
model: model,
migrationChain: versionTree.flatMap { MigrationChain($0) } ?? nil
)
)
}
@available(*, deprecated, message: "Use the new -entityTypesByNameForType: method passing `[NSManagedObject class]` as argument.")
@objc
public var entityClassesByName: [EntityName: NSManagedObject.Type] {
return self.bridgeToSwift.entityTypesByName
}
@available(*, deprecated, message: "Use the new -entityTypesByNameForType: method passing `[NSManagedObject class]` as argument.")
@objc
public func entityClassWithName(_ name: EntityName) -> NSManagedObject.Type? {
return self.bridgeToSwift.entityTypesByName[name]
}
} }
@@ -277,5 +273,8 @@ extension DataStack: CoreStoreSwiftType {
// MARK: CoreStoreSwiftType // MARK: CoreStoreSwiftType
public typealias ObjectiveCType = CSDataStack public var bridgeToObjectiveC: CSDataStack {
return CSDataStack(self)
}
} }

View File

@@ -0,0 +1,51 @@
//
// CSDynamicSchema.swift
// CoreStore
//
// Copyright © 2017 John Rommel Estropia
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in all
// copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
// SOFTWARE.
//
import CoreData
import Foundation
// MARK: - CSDynamicSchema
/**
The `CSDynamicSchema` serves as the Objective-C bridging type for `DynamicSchema`.
- SeeAlso: `DynamicSchema`
*/
@objc
public protocol CSDynamicSchema {
/**
The version string for this model schema.
*/
@objc
var modelVersion: ModelVersion { get }
/**
Do not call this directly. The `NSManagedObjectModel` for this schema may be created lazily and using this method directly may affect the integrity of the model.
*/
@objc
func rawModel() -> NSManagedObjectModel
}

View File

@@ -53,7 +53,7 @@ public final class CSError: NSError, CoreStoreObjectiveCType {
return self.bridgeToSwift.hashValue return self.bridgeToSwift.hashValue
} }
public override func isEqual(object: AnyObject?) -> Bool { public override func isEqual(_ object: Any?) -> Bool {
guard let object = object as? CSError else { guard let object = object as? CSError else {
@@ -64,7 +64,7 @@ public final class CSError: NSError, CoreStoreObjectiveCType {
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)"
} }
@@ -76,58 +76,7 @@ public final class CSError: NSError, CoreStoreObjectiveCType {
return swift return swift
} }
let swift = CoreStoreError(_bridgedNSError: self) ?? .unknown
func createSwiftObject(error: CSError) -> CoreStoreError {
guard error.domain == CoreStoreErrorDomain else {
return .InternalError(NSError: self)
}
guard let code = CoreStoreErrorCode(rawValue: error.code) else {
return .Unknown
}
let info = error.userInfo
switch code {
case .UnknownError:
return .Unknown
case .DifferentPersistentStoreExistsAtURL:
guard case let existingPersistentStoreURL as NSURL = info["existingPersistentStoreURL"] else {
return .Unknown
}
return .DifferentStorageExistsAtURL(existingPersistentStoreURL: existingPersistentStoreURL)
case .MappingModelNotFound:
guard let localStoreURL = info["localStoreURL"] as? NSURL,
let targetModel = info["targetModel"] as? NSManagedObjectModel,
let targetModelVersion = info["targetModelVersion"] as? String else {
return .Unknown
}
return .MappingModelNotFound(localStoreURL: localStoreURL, targetModel: targetModel, targetModelVersion: targetModelVersion)
case .ProgressiveMigrationRequired:
guard let localStoreURL = info["localStoreURL"] as? NSURL else {
return .Unknown
}
return .ProgressiveMigrationRequired(localStoreURL: localStoreURL)
case .InternalError:
guard case let NSError as NSError = info["NSError"] else {
return .Unknown
}
return .InternalError(NSError: NSError)
}
}
let swift = createSwiftObject(self)
self.swiftError = swift self.swiftError = swift
return swift return swift
} }
@@ -138,43 +87,7 @@ public final class CSError: NSError, CoreStoreObjectiveCType {
public init(_ swiftValue: CoreStoreError) { public init(_ swiftValue: CoreStoreError) {
self.swiftError = swiftValue self.swiftError = swiftValue
super.init(domain: CoreStoreError.errorDomain, code: swiftValue.errorCode, userInfo: swiftValue.errorUserInfo)
let code: CoreStoreErrorCode
let info: [NSObject: AnyObject]
switch swiftValue {
case .Unknown:
code = .UnknownError
info = [:]
case .DifferentStorageExistsAtURL(let existingPersistentStoreURL):
code = .DifferentPersistentStoreExistsAtURL
info = [
"existingPersistentStoreURL": existingPersistentStoreURL
]
case .MappingModelNotFound(let localStoreURL, let targetModel, let targetModelVersion):
code = .MappingModelNotFound
info = [
"localStoreURL": localStoreURL,
"targetModel": targetModel,
"targetModelVersion": targetModelVersion
]
case .ProgressiveMigrationRequired(let localStoreURL):
code = .ProgressiveMigrationRequired
info = [
"localStoreURL": localStoreURL
]
case .InternalError(let NSError):
code = .InternalError
info = [
"NSError": NSError
]
}
super.init(domain: CoreStoreErrorDomain, code: code.rawValue, userInfo: info)
} }
public required init?(coder aDecoder: NSCoder) { public required init?(coder aDecoder: NSCoder) {
@@ -203,33 +116,43 @@ public enum CSErrorCode: Int {
/** /**
A failure occured because of an unknown error. A failure occured because of an unknown error.
*/ */
case UnknownError case unknownError
/** /**
The `NSPersistentStore` could note be initialized because another store existed at the specified `NSURL`. The `NSPersistentStore` could note be initialized because another store existed at the specified `NSURL`.
*/ */
case DifferentPersistentStoreExistsAtURL case differentStorageExistsAtURL
/** /**
An `NSMappingModel` could not be found for a specific source and destination model versions. An `NSMappingModel` could not be found for a specific source and destination model versions.
*/ */
case MappingModelNotFound case mappingModelNotFound
/** /**
Progressive migrations are disabled for a store, but an `NSMappingModel` could not be found for a specific source and destination model versions. Progressive migrations are disabled for a store, but an `NSMappingModel` could not be found for a specific source and destination model versions.
*/ */
case ProgressiveMigrationRequired case progressiveMigrationRequired
/** /**
An internal SDK call failed with the specified "NSError" userInfo key. An internal SDK call failed with the specified "NSError" userInfo key.
*/ */
case InternalError case internalError
/**
The transaction was terminated by a user-thrown error with the specified "Error" userInfo key.
*/
case userError
/**
The transaction was cancelled by the user.
*/
case userCancelled
} }
// MARK: - CoreStoreError // MARK: - CoreStoreError
extension CoreStoreError: CoreStoreSwiftType { extension CoreStoreError: CoreStoreSwiftType, _ObjectiveCBridgeableError {
// MARK: CoreStoreSwiftType // MARK: CoreStoreSwiftType
@@ -237,20 +160,106 @@ extension CoreStoreError: CoreStoreSwiftType {
return CSError(self) return CSError(self)
} }
// MARK: _ObjectiveCBridgeableError
public init?(_bridgedNSError error: NSError) {
guard error.domain == CoreStoreErrorDomain else {
if error is CSError {
self = .internalError(NSError: error)
return
}
return nil
}
guard let code = CoreStoreErrorCode(rawValue: error.code) else {
if error is CSError {
self = .unknown
return
}
return nil
}
let info = error.userInfo
switch code {
case .unknownError:
self = .unknown
case .differentStorageExistsAtURL:
guard case let existingPersistentStoreURL as URL = info["existingPersistentStoreURL"] else {
self = .unknown
return
}
self = .differentStorageExistsAtURL(existingPersistentStoreURL: existingPersistentStoreURL)
case .mappingModelNotFound:
guard let localStoreURL = info["localStoreURL"] as? URL,
let targetModel = info["targetModel"] as? NSManagedObjectModel,
let targetModelVersion = info["targetModelVersion"] as? String else {
self = .unknown
return
}
self = .mappingModelNotFound(localStoreURL: localStoreURL, targetModel: targetModel, targetModelVersion: targetModelVersion)
case .progressiveMigrationRequired:
guard let localStoreURL = info["localStoreURL"] as? URL else {
self = .unknown
return
}
self = .progressiveMigrationRequired(localStoreURL: localStoreURL)
case .internalError:
guard case let nsError as NSError = info["NSError"] else {
self = .unknown
return
}
self = .internalError(NSError: nsError)
case .userError:
guard case let error as Error = info["Error"] else {
self = .unknown
return
}
self = .userError(error: error)
case .userCancelled:
self = .userCancelled
}
}
} }
// MARK: Internal // MARK: Internal
internal extension ErrorType { internal extension Error {
internal var bridgeToSwift: CoreStoreError { internal var bridgeToSwift: CoreStoreError {
switch self { switch self {
case let error as CoreStoreError: return error case let error as CoreStoreError:
case let error as CSError: return error.bridgeToSwift return error
default: return .Unknown
case let error as CSError:
return error.bridgeToSwift
case let error as NSError where type(of: self) is NSError.Type:
return .internalError(NSError: error)
default:
return .unknown
} }
} }
@@ -258,9 +267,14 @@ internal extension ErrorType {
switch self { switch self {
case let error as CoreStoreError: return error.bridgeToObjectiveC case let error as CoreStoreError:
case let error as CSError: return error return error.bridgeToObjectiveC
default: return self as NSError
case let error as CSError:
return error
default:
return self as NSError
} }
} }
} }

View File

@@ -35,7 +35,7 @@ import CoreData
- SeeAlso: `From` - SeeAlso: `From`
*/ */
@objc @objc
public final class CSFrom: NSObject, CoreStoreObjectiveCType { public final class CSFrom: NSObject {
/** /**
The associated `NSManagedObject` entity class The associated `NSManagedObject` entity class
@@ -51,7 +51,7 @@ public final class CSFrom: NSObject, CoreStoreObjectiveCType {
May contain `NSString` instances to pertain to named configurations, or `NSNull` to pertain to the default configuration May contain `NSString` instances to pertain to named configurations, or `NSNull` to pertain to the default configuration
*/ */
@objc @objc
public var configurations: [AnyObject]? { public var configurations: [Any]? {
return self.bridgeToSwift.configurations?.map { return self.bridgeToSwift.configurations?.map {
@@ -68,11 +68,10 @@ public final class CSFrom: NSObject, CoreStoreObjectiveCType {
``` ```
MyPersonEntity *people = [transaction fetchAllFrom:CSFromClass([MyPersonEntity class])]; MyPersonEntity *people = [transaction fetchAllFrom:CSFromClass([MyPersonEntity class])];
``` ```
- parameter entityClass: the `NSManagedObject` class type to be created - parameter entityClass: the `NSManagedObject` class type to be created
*/ */
@objc @objc
public convenience init(entityClass: AnyClass) { public convenience init(entityClass: NSManagedObject.Type) {
self.init(From(entityClass)) self.init(From(entityClass))
} }
@@ -83,11 +82,11 @@ public final class CSFrom: NSObject, CoreStoreObjectiveCType {
MyPersonEntity *people = [transaction fetchAllFrom: MyPersonEntity *people = [transaction fetchAllFrom:
CSFromClass([MyPersonEntity class], @"Config1")]; CSFromClass([MyPersonEntity class], @"Config1")];
``` ```
- parameter entityClass: the associated `NSManagedObject` entity class
- parameter configuration: the `NSPersistentStore` configuration name to associate objects from. This parameter is required if multiple configurations contain the created `NSManagedObject`'s entity type. Set to `[NSNull null]` to use the default configuration. - parameter configuration: the `NSPersistentStore` configuration name to associate objects from. This parameter is required if multiple configurations contain the created `NSManagedObject`'s entity type. Set to `[NSNull null]` to use the default configuration.
*/ */
@objc @objc
public convenience init(entityClass: AnyClass, configuration: AnyObject) { public convenience init(entityClass: NSManagedObject.Type, configuration: Any) {
switch configuration { switch configuration {
@@ -109,14 +108,13 @@ public final class CSFrom: NSObject, CoreStoreObjectiveCType {
CSFromClass([MyPersonEntity class], CSFromClass([MyPersonEntity class],
@[[NSNull null], @"Config1"])]; @[[NSNull null], @"Config1"])];
``` ```
- parameter entityClass: the associated `NSManagedObject` entity class
- parameter entity: the associated `NSManagedObject` entity class
- parameter configurations: an array of the `NSPersistentStore` configuration names to associate objects from. This parameter is required if multiple configurations contain the created `NSManagedObject`'s entity type. Set to `[NSNull null]` to use the default configuration. - parameter configurations: an array of the `NSPersistentStore` configuration names to associate objects from. This parameter is required if multiple configurations contain the created `NSManagedObject`'s entity type. Set to `[NSNull null]` to use the default configuration.
*/ */
@objc @objc
public convenience init(entityClass: AnyClass, configurations: [AnyObject]) { public convenience init(entityClass: NSManagedObject.Type, configurations: [Any]) {
var arguments = [String?]() var arguments = [ModelConfiguration]()
for configuration in configurations { for configuration in configurations {
switch configuration { switch configuration {
@@ -139,7 +137,7 @@ public final class CSFrom: NSObject, CoreStoreObjectiveCType {
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)"
} }
@@ -149,7 +147,7 @@ public final class CSFrom: NSObject, CoreStoreObjectiveCType {
public init<T: NSManagedObject>(_ swiftValue: From<T>) { public init<T: NSManagedObject>(_ swiftValue: From<T>) {
self.bridgeToSwift = swiftValue.upcast() self.bridgeToSwift = swiftValue.downcast()
super.init() super.init()
} }
} }
@@ -157,7 +155,7 @@ public final class CSFrom: NSObject, CoreStoreObjectiveCType {
// MARK: - From // MARK: - From
extension From: CoreStoreSwiftType { extension From where T: NSManagedObject {
// MARK: CoreStoreSwiftType // MARK: CoreStoreSwiftType
@@ -165,4 +163,16 @@ extension From: CoreStoreSwiftType {
return CSFrom(self) return CSFrom(self)
} }
// MARK: FilePrivate
fileprivate func downcast() -> From<NSManagedObject> {
return From<NSManagedObject>(
entityClass: self.entityClass,
configurations: self.configurations,
findPersistentStores: self.findPersistentStores
)
}
} }

View File

@@ -76,7 +76,7 @@ public final class CSGroupBy: NSObject, CSQueryClause, CoreStoreObjectiveCType {
return self.bridgeToSwift.hashValue return self.bridgeToSwift.hashValue
} }
public override func isEqual(object: AnyObject?) -> Bool { public override func isEqual(_ object: Any?) -> Bool {
guard let object = object as? CSGroupBy else { guard let object = object as? CSGroupBy else {
@@ -87,14 +87,14 @@ public final class CSGroupBy: NSObject, CSQueryClause, CoreStoreObjectiveCType {
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)"
} }
// MARK: CSQueryClause // MARK: CSQueryClause
@objc @objc
public func applyToFetchRequest(fetchRequest: NSFetchRequest) { public func applyToFetchRequest(_ fetchRequest: NSFetchRequest<NSFetchRequestResult>) {
self.bridgeToSwift.applyToFetchRequest(fetchRequest) self.bridgeToSwift.applyToFetchRequest(fetchRequest)
} }
@@ -118,5 +118,8 @@ extension GroupBy: CoreStoreSwiftType {
// MARK: CoreStoreSwiftType // MARK: CoreStoreSwiftType
public typealias ObjectiveCType = CSGroupBy public var bridgeToObjectiveC: CSGroupBy {
return CSGroupBy(self)
}
} }

View File

@@ -43,7 +43,7 @@ public final class CSInMemoryStore: NSObject, CSStorageInterface, CoreStoreObjec
- parameter configuration: an optional configuration name from the model file. If not specified, defaults to `nil`, the "Default" configuration. - parameter configuration: an optional configuration name from the model file. If not specified, defaults to `nil`, the "Default" configuration.
*/ */
@objc @objc
public convenience init(configuration: String?) { public convenience init(configuration: ModelConfiguration) {
self.init(InMemoryStore(configuration: configuration)) self.init(InMemoryStore(configuration: configuration))
} }
@@ -70,7 +70,7 @@ public final class CSInMemoryStore: NSObject, CSStorageInterface, CoreStoreObjec
The configuration name in the model file The configuration name in the model file
*/ */
@objc @objc
public var configuration: String? { public var configuration: ModelConfiguration {
return self.bridgeToSwift.configuration return self.bridgeToSwift.configuration
} }
@@ -79,7 +79,7 @@ public final class CSInMemoryStore: NSObject, CSStorageInterface, CoreStoreObjec
The options dictionary for the `NSPersistentStore`. For `CSInMemoryStore`s, this is always set to `nil`. The options dictionary for the `NSPersistentStore`. For `CSInMemoryStore`s, this is always set to `nil`.
*/ */
@objc @objc
public var storeOptions: [String: AnyObject]? { public var storeOptions: [AnyHashable: Any]? {
return self.bridgeToSwift.storeOptions return self.bridgeToSwift.storeOptions
} }
@@ -92,7 +92,7 @@ public final class CSInMemoryStore: NSObject, CSStorageInterface, CoreStoreObjec
return ObjectIdentifier(self.bridgeToSwift).hashValue return ObjectIdentifier(self.bridgeToSwift).hashValue
} }
public override func isEqual(object: AnyObject?) -> Bool { public override func isEqual(_ object: Any?) -> Bool {
guard let object = object as? CSInMemoryStore else { guard let object = object as? CSInMemoryStore else {
@@ -103,7 +103,7 @@ public final class CSInMemoryStore: NSObject, CSStorageInterface, CoreStoreObjec
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)"
} }
@@ -125,5 +125,8 @@ extension InMemoryStore: CoreStoreSwiftType {
// MARK: CoreStoreSwiftType // MARK: CoreStoreSwiftType
public typealias ObjectiveCType = CSInMemoryStore public var bridgeToObjectiveC: CSInMemoryStore {
return CSInMemoryStore(self)
}
} }

View File

@@ -35,13 +35,13 @@ import CoreData
- SeeAlso: `Into` - SeeAlso: `Into`
*/ */
@objc @objc
public final class CSInto: NSObject, CoreStoreObjectiveCType { public final class CSInto: NSObject {
/** /**
The associated `NSManagedObject` entity class The associated `NSManagedObject` entity class
*/ */
@objc @objc
public var entityClass: AnyClass { public var entityClass: NSManagedObject.Type {
return self.bridgeToSwift.entityClass return self.bridgeToSwift.entityClass
} }
@@ -51,7 +51,7 @@ public final class CSInto: NSObject, CoreStoreObjectiveCType {
May contain a `String` to pertain to a named configuration, or `nil` to pertain to the default configuration May contain a `String` to pertain to a named configuration, or `nil` to pertain to the default configuration
*/ */
@objc @objc
public var configuration: String? { public var configuration: ModelConfiguration {
return self.bridgeToSwift.configuration return self.bridgeToSwift.configuration
} }
@@ -62,11 +62,10 @@ public final class CSInto: NSObject, CoreStoreObjectiveCType {
MyPersonEntity *person = [transaction createInto: MyPersonEntity *person = [transaction createInto:
CSIntoClass([MyPersonEntity class])]; CSIntoClass([MyPersonEntity class])];
``` ```
- parameter entityClass: the `NSManagedObject` class type to be created - parameter entityClass: the `NSManagedObject` class type to be created
*/ */
@objc @objc
public convenience init(entityClass: AnyClass) { public convenience init(entityClass: NSManagedObject.Type) {
self.init(Into(entityClass)) self.init(Into(entityClass))
} }
@@ -77,12 +76,11 @@ public final class CSInto: NSObject, CoreStoreObjectiveCType {
MyPersonEntity *person = [transaction createInto: MyPersonEntity *person = [transaction createInto:
CSIntoClass([MyPersonEntity class])]; CSIntoClass([MyPersonEntity class])];
``` ```
- parameter entityClass: the `NSManagedObject` class type to be created - parameter entityClass: the `NSManagedObject` class type to be created
- parameter configuration: the `NSPersistentStore` configuration name to associate the object to. This parameter is required if multiple configurations contain the created `NSManagedObject`'s entity type. Set to `nil` to use the default configuration. - parameter configuration: the `NSPersistentStore` configuration name to associate the object to. This parameter is required if multiple configurations contain the created `NSManagedObject`'s entity type. Set to `nil` to use the default configuration.
*/ */
@objc @objc
public convenience init(entityClass: AnyClass, configuration: String?) { public convenience init(entityClass: NSManagedObject.Type, configuration: ModelConfiguration) {
self.init(Into(entityClass, configuration)) self.init(Into(entityClass, configuration))
} }
@@ -95,7 +93,7 @@ public final class CSInto: NSObject, CoreStoreObjectiveCType {
return self.bridgeToSwift.hashValue return self.bridgeToSwift.hashValue
} }
public override func isEqual(object: AnyObject?) -> Bool { public override func isEqual(_ object: Any?) -> Bool {
guard let object = object as? CSInto else { guard let object = object as? CSInto else {
@@ -106,7 +104,7 @@ public final class CSInto: NSObject, CoreStoreObjectiveCType {
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)"
} }
@@ -116,7 +114,7 @@ public final class CSInto: NSObject, CoreStoreObjectiveCType {
public required init<T: NSManagedObject>(_ swiftValue: Into<T>) { public required init<T: NSManagedObject>(_ swiftValue: Into<T>) {
self.bridgeToSwift = swiftValue.upcast() self.bridgeToSwift = swiftValue.downcast()
super.init() super.init()
} }
} }
@@ -124,7 +122,7 @@ public final class CSInto: NSObject, CoreStoreObjectiveCType {
// MARK: - Into // MARK: - Into
extension Into: CoreStoreSwiftType { extension Into where T: NSManagedObject {
// MARK: CoreStoreSwiftType // MARK: CoreStoreSwiftType
@@ -132,4 +130,16 @@ extension Into: CoreStoreSwiftType {
return CSInto(self) return CSInto(self)
} }
// MARK: FilePrivate
fileprivate func downcast() -> Into<NSManagedObject> {
return Into<NSManagedObject>(
entityClass: self.entityClass,
configuration: self.configuration,
inferStoreIfPossible: self.inferStoreIfPossible
)
}
} }

View File

@@ -0,0 +1,115 @@
//
// CSLegacyXcodeDataModelSchema.swift
// CoreStore
//
// Copyright © 2017 John Rommel Estropia
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in all
// copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
// SOFTWARE.
//
import CoreData
import Foundation
// MARK: - CSLegacyXcodeDataModelSchema
/**
The `CSLegacyXcodeDataModelSchema` serves as the Objective-C bridging type for `LegacyXcodeDataModelSchema`.
- SeeAlso: `LegacyXcodeDataModelSchema`
*/
@objc
public final class CSLegacyXcodeDataModelSchema: NSObject, CSDynamicSchema, CoreStoreObjectiveCType {
/**
Initializes a `CSLegacyXcodeDataModelSchema` from an `NSManagedObjectModel`.
- parameter modelName: the model version, typically the file name of an *.xcdatamodeld file (without the file extension)
- parameter model: the `NSManagedObjectModel`
*/
@objc
public required init(modelName: ModelVersion, model: NSManagedObjectModel) {
self.bridgeToSwift = LegacyXcodeDataModelSchema(
modelName: modelName,
model: model
)
}
// MARK: NSObject
public override var hash: Int {
return ObjectIdentifier(self.bridgeToSwift).hashValue
}
public override func isEqual(_ object: Any?) -> Bool {
guard let object = object as? CSLegacyXcodeDataModelSchema else {
return false
}
return self.bridgeToSwift === object.bridgeToSwift
}
public override var description: String {
return "(\(String(reflecting: type(of: self)))) \(self.bridgeToSwift.coreStoreDumpString)"
}
// MARK: CSDynamicSchema
@objc
public var modelVersion: ModelVersion {
return self.bridgeToSwift.modelVersion
}
@objc
public func rawModel() -> NSManagedObjectModel {
return self.bridgeToSwift.rawModel()
}
// MARK: CoreStoreObjectiveCType
public let bridgeToSwift: LegacyXcodeDataModelSchema
public required init(_ swiftValue: LegacyXcodeDataModelSchema) {
self.bridgeToSwift = swiftValue
super.init()
}
}
// MARK: - LegacyXcodeDataModelSchema
extension LegacyXcodeDataModelSchema: CoreStoreSwiftType {
// MARK: CoreStoreSwiftType
public var bridgeToObjectiveC: CSLegacyXcodeDataModelSchema {
return CSLegacyXcodeDataModelSchema(self)
}
}

View File

@@ -27,8 +27,6 @@ import Foundation
import CoreData import CoreData
#if os(iOS) || os(watchOS) || os(tvOS)
// MARK: - CSListMonitor // MARK: - CSListMonitor
/** /**
@@ -36,8 +34,9 @@ import CoreData
- SeeAlso: `ListMonitor` - SeeAlso: `ListMonitor`
*/ */
@available(OSX 10.12, *)
@objc @objc
public final class CSListMonitor: NSObject, CoreStoreObjectiveCType { public final class CSListMonitor: NSObject {
// MARK: Public (Accessors) // MARK: Public (Accessors)
@@ -48,7 +47,7 @@ public final class CSListMonitor: NSObject, CoreStoreObjectiveCType {
- returns: the `NSManagedObject` at the specified index - returns: the `NSManagedObject` at the specified index
*/ */
@objc @objc
public subscript(index: Int) -> AnyObject { public subscript(index: Int) -> Any {
return self.bridgeToSwift[index] return self.bridgeToSwift[index]
} }
@@ -60,7 +59,7 @@ public final class CSListMonitor: NSObject, CoreStoreObjectiveCType {
- returns: the `NSManagedObject` at the specified index, or `nil` if out of bounds - returns: the `NSManagedObject` at the specified index, or `nil` if out of bounds
*/ */
@objc @objc
public func objectAtSafeIndex(index: Int) -> AnyObject? { public func objectAtSafeIndex(_ index: Int) -> Any? {
return self.bridgeToSwift[safeIndex: index] return self.bridgeToSwift[safeIndex: index]
} }
@@ -73,12 +72,10 @@ public final class CSListMonitor: NSObject, CoreStoreObjectiveCType {
- returns: the `NSManagedObject` at the specified section and item index - returns: the `NSManagedObject` at the specified section and item index
*/ */
@objc @objc
public func objectAtSectionIndex(sectionIndex: Int, itemIndex: Int) -> AnyObject { public func objectAtSectionIndex(_ sectionIndex: Int, itemIndex: Int) -> Any {
return self.bridgeToSwift[sectionIndex, itemIndex] return self.bridgeToSwift[sectionIndex, itemIndex]
} } /**
/**
Returns the object at the given section and item index, or `nil` if out of bounds. This indexer is typically used for `CSListMonitor`s created as sectioned lists. Returns the object at the given section and item index, or `nil` if out of bounds. This indexer is typically used for `CSListMonitor`s created as sectioned lists.
- parameter sectionIndex: the section index for the object. Using a `sectionIndex` with an invalid range will return `nil`. - parameter sectionIndex: the section index for the object. Using a `sectionIndex` with an invalid range will return `nil`.
@@ -86,7 +83,7 @@ public final class CSListMonitor: NSObject, CoreStoreObjectiveCType {
- returns: the `NSManagedObject` at the specified section and item index, or `nil` if out of bounds - returns: the `NSManagedObject` at the specified section and item index, or `nil` if out of bounds
*/ */
@objc @objc
public func objectAtSafeSectionIndex(sectionIndex: Int, safeItemIndex itemIndex: Int) -> AnyObject? { public func objectAtSafeSectionIndex(_ sectionIndex: Int, safeItemIndex itemIndex: Int) -> Any? {
return self.bridgeToSwift[safeSectionIndex: sectionIndex, safeItemIndex: itemIndex] return self.bridgeToSwift[safeSectionIndex: sectionIndex, safeItemIndex: itemIndex]
} }
@@ -98,7 +95,7 @@ public final class CSListMonitor: NSObject, CoreStoreObjectiveCType {
- returns: the `NSManagedObject` at the specified index path - returns: the `NSManagedObject` at the specified index path
*/ */
@objc @objc
public func objectAtIndexPath(indexPath: NSIndexPath) -> AnyObject { public func objectAtIndexPath(_ indexPath: IndexPath) -> Any {
return self.bridgeToSwift[indexPath] return self.bridgeToSwift[indexPath]
} }
@@ -110,7 +107,7 @@ public final class CSListMonitor: NSObject, CoreStoreObjectiveCType {
- returns: the `NSManagedObject` at the specified index path, or `nil` if out of bounds - returns: the `NSManagedObject` at the specified index path, or `nil` if out of bounds
*/ */
@objc @objc
public func objectAtSafeIndexPath(indexPath: NSIndexPath) -> AnyObject? { public func objectAtSafeIndexPath(_ indexPath: IndexPath) -> Any? {
return self.bridgeToSwift[safeIndexPath: indexPath] return self.bridgeToSwift[safeIndexPath: indexPath]
} }
@@ -121,7 +118,6 @@ public final class CSListMonitor: NSObject, CoreStoreObjectiveCType {
- returns: `YES` if at least one object in any section exists, `NO` otherwise - returns: `YES` if at least one object in any section exists, `NO` otherwise
*/ */
@objc @objc
@warn_unused_result
public func hasObjects() -> Bool { public func hasObjects() -> Bool {
return self.bridgeToSwift.hasObjects() return self.bridgeToSwift.hasObjects()
@@ -134,8 +130,7 @@ public final class CSListMonitor: NSObject, CoreStoreObjectiveCType {
- returns: `YES` if at least one object in the specified section exists, `NO` otherwise - returns: `YES` if at least one object in the specified section exists, `NO` otherwise
*/ */
@objc @objc
@warn_unused_result public func hasObjectsInSection(_ section: Int) -> Bool {
public func hasObjectsInSection(section: Int) -> Bool {
return self.bridgeToSwift.hasObjectsInSection(section) return self.bridgeToSwift.hasObjectsInSection(section)
} }
@@ -146,7 +141,6 @@ public final class CSListMonitor: NSObject, CoreStoreObjectiveCType {
- returns: all objects in all sections - returns: all objects in all sections
*/ */
@objc @objc
@warn_unused_result
public func objectsInAllSections() -> [NSManagedObject] { public func objectsInAllSections() -> [NSManagedObject] {
return self.bridgeToSwift.objectsInAllSections() return self.bridgeToSwift.objectsInAllSections()
@@ -159,8 +153,7 @@ public final class CSListMonitor: NSObject, CoreStoreObjectiveCType {
- returns: all objects in the specified section - returns: all objects in the specified section
*/ */
@objc @objc
@warn_unused_result public func objectsInSection(_ section: Int) -> [NSManagedObject] {
public func objectsInSection(section: Int) -> [NSManagedObject] {
return self.bridgeToSwift.objectsInSection(section) return self.bridgeToSwift.objectsInSection(section)
} }
@@ -172,7 +165,6 @@ public final class CSListMonitor: NSObject, CoreStoreObjectiveCType {
- returns: all objects in the specified section, or `nil` if out of bounds - returns: all objects in the specified section, or `nil` if out of bounds
*/ */
@objc @objc
@warn_unused_result
public func objectsInSafeSection(safeSectionIndex section: Int) -> [NSManagedObject]? { public func objectsInSafeSection(safeSectionIndex section: Int) -> [NSManagedObject]? {
return self.bridgeToSwift.objectsInSection(safeSectionIndex: section) return self.bridgeToSwift.objectsInSection(safeSectionIndex: section)
@@ -184,7 +176,6 @@ public final class CSListMonitor: NSObject, CoreStoreObjectiveCType {
- returns: the number of sections - returns: the number of sections
*/ */
@objc @objc
@warn_unused_result
public func numberOfSections() -> Int { public func numberOfSections() -> Int {
return self.bridgeToSwift.numberOfSections() return self.bridgeToSwift.numberOfSections()
@@ -196,7 +187,6 @@ public final class CSListMonitor: NSObject, CoreStoreObjectiveCType {
- returns: the number of objects in all sections - returns: the number of objects in all sections
*/ */
@objc @objc
@warn_unused_result
public func numberOfObjects() -> Int { public func numberOfObjects() -> Int {
return self.bridgeToSwift.numberOfObjects() return self.bridgeToSwift.numberOfObjects()
@@ -209,8 +199,7 @@ public final class CSListMonitor: NSObject, CoreStoreObjectiveCType {
- returns: the number of objects in the specified section - returns: the number of objects in the specified section
*/ */
@objc @objc
@warn_unused_result public func numberOfObjectsInSection(_ section: Int) -> Int {
public func numberOfObjectsInSection(section: Int) -> Int {
return self.bridgeToSwift.numberOfObjectsInSection(section) return self.bridgeToSwift.numberOfObjectsInSection(section)
} }
@@ -222,10 +211,11 @@ public final class CSListMonitor: NSObject, CoreStoreObjectiveCType {
- returns: the number of objects in the specified section, or `nil` if out of bounds - returns: the number of objects in the specified section, or `nil` if out of bounds
*/ */
@objc @objc
@warn_unused_result
public func numberOfObjectsInSafeSection(safeSectionIndex section: Int) -> NSNumber? { public func numberOfObjectsInSafeSection(safeSectionIndex section: Int) -> NSNumber? {
return self.bridgeToSwift.numberOfObjectsInSection(safeSectionIndex: section) return self.bridgeToSwift
.numberOfObjectsInSection(safeSectionIndex: section)
.flatMap { NSNumber(value: $0) }
} }
/** /**
@@ -235,8 +225,7 @@ public final class CSListMonitor: NSObject, CoreStoreObjectiveCType {
- returns: the `NSFetchedResultsSectionInfo` for the specified section - returns: the `NSFetchedResultsSectionInfo` for the specified section
*/ */
@objc @objc
@warn_unused_result public func sectionInfoAtIndex(_ section: Int) -> NSFetchedResultsSectionInfo {
public func sectionInfoAtIndex(section: Int) -> NSFetchedResultsSectionInfo {
return self.bridgeToSwift.sectionInfoAtIndex(section) return self.bridgeToSwift.sectionInfoAtIndex(section)
} }
@@ -248,7 +237,6 @@ public final class CSListMonitor: NSObject, CoreStoreObjectiveCType {
- returns: the `NSFetchedResultsSectionInfo` for the specified section, or `nil` if the section index is out of bounds. - returns: the `NSFetchedResultsSectionInfo` for the specified section, or `nil` if the section index is out of bounds.
*/ */
@objc @objc
@warn_unused_result
public func sectionInfoAtSafeSectionIndex(safeSectionIndex section: Int) -> NSFetchedResultsSectionInfo? { public func sectionInfoAtSafeSectionIndex(safeSectionIndex section: Int) -> NSFetchedResultsSectionInfo? {
return self.bridgeToSwift.sectionInfoAtIndex(safeSectionIndex: section) return self.bridgeToSwift.sectionInfoAtIndex(safeSectionIndex: section)
@@ -260,7 +248,6 @@ public final class CSListMonitor: NSObject, CoreStoreObjectiveCType {
- returns: the `NSFetchedResultsSectionInfo`s for all sections - returns: the `NSFetchedResultsSectionInfo`s for all sections
*/ */
@objc @objc
@warn_unused_result
public func sections() -> [NSFetchedResultsSectionInfo] { public func sections() -> [NSFetchedResultsSectionInfo] {
return self.bridgeToSwift.sections() return self.bridgeToSwift.sections()
@@ -274,8 +261,7 @@ public final class CSListMonitor: NSObject, CoreStoreObjectiveCType {
- returns: the target section for the specified "Section Index" title and index. - returns: the target section for the specified "Section Index" title and index.
*/ */
@objc @objc
@warn_unused_result public func targetSectionForSectionIndexTitle(title: String, index: Int) -> Int {
public func targetSectionForSectionIndexTitle(title title: String, index: Int) -> Int {
return self.bridgeToSwift.targetSectionForSectionIndex(title: title, index: index) return self.bridgeToSwift.targetSectionForSectionIndex(title: title, index: index)
} }
@@ -286,7 +272,6 @@ public final class CSListMonitor: NSObject, CoreStoreObjectiveCType {
- returns: the section index titles for all sections - returns: the section index titles for all sections
*/ */
@objc @objc
@warn_unused_result
public func sectionIndexTitles() -> [String] { public func sectionIndexTitles() -> [String] {
return self.bridgeToSwift.sectionIndexTitles() return self.bridgeToSwift.sectionIndexTitles()
@@ -299,10 +284,11 @@ public final class CSListMonitor: NSObject, CoreStoreObjectiveCType {
- returns: the index of the `NSManagedObject` if it exists in the `CSListMonitor`'s fetched objects, or `nil` if not found. - returns: the index of the `NSManagedObject` if it exists in the `CSListMonitor`'s fetched objects, or `nil` if not found.
*/ */
@objc @objc
@warn_unused_result public func indexOf(_ object: NSManagedObject) -> NSNumber? {
public func indexOf(object: NSManagedObject) -> NSNumber? {
return self.bridgeToSwift.indexOf(object) return self.bridgeToSwift
.indexOf(object)
.flatMap { NSNumber(value: $0) }
} }
/** /**
@@ -312,8 +298,7 @@ public final class CSListMonitor: NSObject, CoreStoreObjectiveCType {
- returns: the `NSIndexPath` of the `NSManagedObject` if it exists in the `ListMonitor`'s fetched objects, or `nil` if not found. - returns: the `NSIndexPath` of the `NSManagedObject` if it exists in the `ListMonitor`'s fetched objects, or `nil` if not found.
*/ */
@objc @objc
@warn_unused_result public func indexPathOf(_ object: NSManagedObject) -> IndexPath? {
public func indexPathOf(object: NSManagedObject) -> NSIndexPath? {
return self.bridgeToSwift.indexPathOf(object) return self.bridgeToSwift.indexPathOf(object)
} }
@@ -333,7 +318,7 @@ public final class CSListMonitor: NSObject, CoreStoreObjectiveCType {
- parameter observer: a `CSListObserver` to send change notifications to - parameter observer: a `CSListObserver` to send change notifications to
*/ */
@objc @objc
public func addListObserver(observer: CSListObserver) { public func addListObserver(_ observer: CSListObserver) {
let swift = self.bridgeToSwift let swift = self.bridgeToSwift
swift.unregisterObserver(observer) swift.unregisterObserver(observer)
@@ -369,7 +354,7 @@ public final class CSListMonitor: NSObject, CoreStoreObjectiveCType {
- parameter observer: a `CSListObjectObserver` to send change notifications to - parameter observer: a `CSListObjectObserver` to send change notifications to
*/ */
public func addListObjectObserver(observer: CSListObjectObserver) { public func addListObjectObserver(_ observer: CSListObjectObserver) {
let swift = self.bridgeToSwift let swift = self.bridgeToSwift
swift.unregisterObserver(observer) swift.unregisterObserver(observer)
@@ -425,7 +410,7 @@ public final class CSListMonitor: NSObject, CoreStoreObjectiveCType {
- parameter observer: a `CSListSectionObserver` to send change notifications to - parameter observer: a `CSListSectionObserver` to send change notifications to
*/ */
@objc @objc
public func addListSectionObserver(observer: CSListSectionObserver) { public func addListSectionObserver(_ observer: CSListSectionObserver) {
let swift = self.bridgeToSwift let swift = self.bridgeToSwift
swift.unregisterObserver(observer) swift.unregisterObserver(observer)
@@ -488,7 +473,7 @@ public final class CSListMonitor: NSObject, CoreStoreObjectiveCType {
- parameter observer: a `CSListObserver` to unregister notifications to - parameter observer: a `CSListObserver` to unregister notifications to
*/ */
@objc @objc
public func removeListObserver(observer: CSListObserver) { public func removeListObserver(_ observer: CSListObserver) {
self.bridgeToSwift.unregisterObserver(observer) self.bridgeToSwift.unregisterObserver(observer)
} }
@@ -513,11 +498,11 @@ public final class CSListMonitor: NSObject, CoreStoreObjectiveCType {
- parameter fetchClauses: a series of `FetchClause` instances for fetching the object list. Accepts `Where`, `OrderBy`, and `Tweak` clauses. Note that only specified clauses will be changed; unspecified clauses will use previous values. - parameter fetchClauses: a series of `FetchClause` instances for fetching the object list. Accepts `Where`, `OrderBy`, and `Tweak` clauses. Note that only specified clauses will be changed; unspecified clauses will use previous values.
*/ */
@objc @objc
public func refetch(fetchClauses: [CSFetchClause]) { public func refetch(_ fetchClauses: [CSFetchClause]) {
self.bridgeToSwift.refetch { (fetchRequest) in self.bridgeToSwift.refetch { (fetchRequest) in
fetchClauses.forEach { $0.applyToFetchRequest(fetchRequest) } fetchClauses.forEach { $0.applyToFetchRequest(fetchRequest as! NSFetchRequest<NSFetchRequestResult>) }
} }
} }
@@ -529,7 +514,7 @@ public final class CSListMonitor: NSObject, CoreStoreObjectiveCType {
return self.bridgeToSwift.hashValue return self.bridgeToSwift.hashValue
} }
public override func isEqual(object: AnyObject?) -> Bool { public override func isEqual(_ object: Any?) -> Bool {
guard let object = object as? CSListMonitor else { guard let object = object as? CSListMonitor else {
@@ -540,7 +525,7 @@ public final class CSListMonitor: NSObject, CoreStoreObjectiveCType {
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)"
} }
@@ -552,7 +537,7 @@ public final class CSListMonitor: NSObject, CoreStoreObjectiveCType {
@nonobjc @nonobjc
public required init<T: NSManagedObject>(_ swiftValue: ListMonitor<T>) { public required init<T: NSManagedObject>(_ swiftValue: ListMonitor<T>) {
self.bridgeToSwift = swiftValue.upcast() self.bridgeToSwift = swiftValue.downcast()
super.init() super.init()
} }
} }
@@ -560,7 +545,8 @@ public final class CSListMonitor: NSObject, CoreStoreObjectiveCType {
// MARK: - ListMonitor // MARK: - ListMonitor
extension ListMonitor: CoreStoreSwiftType { @available(OSX 10.12, *)
extension ListMonitor where ListMonitor.ObjectType: NSManagedObject {
// MARK: CoreStoreSwiftType // MARK: CoreStoreSwiftType
@@ -568,6 +554,17 @@ extension ListMonitor: CoreStoreSwiftType {
return CSListMonitor(self) return CSListMonitor(self)
} }
// MARK: FilePrivate
fileprivate func downcast() -> ListMonitor<NSManagedObject> {
@inline(__always)
func noWarnUnsafeBitCast<T, U>(_ x: T, to type: U.Type) -> U {
return unsafeBitCast(x, to: type)
}
return noWarnUnsafeBitCast(self, to: ListMonitor<NSManagedObject>.self)
}
} }
#endif

View File

@@ -27,8 +27,6 @@ import Foundation
import CoreData import CoreData
#if os(iOS) || os(watchOS) || os(tvOS)
// MARK: - CSListObserver // MARK: - CSListObserver
/** /**
@@ -42,6 +40,7 @@ import CoreData
- SeeAlso: `ListObserver` - SeeAlso: `ListObserver`
*/ */
@available(OSX 10.12, *)
@objc @objc
public protocol CSListObserver: class, AnyObject { public protocol CSListObserver: class, AnyObject {
@@ -51,7 +50,7 @@ public protocol CSListObserver: class, AnyObject {
- parameter monitor: the `CSListMonitor` monitoring the list being observed - parameter monitor: the `CSListMonitor` monitoring the list being observed
*/ */
@objc @objc
optional func listMonitorWillChange(monitor: CSListMonitor) optional func listMonitorWillChange(_ monitor: CSListMonitor)
/** /**
Handles processing right after a change to the observed list occurs Handles processing right after a change to the observed list occurs
@@ -59,7 +58,7 @@ public protocol CSListObserver: class, AnyObject {
- parameter monitor: the `CSListMonitor` monitoring the object being observed - parameter monitor: the `CSListMonitor` monitoring the object being observed
*/ */
@objc @objc
optional func listMonitorDidChange(monitor: CSListMonitor) optional func listMonitorDidChange(_ monitor: CSListMonitor)
/** /**
This method is broadcast from within the `CSListMonitor`'s `-refetchWithFetchClauses:` method to let observers prepare for the internal `NSFetchedResultsController`'s pending change to its predicate, sort descriptors, etc. Note that the actual refetch will happen after the `NSFetchedResultsController`'s last `-controllerDidChangeContent:` notification completes. This method is broadcast from within the `CSListMonitor`'s `-refetchWithFetchClauses:` method to let observers prepare for the internal `NSFetchedResultsController`'s pending change to its predicate, sort descriptors, etc. Note that the actual refetch will happen after the `NSFetchedResultsController`'s last `-controllerDidChangeContent:` notification completes.
@@ -67,7 +66,7 @@ public protocol CSListObserver: class, AnyObject {
- parameter monitor: the `CSListMonitor` monitoring the object being observed - parameter monitor: the `CSListMonitor` monitoring the object being observed
*/ */
@objc @objc
optional func listMonitorWillRefetch(monitor: CSListMonitor) optional func listMonitorWillRefetch(_ monitor: CSListMonitor)
/** /**
After the `CSListMonitor`'s `-refetchWithFetchClauses:` method is called, this method is broadcast after the `NSFetchedResultsController`'s last `-controllerDidChangeContent:` notification completes. After the `CSListMonitor`'s `-refetchWithFetchClauses:` method is called, this method is broadcast after the `NSFetchedResultsController`'s last `-controllerDidChangeContent:` notification completes.
@@ -75,7 +74,7 @@ public protocol CSListObserver: class, AnyObject {
- parameter monitor: the `CSListMonitor` monitoring the object being observed - parameter monitor: the `CSListMonitor` monitoring the object being observed
*/ */
@objc @objc
optional func listMonitorDidRefetch(monitor: CSListMonitor) optional func listMonitorDidRefetch(_ monitor: CSListMonitor)
} }
@@ -92,6 +91,7 @@ public protocol CSListObserver: class, AnyObject {
- SeeAlso: `ListObjectObserver` - SeeAlso: `ListObjectObserver`
*/ */
@available(OSX 10.12, *)
@objc @objc
public protocol CSListObjectObserver: CSListObserver { public protocol CSListObjectObserver: CSListObserver {
@@ -103,7 +103,7 @@ public protocol CSListObjectObserver: CSListObserver {
- parameter indexPath: the new `NSIndexPath` for the inserted object - parameter indexPath: the new `NSIndexPath` for the inserted object
*/ */
@objc @objc
optional func listMonitor(monitor: CSListMonitor, didInsertObject object: AnyObject, toIndexPath indexPath: NSIndexPath) optional func listMonitor(_ monitor: CSListMonitor, didInsertObject object: Any, toIndexPath indexPath: IndexPath)
/** /**
Notifies that an object was deleted from the specified `NSIndexPath` in the list Notifies that an object was deleted from the specified `NSIndexPath` in the list
@@ -113,7 +113,7 @@ public protocol CSListObjectObserver: CSListObserver {
- parameter indexPath: the `NSIndexPath` for the deleted object - parameter indexPath: the `NSIndexPath` for the deleted object
*/ */
@objc @objc
optional func listMonitor(monitor: CSListMonitor, didDeleteObject object: AnyObject, fromIndexPath indexPath: NSIndexPath) optional func listMonitor(_ monitor: CSListMonitor, didDeleteObject object: Any, fromIndexPath indexPath: IndexPath)
/** /**
Notifies that an object at the specified `NSIndexPath` was updated Notifies that an object at the specified `NSIndexPath` was updated
@@ -123,7 +123,7 @@ public protocol CSListObjectObserver: CSListObserver {
- parameter indexPath: the `NSIndexPath` for the updated object - parameter indexPath: the `NSIndexPath` for the updated object
*/ */
@objc @objc
optional func listMonitor(monitor: CSListMonitor, didUpdateObject object: AnyObject, atIndexPath indexPath: NSIndexPath) optional func listMonitor(_ monitor: CSListMonitor, didUpdateObject object: Any, atIndexPath indexPath: IndexPath)
/** /**
Notifies that an object's index changed Notifies that an object's index changed
@@ -134,7 +134,7 @@ public protocol CSListObjectObserver: CSListObserver {
- parameter toIndexPath: the new `NSIndexPath` for the moved object - parameter toIndexPath: the new `NSIndexPath` for the moved object
*/ */
@objc @objc
optional func listMonitor(monitor: CSListMonitor, didMoveObject object: AnyObject, fromIndexPath: NSIndexPath, toIndexPath: NSIndexPath) optional func listMonitor(_ monitor: CSListMonitor, didMoveObject object: Any, fromIndexPath: IndexPath, toIndexPath: IndexPath)
} }
@@ -152,6 +152,7 @@ public protocol CSListObjectObserver: CSListObserver {
- SeeAlso: `ListSectionObserver` - SeeAlso: `ListSectionObserver`
*/ */
@available(OSX 10.12, *)
@objc @objc
public protocol CSListSectionObserver: CSListObjectObserver { public protocol CSListSectionObserver: CSListObjectObserver {
@@ -163,7 +164,7 @@ public protocol CSListSectionObserver: CSListObjectObserver {
- parameter sectionIndex: the new section index for the new section - parameter sectionIndex: the new section index for the new section
*/ */
@objc @objc
optional func listMonitor(monitor: CSListMonitor, didInsertSection sectionInfo: NSFetchedResultsSectionInfo, toSectionIndex sectionIndex: Int) optional func listMonitor(_ monitor: CSListMonitor, didInsertSection sectionInfo: NSFetchedResultsSectionInfo, toSectionIndex sectionIndex: Int)
/** /**
Notifies that a section was inserted at the specified index Notifies that a section was inserted at the specified index
@@ -173,7 +174,5 @@ public protocol CSListSectionObserver: CSListObjectObserver {
- parameter sectionIndex: the previous section index for the deleted section - parameter sectionIndex: the previous section index for the deleted section
*/ */
@objc @objc
optional func listMonitor(monitor: CSListMonitor, didDeleteSection sectionInfo: NSFetchedResultsSectionInfo, fromSectionIndex sectionIndex: Int) optional func listMonitor(_ monitor: CSListMonitor, didDeleteSection sectionInfo: NSFetchedResultsSectionInfo, fromSectionIndex sectionIndex: Int)
} }
#endif

View File

@@ -43,7 +43,7 @@ public final class CSMigrationResult: NSObject, CoreStoreObjectiveCType {
@objc @objc
public var isSuccess: Bool { public var isSuccess: Bool {
return self.bridgeToSwift.boolValue return self.bridgeToSwift.isSuccess
} }
/** /**
@@ -52,7 +52,7 @@ public final class CSMigrationResult: NSObject, CoreStoreObjectiveCType {
@objc @objc
public var isFailure: Bool { public var isFailure: Bool {
return !self.bridgeToSwift.boolValue return !self.bridgeToSwift.isSuccess
} }
/** /**
@@ -61,7 +61,7 @@ public final class CSMigrationResult: NSObject, CoreStoreObjectiveCType {
@objc @objc
public var migrationTypes: [CSMigrationType]? { public var migrationTypes: [CSMigrationType]? {
guard case .Success(let migrationTypes) = self.bridgeToSwift else { guard case .success(let migrationTypes) = self.bridgeToSwift else {
return nil return nil
} }
@@ -74,7 +74,7 @@ public final class CSMigrationResult: NSObject, CoreStoreObjectiveCType {
@objc @objc
public var error: NSError? { public var error: NSError? {
guard case .Failure(let error) = self.bridgeToSwift else { guard case .failure(let error) = self.bridgeToSwift else {
return nil return nil
} }
@@ -90,15 +90,15 @@ public final class CSMigrationResult: NSObject, CoreStoreObjectiveCType {
- parameter failure: the block to execute on failure. The block passes an `NSError` argument that pertains to the actual error. - parameter failure: the block to execute on failure. The block passes an `NSError` argument that pertains to the actual error.
*/ */
@objc @objc
public func handleSuccess(@noescape success: (migrationTypes: [CSMigrationType]) -> Void, @noescape failure: (error: NSError) -> Void) { public func handleSuccess(_ success: (_ migrationTypes: [CSMigrationType]) -> Void, failure: (_ error: NSError) -> Void) {
switch self.bridgeToSwift { switch self.bridgeToSwift {
case .Success(let migrationTypes): case .success(let migrationTypes):
success(migrationTypes: migrationTypes.map { $0.bridgeToObjectiveC }) success(migrationTypes.map { $0.bridgeToObjectiveC })
case .Failure(let error): case .failure(let error):
failure(error: error.bridgeToObjectiveC) failure(error.bridgeToObjectiveC)
} }
} }
@@ -110,13 +110,13 @@ public final class CSMigrationResult: NSObject, CoreStoreObjectiveCType {
- parameter success: the block to execute on success. The block passes an array of `CSMigrationType`s that indicates the migration steps completed. - parameter success: the block to execute on success. The block passes an array of `CSMigrationType`s that indicates the migration steps completed.
*/ */
@objc @objc
public func handleSuccess(@noescape success: (migrationTypes: [CSMigrationType]) -> Void) { public func handleSuccess(_ success: (_ migrationTypes: [CSMigrationType]) -> Void) {
guard case .Success(let migrationTypes) = self.bridgeToSwift else { guard case .success(let migrationTypes) = self.bridgeToSwift else {
return return
} }
success(migrationTypes: migrationTypes.map { $0.bridgeToObjectiveC }) success(migrationTypes.map { $0.bridgeToObjectiveC })
} }
/** /**
@@ -127,13 +127,13 @@ public final class CSMigrationResult: NSObject, CoreStoreObjectiveCType {
- parameter failure: the block to execute on failure. The block passes an `NSError` argument that pertains to the actual error. - parameter failure: the block to execute on failure. The block passes an `NSError` argument that pertains to the actual error.
*/ */
@objc @objc
public func handleFailure(@noescape failure: (error: NSError) -> Void) { public func handleFailure(_ failure: (_ error: NSError) -> Void) {
guard case .Failure(let error) = self.bridgeToSwift else { guard case .failure(let error) = self.bridgeToSwift else {
return return
} }
failure(error: error.bridgeToObjectiveC) failure(error.bridgeToObjectiveC)
} }
@@ -144,7 +144,7 @@ public final class CSMigrationResult: NSObject, CoreStoreObjectiveCType {
return self.bridgeToSwift.hashValue return self.bridgeToSwift.hashValue
} }
public override func isEqual(object: AnyObject?) -> Bool { public override func isEqual(_ object: Any?) -> Bool {
guard let object = object as? CSMigrationResult else { guard let object = object as? CSMigrationResult else {
@@ -155,7 +155,7 @@ public final class CSMigrationResult: NSObject, CoreStoreObjectiveCType {
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)"
} }
@@ -177,5 +177,8 @@ extension MigrationResult: CoreStoreSwiftType {
// MARK: CoreStoreSwiftType // MARK: CoreStoreSwiftType
public typealias ObjectiveCType = CSMigrationResult public var bridgeToObjectiveC: CSMigrationResult {
return CSMigrationResult(self)
}
} }

View File

@@ -43,7 +43,7 @@ public final class CSMigrationType: NSObject, CoreStoreObjectiveCType {
@objc @objc
public var needsMigration: Bool { public var needsMigration: Bool {
return self.bridgeToSwift.boolValue return self.bridgeToSwift.hasMigration
} }
/** /**
@@ -90,7 +90,7 @@ public final class CSMigrationType: NSObject, CoreStoreObjectiveCType {
return self.bridgeToSwift.hashValue return self.bridgeToSwift.hashValue
} }
public override func isEqual(object: AnyObject?) -> Bool { public override func isEqual(_ object: Any?) -> Bool {
guard let object = object as? CSMigrationType else { guard let object = object as? CSMigrationType else {
@@ -101,7 +101,7 @@ public final class CSMigrationType: NSObject, CoreStoreObjectiveCType {
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)"
} }
@@ -123,5 +123,8 @@ extension MigrationType: CoreStoreSwiftType {
// MARK: CoreStoreSwiftType // MARK: CoreStoreSwiftType
public typealias ObjectiveCType = CSMigrationType public var bridgeToObjectiveC: CSMigrationType {
return CSMigrationType(self)
}
} }

View File

@@ -27,8 +27,6 @@ import Foundation
import CoreData import CoreData
#if os(iOS) || os(watchOS) || os(tvOS)
// MARK: - CSObjectMonitor // MARK: - CSObjectMonitor
/** /**
@@ -36,13 +34,14 @@ import CoreData
- SeeAlso: `ObjectMonitor` - SeeAlso: `ObjectMonitor`
*/ */
@available(OSX 10.12, *)
@objc @objc
public final class CSObjectMonitor: NSObject, CoreStoreObjectiveCType { public final class CSObjectMonitor: NSObject {
/** /**
Returns the `NSManagedObject` instance being observed, or `nil` if the object was already deleted. Returns the `NSManagedObject` instance being observed, or `nil` if the object was already deleted.
*/ */
public var object: AnyObject? { public var object: Any? {
return self.bridgeToSwift.object return self.bridgeToSwift.object
} }
@@ -66,7 +65,7 @@ public final class CSObjectMonitor: NSObject, CoreStoreObjectiveCType {
- parameter observer: an `CSObjectObserver` to send change notifications to - parameter observer: an `CSObjectObserver` to send change notifications to
*/ */
public func addObjectObserver(observer: CSObjectObserver) { public func addObjectObserver(_ observer: CSObjectObserver) {
let swift = self.bridgeToSwift let swift = self.bridgeToSwift
swift.unregisterObserver(observer) swift.unregisterObserver(observer)
@@ -94,7 +93,7 @@ public final class CSObjectMonitor: NSObject, CoreStoreObjectiveCType {
- parameter observer: an `CSObjectObserver` to unregister notifications to - parameter observer: an `CSObjectObserver` to unregister notifications to
*/ */
public func removeObjectObserver(observer: CSObjectObserver) { public func removeObjectObserver(_ observer: CSObjectObserver) {
self.bridgeToSwift.unregisterObserver(observer) self.bridgeToSwift.unregisterObserver(observer)
} }
@@ -107,7 +106,7 @@ public final class CSObjectMonitor: NSObject, CoreStoreObjectiveCType {
return self.bridgeToSwift.hashValue return self.bridgeToSwift.hashValue
} }
public override func isEqual(object: AnyObject?) -> Bool { public override func isEqual(_ object: Any?) -> Bool {
guard let object = object as? CSObjectMonitor else { guard let object = object as? CSObjectMonitor else {
@@ -118,7 +117,7 @@ public final class CSObjectMonitor: NSObject, CoreStoreObjectiveCType {
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)"
} }
@@ -130,7 +129,7 @@ public final class CSObjectMonitor: NSObject, CoreStoreObjectiveCType {
@nonobjc @nonobjc
public required init<T: NSManagedObject>(_ swiftValue: ObjectMonitor<T>) { public required init<T: NSManagedObject>(_ swiftValue: ObjectMonitor<T>) {
self.bridgeToSwift = swiftValue.upcast() self.bridgeToSwift = swiftValue.downcast()
super.init() super.init()
} }
} }
@@ -138,7 +137,8 @@ public final class CSObjectMonitor: NSObject, CoreStoreObjectiveCType {
// MARK: - ObjectMonitor // MARK: - ObjectMonitor
extension ObjectMonitor: CoreStoreSwiftType { @available(OSX 10.12, *)
extension ObjectMonitor where ObjectMonitor.ObjectType: NSManagedObject {
// MARK: CoreStoreSwiftType // MARK: CoreStoreSwiftType
@@ -146,6 +146,17 @@ extension ObjectMonitor: CoreStoreSwiftType {
return CSObjectMonitor(self) return CSObjectMonitor(self)
} }
// MARK: FilePrivate
fileprivate func downcast() -> ObjectMonitor<NSManagedObject> {
@inline(__always)
func noWarnUnsafeBitCast<T, U>(_ x: T, to type: U.Type) -> U {
return unsafeBitCast(x, to: type)
}
return noWarnUnsafeBitCast(self, to: ObjectMonitor<NSManagedObject>.self)
}
} }
#endif

View File

@@ -27,8 +27,6 @@ import Foundation
import CoreData import CoreData
#if os(iOS) || os(watchOS) || os(tvOS)
// MARK: - CSObjectObserver // MARK: - CSObjectObserver
/** /**
@@ -40,6 +38,7 @@ import CoreData
- SeeAlso: `ObjectObserver` - SeeAlso: `ObjectObserver`
*/ */
@available(OSX 10.12, *)
@objc @objc
public protocol CSObjectObserver: class, AnyObject { public protocol CSObjectObserver: class, AnyObject {
@@ -50,7 +49,7 @@ public protocol CSObjectObserver: class, AnyObject {
- parameter object: the `NSManagedObject` instance being observed - parameter object: the `NSManagedObject` instance being observed
*/ */
@objc @objc
optional func objectMonitor(monitor: CSObjectMonitor, willUpdateObject object: AnyObject) optional func objectMonitor(_ monitor: CSObjectMonitor, willUpdateObject object: Any)
/** /**
Handles processing right after a change to the observed `object` occurs Handles processing right after a change to the observed `object` occurs
@@ -60,7 +59,7 @@ public protocol CSObjectObserver: class, AnyObject {
- parameter changedPersistentKeys: an `NSSet` of key paths for the attributes that were changed. Note that `changedPersistentKeys` only contains keys for attributes/relationships present in the persistent store, thus transient properties will not be reported. - parameter changedPersistentKeys: an `NSSet` of key paths for the attributes that were changed. Note that `changedPersistentKeys` only contains keys for attributes/relationships present in the persistent store, thus transient properties will not be reported.
*/ */
@objc @objc
optional func objectMonitor(monitor: CSObjectMonitor, didUpdateObject object: AnyObject, changedPersistentKeys: Set<String>) optional func objectMonitor(_ monitor: CSObjectMonitor, didUpdateObject object: Any, changedPersistentKeys: Set<String>)
/** /**
Handles processing right after `object` is deleted Handles processing right after `object` is deleted
@@ -69,7 +68,5 @@ public protocol CSObjectObserver: class, AnyObject {
- parameter object: the `NSManagedObject` instance being observed - parameter object: the `NSManagedObject` instance being observed
*/ */
@objc @objc
optional func objectMonitor(monitor: CSObjectMonitor, didDeleteObject object: AnyObject) optional func objectMonitor(_ monitor: CSObjectMonitor, didDeleteObject object: Any)
} }
#endif

View File

@@ -53,7 +53,6 @@ public final class CSOrderBy: NSObject, CSFetchClause, CSQueryClause, CSDeleteCl
fetchAllFrom:CSFromClass([MyPersonEntity class]) fetchAllFrom:CSFromClass([MyPersonEntity class])
fetchClauses:@[CSOrderByKey(CSSortAscending(@"fullname"))]]]; fetchClauses:@[CSOrderByKey(CSSortAscending(@"fullname"))]]];
``` ```
- parameter sortDescriptor: a `NSSortDescriptor` - parameter sortDescriptor: a `NSSortDescriptor`
*/ */
@objc @objc
@@ -69,7 +68,6 @@ public final class CSOrderBy: NSObject, CSFetchClause, CSQueryClause, CSDeleteCl
fetchAllFrom:CSFromClass([MyPersonEntity class]) fetchAllFrom:CSFromClass([MyPersonEntity class])
fetchClauses:@[CSOrderByKeys(CSSortAscending(@"fullname"), CSSortDescending(@"age"), nil))]]]; fetchClauses:@[CSOrderByKeys(CSSortAscending(@"fullname"), CSSortDescending(@"age"), nil))]]];
``` ```
- parameter sortDescriptors: an array of `NSSortDescriptor`s - parameter sortDescriptors: an array of `NSSortDescriptor`s
*/ */
@objc @objc
@@ -86,7 +84,7 @@ public final class CSOrderBy: NSObject, CSFetchClause, CSQueryClause, CSDeleteCl
return self.bridgeToSwift.hashValue return self.bridgeToSwift.hashValue
} }
public override func isEqual(object: AnyObject?) -> Bool { public override func isEqual(_ object: Any?) -> Bool {
guard let object = object as? CSOrderBy else { guard let object = object as? CSOrderBy else {
@@ -97,14 +95,14 @@ public final class CSOrderBy: NSObject, CSFetchClause, CSQueryClause, CSDeleteCl
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)"
} }
// MARK: CSFetchClause, CSQueryClause, CSDeleteClause // MARK: CSFetchClause, CSQueryClause, CSDeleteClause
@objc @objc
public func applyToFetchRequest(fetchRequest: NSFetchRequest) { public func applyToFetchRequest(_ fetchRequest: NSFetchRequest<NSFetchRequestResult>) {
self.bridgeToSwift.applyToFetchRequest(fetchRequest) self.bridgeToSwift.applyToFetchRequest(fetchRequest)
} }
@@ -128,5 +126,8 @@ extension OrderBy: CoreStoreSwiftType {
// MARK: CoreStoreSwiftType // MARK: CoreStoreSwiftType
public typealias ObjectiveCType = CSOrderBy public var bridgeToObjectiveC: CSOrderBy {
return CSOrderBy(self)
}
} }

View File

@@ -40,19 +40,18 @@ public final class CSSQLiteStore: NSObject, CSLocalStorage, CoreStoreObjectiveCT
/** /**
Initializes an SQLite store interface from the given SQLite file URL. When this instance is passed to the `CSDataStack`'s `-addStorage*:` methods, a new SQLite file will be created if it does not exist. Initializes an SQLite store interface from the given SQLite file URL. When this instance is passed to the `CSDataStack`'s `-addStorage*:` methods, a new SQLite file will be created if it does not exist.
- Important: Initializing `CSSQLiteStore`s with custom migration mapping models is currently not supported. Create an `SQLiteStore` instance from Swift code and bridge the instance to Objective-C using its `SQLiteStore.bridgeToObjectiveC` property.
- parameter fileURL: the local file URL for the target SQLite persistent store. Note that if you have multiple configurations, you will need to specify a different `fileURL` explicitly for each of them. - parameter fileURL: the local file URL for the target SQLite persistent store. Note that if you have multiple configurations, you will need to specify a different `fileURL` explicitly for each of them.
- parameter configuration: an optional configuration name from the model file. If not specified, defaults to `nil`, the "Default" configuration. Note that if you have multiple configurations, you will need to specify a different `fileURL` explicitly for each of them. - parameter configuration: an optional configuration name from the model file. If not specified, defaults to `nil`, the "Default" configuration. Note that if you have multiple configurations, you will need to specify a different `fileURL` explicitly for each of them.
- parameter mappingModelBundles: a list of `NSBundle`s from which to search mapping models for migration.
- parameter localStorageOptions: When the `CSSQLiteStore` is passed to the `CSDataStack`'s `addStorage()` methods, tells the `CSDataStack` how to setup the persistent store. Defaults to `CSLocalStorageOptionsNone`. - parameter localStorageOptions: When the `CSSQLiteStore` is passed to the `CSDataStack`'s `addStorage()` methods, tells the `CSDataStack` how to setup the persistent store. Defaults to `CSLocalStorageOptionsNone`.
*/ */
@objc @objc
public convenience init(fileURL: NSURL, configuration: String?, mappingModelBundles: [NSBundle]?, localStorageOptions: Int) { public convenience init(fileURL: URL, configuration: ModelConfiguration, localStorageOptions: Int) {
self.init( self.init(
SQLiteStore( SQLiteStore(
fileURL: fileURL, fileURL: fileURL,
configuration: configuration, configuration: configuration,
mappingModelBundles: mappingModelBundles ?? NSBundle.allBundles(),
localStorageOptions: LocalStorageOptions(rawValue: localStorageOptions) localStorageOptions: LocalStorageOptions(rawValue: localStorageOptions)
) )
) )
@@ -61,29 +60,27 @@ public final class CSSQLiteStore: NSObject, CSLocalStorage, CoreStoreObjectiveCT
/** /**
Initializes an SQLite store interface from the given SQLite file name. When this instance is passed to the `CSDataStack`'s `-addStorage*:` methods, a new SQLite file will be created if it does not exist. Initializes an SQLite store interface from the given SQLite file name. When this instance is passed to the `CSDataStack`'s `-addStorage*:` methods, a new SQLite file will be created if it does not exist.
- Warning: The default SQLite file location for the `CSLegacySQLiteStore` and `CSSQLiteStore` are different. If the app was depending on CoreStore's default directories prior to 2.0.0, make sure to use `CSLegacySQLiteStore` instead of `CSSQLiteStore`. - Important: Initializing `CSSQLiteStore`s with custom migration mapping models is currently not supported. Create an `SQLiteStore` instance from Swift code and bridge the instance to Objective-C using its `SQLiteStore.bridgeToObjectiveC` property.
- parameter fileName: the local filename for the SQLite persistent store in the "Application Support/<bundle id>" directory (or the "Caches/<bundle id>" directory on tvOS). Note that if you have multiple configurations, you will need to specify a different `fileName` explicitly for each of them. - parameter fileName: the local filename for the SQLite persistent store in the "Application Support/<bundle id>" directory (or the "Caches/<bundle id>" directory on tvOS). Note that if you have multiple configurations, you will need to specify a different `fileName` explicitly for each of them.
- parameter configuration: an optional configuration name from the model file. If not specified, defaults to `nil`, the "Default" configuration. Note that if you have multiple configurations, you will need to specify a different `fileName` explicitly for each of them. - parameter configuration: an optional configuration name from the model file. If not specified, defaults to `nil`, the "Default" configuration. Note that if you have multiple configurations, you will need to specify a different `fileName` explicitly for each of them.
- parameter mappingModelBundles: a list of `NSBundle`s from which to search mapping models for migration
- parameter localStorageOptions: When the `CSSQLiteStore` is passed to the `CSDataStack`'s `addStorage()` methods, tells the `CSDataStack` how to setup the persistent store. Defaults to `[CSLocalStorageOptions none]`. - parameter localStorageOptions: When the `CSSQLiteStore` is passed to the `CSDataStack`'s `addStorage()` methods, tells the `CSDataStack` how to setup the persistent store. Defaults to `[CSLocalStorageOptions none]`.
*/ */
@objc @objc
public convenience init(fileName: String, configuration: String?, mappingModelBundles: [NSBundle]?, localStorageOptions: Int) { public convenience init(fileName: String, configuration: ModelConfiguration, localStorageOptions: Int) {
self.init( self.init(
SQLiteStore( SQLiteStore(
fileName: fileName, fileName: fileName,
configuration: configuration, configuration: configuration,
mappingModelBundles: mappingModelBundles ?? NSBundle.allBundles(),
localStorageOptions: LocalStorageOptions(rawValue: localStorageOptions) localStorageOptions: LocalStorageOptions(rawValue: localStorageOptions)
) )
) )
} }
/** /**
Initializes an `CSSQLiteStore` with an all-default settings: a `fileURL` pointing to a "<Application name>.sqlite" file in the "Application Support/<bundle id>" directory (or the "Caches/<bundle id>" directory on tvOS), a `nil` `configuration` pertaining to the "Default" configuration, a `mappingModelBundles` set to search all `NSBundle`s, and `localStorageOptions` set to `.AllowProgresiveMigration`. Initializes an `CSSQLiteStore` with an all-default settings: a `fileURL` pointing to a "<Application name>.sqlite" file in the "Application Support/<bundle id>" directory (or the "Caches/<bundle id>" directory on tvOS), a `nil` `configuration` pertaining to the "Default" configuration, a `mappingModelBundles` set to search all `NSBundle`s, and `localStorageOptions` set to `[CSLocalStorageOptions none]`.
- Warning: The default SQLite file location for the `CSLegacySQLiteStore` and `CSSQLiteStore` are different. If the app was depending on CoreStore's default directories prior to 2.0.0, make sure to use `CSLegacySQLiteStore` instead of `CSSQLiteStore`. - Important: Initializing `CSSQLiteStore`s with custom migration mapping models is currently not supported. Create an `SQLiteStore` instance from Swift code and bridge the instance to Objective-C using its `SQLiteStore.bridgeToObjectiveC` property.
*/ */
@objc @objc
public convenience override init() { public convenience override init() {
@@ -98,18 +95,18 @@ public final class CSSQLiteStore: NSObject, CSLocalStorage, CoreStoreObjectiveCT
The `NSURL` that points to the SQLite file The `NSURL` that points to the SQLite file
*/ */
@objc @objc
public var fileURL: NSURL { public var fileURL: URL {
return self.bridgeToSwift.fileURL return self.bridgeToSwift.fileURL as URL
} }
/** /**
The `NSBundle`s from which to search mapping models for migrations An array of `SchemaMappingProvider`s that provides the complete mapping models for custom migrations. This is currently only supported for Swift code.
*/ */
@objc @objc
public var mappingModelBundles: [NSBundle] { public var migrationMappingProviders: [Any] {
return self.bridgeToSwift.mappingModelBundles return self.bridgeToSwift.migrationMappingProviders
} }
/** /**
@@ -133,7 +130,7 @@ public final class CSSQLiteStore: NSObject, CSLocalStorage, CoreStoreObjectiveCT
/** /**
The configuration name in the model file The configuration name in the model file
*/ */
public var configuration: String? { public var configuration: ModelConfiguration {
return self.bridgeToSwift.configuration return self.bridgeToSwift.configuration
} }
@@ -145,7 +142,7 @@ public final class CSSQLiteStore: NSObject, CSLocalStorage, CoreStoreObjectiveCT
``` ```
*/ */
@objc @objc
public var storeOptions: [String: AnyObject]? { public var storeOptions: [AnyHashable: Any]? {
return self.bridgeToSwift.storeOptions return self.bridgeToSwift.storeOptions
} }
@@ -154,11 +151,11 @@ public final class CSSQLiteStore: NSObject, CSLocalStorage, CoreStoreObjectiveCT
Called by the `CSDataStack` to perform actual deletion of the store file from disk. Do not call directly! The `sourceModel` argument is a hint for the existing store's model version. For `CSSQLiteStore`, this converts the database's WAL journaling mode to DELETE before deleting the file. Called by the `CSDataStack` to perform actual deletion of the store file from disk. Do not call directly! The `sourceModel` argument is a hint for the existing store's model version. For `CSSQLiteStore`, this converts the database's WAL journaling mode to DELETE before deleting the file.
*/ */
@objc @objc
public func eraseStorageAndWait(soureModel soureModel: NSManagedObjectModel, error: NSErrorPointer) -> Bool { public func cs_eraseStorageAndWait(metadata: NSDictionary, soureModelHint: NSManagedObjectModel?, error: NSErrorPointer) -> Bool {
return bridge(error) { return bridge(error) {
try self.bridgeToSwift.eraseStorageAndWait(soureModel: soureModel) try self.bridgeToSwift.cs_eraseStorageAndWait(metadata: metadata as! [String: Any], soureModelHint: soureModelHint)
} }
} }
@@ -170,7 +167,7 @@ public final class CSSQLiteStore: NSObject, CSLocalStorage, CoreStoreObjectiveCT
return ObjectIdentifier(self.bridgeToSwift).hashValue return ObjectIdentifier(self.bridgeToSwift).hashValue
} }
public override func isEqual(object: AnyObject?) -> Bool { public override func isEqual(_ object: Any?) -> Bool {
guard let object = object as? CSSQLiteStore else { guard let object = object as? CSSQLiteStore else {
@@ -181,7 +178,7 @@ public final class CSSQLiteStore: NSObject, CSLocalStorage, CoreStoreObjectiveCT
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)"
} }
@@ -194,6 +191,23 @@ public final class CSSQLiteStore: NSObject, CSLocalStorage, CoreStoreObjectiveCT
self.bridgeToSwift = swiftValue self.bridgeToSwift = swiftValue
super.init() super.init()
} }
// MARK: Obsoleted
@available(*, obsoleted: 3.1, message: "The `mappingModelBundles` argument of this method is ignored. Use the new -[CSSQLiteStore initWithFileURL:configuration:localStorageOptions:]) initializer instead.")
@objc
public convenience init(fileURL: URL, configuration: ModelConfiguration, mappingModelBundles: [Bundle]?, localStorageOptions: Int) {
fatalError()
}
@available(*, obsoleted: 3.1, message: "The `mappingModelBundles` argument of this method is ignored. Use the new -[CSSQLiteStore initWithFileName:configuration:localStorageOptions:]) initializer instead.")
@objc
public convenience init(fileName: String, configuration: ModelConfiguration, mappingModelBundles: [Bundle]?, localStorageOptions: Int) {
fatalError()
}
} }
@@ -203,5 +217,8 @@ extension SQLiteStore: CoreStoreSwiftType {
// MARK: CoreStoreSwiftType // MARK: CoreStoreSwiftType
public typealias ObjectiveCType = CSSQLiteStore public var bridgeToObjectiveC: CSSQLiteStore {
return CSSQLiteStore(self)
}
} }

147
Sources/CSSaveResult.swift Normal file
View File

@@ -0,0 +1,147 @@
//
// CSSaveResult.swift
// CoreStore
//
// Copyright © 2016 John Rommel Estropia
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in all
// copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
// SOFTWARE.
//
import Foundation
import CoreData
// MARK: - CSSaveResult
@available(*, deprecated, message: "Use APIs that report failures with `CSError`s instead.")
@objc
public final class CSSaveResult: NSObject, CoreStoreObjectiveCType {
@objc
public var isSuccess: Bool {
return self.bridgeToSwift.boolValue
}
@objc
public var isFailure: Bool {
return !self.bridgeToSwift.boolValue
}
@objc
public var hasChanges: Bool {
guard case .success(let hasChanges) = self.bridgeToSwift else {
return false
}
return hasChanges
}
@objc
public var error: NSError? {
guard case .failure(let error) = self.bridgeToSwift else {
return nil
}
return error.bridgeToObjectiveC
}
@objc
public func handleSuccess(_ success: (_ hasChanges: Bool) -> Void, failure: (_ error: NSError) -> Void) {
switch self.bridgeToSwift {
case .success(let hasChanges):
success(hasChanges)
case .failure(let error):
failure(error.bridgeToObjectiveC)
}
}
@objc
public func handleSuccess(_ success: (_ hasChanges: Bool) -> Void) {
guard case .success(let hasChanges) = self.bridgeToSwift else {
return
}
success(hasChanges)
}
@objc
public func handleFailure(_ failure: (_ error: NSError) -> Void) {
guard case .failure(let error) = self.bridgeToSwift else {
return
}
failure(error.bridgeToObjectiveC)
}
// MARK: NSObject
public override var hash: Int {
return self.bridgeToSwift.hashValue
}
public override func isEqual(_ object: Any?) -> Bool {
guard let object = object as? CSSaveResult else {
return false
}
return self.bridgeToSwift == object.bridgeToSwift
}
public override var description: String {
return "(\(String(reflecting: type(of: self)))) \(self.bridgeToSwift.coreStoreDumpString)"
}
// MARK: CoreStoreObjectiveCType
public let bridgeToSwift: SaveResult
public required init(_ swiftValue: SaveResult) {
self.bridgeToSwift = swiftValue
super.init()
}
}
// MARK: - SaveResult
@available(*, deprecated, message: "Use the new DataStack.perform(asynchronous:...) and DataStack.perform(synchronous:...) family of APIs")
extension SaveResult: CoreStoreSwiftType {
// MARK: CoreStoreSwiftType
public var bridgeToObjectiveC: CSSaveResult {
return CSSaveResult(self)
}
}

View File

@@ -27,8 +27,6 @@ import Foundation
import CoreData import CoreData
#if os(iOS) || os(watchOS) || os(tvOS)
// MARK: - CSSectionBy // MARK: - CSSectionBy
/** /**
@@ -36,6 +34,7 @@ import CoreData
- SeeAlso: `SectionBy` - SeeAlso: `SectionBy`
*/ */
@available(OSX 10.12, *)
@objc @objc
public final class CSSectionBy: NSObject, CoreStoreObjectiveCType { public final class CSSectionBy: NSObject, CoreStoreObjectiveCType {
@@ -46,7 +45,7 @@ public final class CSSectionBy: NSObject, CoreStoreObjectiveCType {
- returns: a `CSSectionBy` clause with the key path to use to group `CSListMonitor` objects into sections - returns: a `CSSectionBy` clause with the key path to use to group `CSListMonitor` objects into sections
*/ */
@objc @objc
public static func keyPath(sectionKeyPath: KeyPath) -> CSSectionBy { public static func keyPath(_ sectionKeyPath: KeyPath) -> CSSectionBy {
return self.init(SectionBy(sectionKeyPath)) return self.init(SectionBy(sectionKeyPath))
} }
@@ -59,7 +58,7 @@ public final class CSSectionBy: NSObject, CoreStoreObjectiveCType {
- returns: a `CSSectionBy` clause with the key path to use to group `CSListMonitor` objects into sections - returns: a `CSSectionBy` clause with the key path to use to group `CSListMonitor` objects into sections
*/ */
@objc @objc
public static func keyPath(sectionKeyPath: KeyPath, sectionIndexTransformer: (sectionName: String?) -> String?) -> CSSectionBy { public static func keyPath(_ sectionKeyPath: KeyPath, sectionIndexTransformer: @escaping (_ sectionName: String?) -> String?) -> CSSectionBy {
return self.init(SectionBy(sectionKeyPath, sectionIndexTransformer)) return self.init(SectionBy(sectionKeyPath, sectionIndexTransformer))
} }
@@ -69,7 +68,7 @@ public final class CSSectionBy: NSObject, CoreStoreObjectiveCType {
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,11 +86,13 @@ public final class CSSectionBy: NSObject, CoreStoreObjectiveCType {
// MARK: - SectionBy // MARK: - SectionBy
@available(OSX 10.12, *)
extension SectionBy: CoreStoreSwiftType { extension SectionBy: CoreStoreSwiftType {
// MARK: CoreStoreSwiftType // MARK: CoreStoreSwiftType
public typealias ObjectiveCType = CSSectionBy public var bridgeToObjectiveC: CSSectionBy {
return CSSectionBy(self)
}
} }
#endif

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