Compare commits

...

567 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
John Rommel Estropia f486ace437 make cocoapods happy 2016-07-12 00:16:02 +09:00
John Estropia edb2aa2463 Update README.md 2016-07-11 13:40:26 +09:00
John Estropia 7b48d825a3 Update README.md 2016-07-11 13:38:21 +09:00
John Rommel Estropia 921b85d91b documentation updates 2016-07-11 02:04:18 +09:00
John Estropia 4f46cbded9 Update README.md 2016-07-11 02:01:24 +09:00
John Estropia a8af91b2f8 Update README.md 2016-07-11 00:55:01 +09:00
John Estropia 8a8b3fa0b1 Update README.md 2016-07-10 23:01:53 +09:00
John Estropia 4196ed8085 Update README.md 2016-07-10 15:49:08 +09:00
John Estropia 0458de5d65 Update README.md 2016-07-10 15:37:52 +09:00
John Estropia 90ae17e904 Update README.md
WIP
2016-07-10 15:31:59 +09:00
John Estropia 3c0d4d648d Update README.md
WIP
2016-07-09 18:44:26 +09:00
John Estropia b60bcf8da6 Update README.md 2016-07-09 17:21:47 +09:00
John Rommel Estropia f9014e65e0 objc keypath utilities 2016-07-01 01:06:16 +09:00
John Rommel Estropia 82887b1dd2 CSInto unit tests 2016-06-25 13:43:43 +09:00
John Estropia 11d428c05c import magic for objective c utils 2016-06-20 20:28:25 +09:00
John Estropia 0b48bb3347 renamed CSFromCreate() to CSFromClass() 2016-06-20 19:36:57 +09:00
John Estropia aa5cd51da6 Merge branch 'develop' into corestore2_develop 2016-06-20 19:18:42 +09:00
John Estropia e50dd9881d allow accessing a ListMonitor as a flat array when using API's without section info 2016-06-20 19:18:31 +09:00
John Rommel Estropia 3ccbce5c29 WIP: utilities for clauses 2016-06-20 08:09:11 +09:00
John Rommel Estropia e5a199489c WIP: objc utilities 2016-06-19 02:40:25 +09:00
John Rommel Estropia 3d5c4f8121 removed unit test check for undefined behavior 2016-06-17 02:44:37 +09:00
John Rommel Estropia 2dc09289bf fixed platform dependencies 2016-06-17 01:24:19 +09:00
John Rommel Estropia 76a2bc1da2 importing unit tests 2016-06-12 20:34:13 +09:00
John Rommel Estropia 8e5c7ec9b2 querying unit tests 2016-06-11 22:57:00 +09:00
John Rommel Estropia 101ab69861 added testing for logger behaviors 2016-06-11 21:13:06 +09:00
John Rommel Estropia ea2a65cf57 Merge branch 'corestore2_develop' of github.com:JohnEstropia/CoreStore into corestore2_develop 2016-06-11 19:10:12 +09:00
John Rommel Estropia f59b1b6320 WIP: query tests 2016-06-11 19:09:56 +09:00
John Estropia 141e977f9c remove sort assertion when using ObjectMonitor 2016-06-09 18:56:32 +09:00
John Estropia 788cce0df6 Merge branch 'corestore2_develop' of https://github.com/JohnEstropia/CoreStore into corestore2_develop
# Conflicts:
#	Sources/Observing/ListMonitor.swift
2016-06-09 18:23:59 +09:00
John Estropia 4304d8687e Merge branch 'develop' into corestore2_develop 2016-06-09 18:20:58 +09:00
John Estropia d25f751089 oops 2016-06-09 18:20:49 +09:00
John Estropia 6df78a0595 Merge branch 'develop' into corestore2_develop
# Conflicts:
#	Sources/Observing/ListMonitor.swift
2016-06-09 18:12:18 +09:00
John Estropia c0ed2f23ce ignore negative indexes when using ListMonitor's safeIndex APIs 2016-06-09 18:06:08 +09:00
John Estropia dcf562fb26 ignore negative indexes when using ListMonitor's safeIndex API 2016-06-09 17:57:15 +09:00
John Rommel Estropia b9353238e8 transaction fetching unit tests 2016-06-07 00:14:22 +09:00
John Rommel Estropia b98805e489 WIP: Fetching unit tests 2016-06-06 00:12:00 +09:00
John Rommel Estropia 02a89accc8 Merge branch 'develop' into corestore2_develop
# Conflicts:
#	CoreStore.podspec
#	Sources/Info.plist
#	Sources/Internal/CoreStoreFetchRequest.swift
2016-06-05 17:20:59 +09:00
John Rommel Estropia 2e4c9a7a25 fix From clauses not setting the NSFetchRequest's affectedStores property properly 2016-06-05 17:19:20 +09:00
John Rommel Estropia fcca6b205e WIP: Unit tests 2016-06-04 14:29:10 +09:00
John Rommel Estropia b199f38b0c Merge branch 'master' into corestore2_develop
# Conflicts:
#	CoreStore.podspec
#	Sources/Info.plist
2016-05-28 22:40:01 +09:00
John Rommel Estropia 0c8731c610 improved flushing behavior 2016-05-28 22:34:14 +09:00
John Rommel Estropia ee4eb178ed Merge branch 'master' into corestore2_develop
# Conflicts:
#	CoreStore.podspec
#	Sources/Convenience/NSFetchedResultsController+Convenience.swift
#	Sources/Info.plist
2016-05-28 11:46:31 +09:00
John Rommel Estropia f617f2cc53 Simpler API for creating CoreStore-managed NSFetchedResultsControllers, useful for external SDK's that require them 2016-05-28 01:47:48 +09:00
John Rommel Estropia f396b01043 fixed Cartfile dependency 2016-05-26 01:28:26 +09:00
John Rommel Estropia 7942cf411e WIP: clauses unit tests 2016-05-26 01:03:01 +09:00
John Rommel Estropia 02be72b0b7 Merge branch 'master' into corestore2_develop
# Conflicts:
#	CoreStore.podspec
#	Sources/Info.plist
#	Sources/Transactions/UnsafeDataTransaction.swift
2016-05-25 21:41:44 +09:00
John Rommel Estropia e38093342d version bump, updated dependendencies 2016-05-24 00:42:35 +09:00
John Rommel Estropia c15afcb381 Allow flushing UnsafeDataTransactions to notify its ListMonitors and ObjectMonitors without saving changes to the DataStack (fixes #71) 2016-05-24 00:40:13 +09:00
John Rommel Estropia a97001cdbb fixed scheme 2016-05-24 00:32:54 +09:00
John Rommel Estropia 000a357808 WIP: test cases 2016-05-23 23:40:00 +09:00
John Estropia c8ca16a982 Merge pull request #69 from bretsko/master
fixed Readme
2016-05-17 14:05:11 +09:00
Oleksandr Bretsko 9e0493a20d fixed Readme
replaced importObjects with importUniqueObjects
2016-05-17 08:43:40 +04:00
John Estropia 77236d66d5 relax NSManagedObject return types so callers don't need to cast every time 2016-05-11 21:55:51 +09:00
John Estropia 8b95d337a3 relax NSManagedObject return types so callers don't need to cast every time 2016-05-10 21:49:50 +09:00
John Rommel Estropia 57b66cff34 implementations for desctiption and debugDescription complete for all CoreStore types 2016-05-08 20:30:28 +09:00
John Rommel Estropia 9dae291f62 WIP: logging clauses 2016-05-08 00:28:36 +09:00
John Rommel Estropia 0c2a3ac4e9 fix merge 2016-05-07 18:13:44 +08:00
John Rommel Estropia a6291e116c Merge branch 'master' into corestore2_develop
# Conflicts:
#	CoreStore.podspec
#	Sources/Info.plist
#	Sources/Internal/NSManagedObjectContext+Transaction.swift
2016-05-07 17:47:35 +08:00
John Rommel Estropia c990f7764a version bump 2016-05-07 12:19:30 +08:00
John Rommel Estropia 26ae6293ca merge changes to main context synchronously or asynchronously depending on the caller intention (fixes #65) 2016-05-07 12:18:54 +08:00
John Rommel Estropia b9a2f96d6e renamed refreshAllObjectsAsFaults to refreshAndMergeAllObjects, which is more correct 2016-05-07 12:04:59 +08:00
John Rommel Estropia ae5f737baf WIP: logging clauses 2016-05-07 12:01:31 +08:00
John Rommel Estropia 4eecd80710 WIP: pretty logging 2016-05-06 09:19:24 +08:00
John Rommel Estropia 0073d038e0 WIP: logging utilities 2016-05-05 09:44:14 +08:00
John Rommel Estropia 099dcfab68 Merge branch 'develop' into corestore2_develop
# Conflicts:
#	CoreStore.podspec
#	Sources/Info.plist
2016-05-02 18:22:43 +08:00
John Rommel Estropia 74fe81bfa7 Fix problem when using carthage where the iOS7 framework overwrites the iOS 8 framework 2016-05-02 12:02:31 +08:00
John Rommel Estropia 0bbb4118a1 documentation for iCloud methods 2016-04-30 01:20:35 +09:00
John Rommel Estropia 3fe9e4ee1d WIP: ICloudStore prototype 2016-04-30 00:26:06 +09:00
John Rommel Estropia bd19326447 folder structure 2016-04-03 19:55:10 +09:00
John Rommel Estropia dccc958ef1 comment documentations 2016-04-03 19:47:25 +09:00
John Rommel Estropia ab3095f078 WIP: documentation 2016-04-03 13:37:00 +09:00
John Rommel Estropia 1a86510045 Group Swift files 2016-04-03 12:20:13 +09:00
John Rommel Estropia aa32f5e158 support value querying in Objective C 2016-04-02 21:39:05 +09:00
John Rommel Estropia b95aaf151d Merge branch 'corestore2_develop' into corestore2_develop_objc 2016-04-01 07:47:03 +09:00
John Rommel Estropia 114bc71841 Merge branch 'develop' into corestore2_develop
# Conflicts:
#	CoreStore.podspec
#	Sources/Info.plist
2016-04-01 07:46:42 +09:00
John Rommel Estropia dff552b95f version bump 2016-04-01 07:42:00 +09:00
John Rommel Estropia 88cac73b20 fix assertion error 2016-04-01 07:41:23 +09:00
John Rommel Estropia 83d0412cb9 Merge branch 'corestore2_develop' into corestore2_develop_objc
# Conflicts:
#	CoreStore.xcodeproj/project.pbxproj
2016-04-01 07:20:42 +09:00
John Rommel Estropia 26e4118355 Merge branch 'develop' into corestore2_develop
# Conflicts:
#	CoreStore.podspec
#	CoreStore.xcodeproj/project.pbxproj
#	CoreStore/Setting Up/DataStack.swift
#	Sources/Info.plist
2016-04-01 07:18:53 +09:00
John Rommel Estropia 0c564add46 separate CoreStoreFetchRequest file 2016-04-01 07:04:02 +09:00
John Rommel Estropia 784a315fb9 version bump 2016-04-01 01:32:32 +09:00
John Rommel Estropia 44cfbebedb prevent deadlock on when DataStack gets deallocated 2016-04-01 01:28:39 +09:00
John Rommel Estropia 0b24072259 Workaround CoreData's bug when using NSFetchRequest's affectedStores property 2016-04-01 01:22:16 +09:00
John Rommel Estropia 28b7ba01dc prevent deadlock on when DataStack gets deallocated 2016-03-31 00:04:17 +09:00
John Rommel Estropia b529735269 Merge branch 'corestore2_develop' into corestore2_develop_objc
# Conflicts:
#	Sources/Observing/ListMonitor.swift
2016-03-30 21:41:44 +09:00
John Rommel Estropia d23121d8ed Merge branch 'develop' into corestore2_develop
# Conflicts:
#	Sources/Observing/ListMonitor.swift
2016-03-30 21:40:21 +09:00
John Rommel Estropia 633ab0a249 cache fetchClauses in property so closures do not retain them indeterminately 2016-03-30 21:16:10 +09:00
John Rommel Estropia 410feda5cd tidy up 2016-03-30 20:47:13 +09:00
John Rommel Estropia 06e952af8a clear FRC delegate on deinit 2016-03-30 20:28:10 +09:00
John Estropia a4d3d0c0ed fix mistype 2016-03-30 13:05:29 +09:00
John Estropia 8b7af86526 WIP: Objective-C bridge (90% done!) 2016-03-30 11:12:17 +09:00
John Estropia 48a8694720 attempt to fix closure deallocation bug (#58) 2016-03-30 05:22:05 +09:00
John Rommel Estropia 09d844f5df WIP: CSSetupResult 2016-03-30 01:55:06 +09:00
John Estropia e25e198bf8 WIP: Objective-C migrations 2016-03-29 14:46:31 +09:00
John Estropia e99d19d2ac ListMonitor and ObjectMonitor objective C bridge 2016-03-29 14:15:57 +09:00
John Estropia 9d7960e674 typed arrays 2016-03-28 19:41:11 +09:00
John Estropia e9ac8629a1 tidy up 2016-03-28 19:35:09 +09:00
John Estropia b0b0df2861 allow public access to bridgeToObjectiveC and bridgeToSwift properties 2016-03-28 19:07:35 +09:00
John Estropia eda398d758 WIP: CSListMonitor 2016-03-28 17:19:51 +09:00
John Rommel Estropia 40c320e1ca add missing files in scheme 2016-03-28 00:43:14 +09:00
John Rommel Estropia 8508dd4f79 delete iCloud folder 2016-03-27 23:13:01 +09:00
John Rommel Estropia d3e0f576cf tidy up 2016-03-27 23:12:21 +09:00
John Rommel Estropia 1d5cf5a4cc Merge branch 'corestore2_develop' into corestore2_develop_objc 2016-03-27 23:03:37 +09:00
John Rommel Estropia 9fc0390b45 Merge branch 'develop' into corestore2_develop 2016-03-27 23:03:21 +09:00
John Rommel Estropia b8ea7ecf01 WIP: objective-C fetching 2016-03-27 23:02:24 +09:00
John Estropia 11ac362dcc Update README.md 2016-03-27 20:32:14 +09:00
John Estropia 10c20e0d62 Update README.md 2016-03-27 10:28:35 +09:00
John Estropia 789028bc58 WIP: CSImportableUniqueObject 2016-03-25 19:59:31 +09:00
John Estropia a168ca577a Merge branch 'corestore2_develop' into corestore2_develop_objc 2016-03-25 19:28:47 +09:00
John Estropia 781f3988d2 Merge branch 'develop' into corestore2_develop
# Conflicts:
#	CoreStoreDemo/CoreStoreDemo/Loggers Demo/CustomLoggerViewController.swift
#	CoreStoreDemo/CoreStoreDemo/Transactions Demo/TransactionsDemoViewController.swift
2016-03-25 19:28:37 +09:00
John Estropia b914a4b5ed updated Readme 2016-03-25 18:20:24 +09:00
John Estropia 7de13131a4 small demo fix 2016-03-25 18:18:17 +09:00
John Estropia 0c1af09a8d Make demo app compile again (sorry) (fixes #57) 2016-03-25 18:08:03 +09:00
John Estropia 1ff635d8b5 WIP: CSImportableObject 2016-03-25 17:57:26 +09:00
John Rommel Estropia 707445a169 WIP: SaveResult bridge 2016-03-25 07:57:09 +09:00
John Estropia 90369cf994 WIP: simpler bridging 2016-03-24 21:22:58 +09:00
John Estropia 09708e587c Merge branch 'corestore2_develop' into corestore2_develop_objc
# Conflicts:
#	CoreStore.xcodeproj/project.pbxproj
2016-03-24 15:16:13 +09:00
John Estropia 36e6e4a8b9 Merge branch 'develop' into corestore2_develop
# Conflicts:
#	Cartfile
#	Cartfile.resolved
#	CoreStore.podspec
#	CoreStore.xcodeproj/project.pbxproj
#	CoreStore/Migrating/DataStack+Migration.swift
#	CoreStore/Setting Up/DataStack.swift
#	README.md
#	Sources/Info.plist
2016-03-24 15:09:36 +09:00
John Rommel Estropia 9f1a351311 add missing scheme 2016-03-23 23:20:24 +09:00
John Rommel Estropia 6e202aa7ca set missing build setting 2016-03-23 22:31:16 +09:00
John Rommel Estropia 783b933294 add missing file 2016-03-23 22:26:39 +09:00
John Rommel Estropia ca49ea3a81 iOS 7 full support 2016-03-23 22:21:05 +09:00
John Rommel Estropia ed8891a6d5 Merge branch 'corestore2_develop' into corestore2_develop_objc
# Conflicts:
#	Sources/Migrating/MigrationChain.swift
2016-03-23 21:24:30 +09:00
John Rommel Estropia dd6c6abaf0 Merge branch 'develop' into corestore2_develop
# Conflicts:
#	CoreStore.podspec
#	CoreStore/CartFile
#	README.md
#	Sources/Info.plist
#	Sources/Internal/NSManagedObjectModel+Setup.swift
#	Sources/Logging/CoreStore+Logging.swift
2016-03-23 21:23:08 +09:00
John Estropia 928585029d XCode 7.3 full support 2016-03-23 12:39:11 +09:00
John Estropia dc6d22b6ff updated travis XCode version 2016-03-23 12:14:34 +09:00
John Estropia 5ca0f657cb XCode 7.3 fixes 2016-03-23 12:07:31 +09:00
John Estropia 2c65ac1834 WIP: transactions in ObjC 2016-03-23 11:32:35 +09:00
John Rommel Estropia 24008d62b2 WIP: error handling 2016-03-22 22:51:42 +09:00
John Rommel Estropia e8a9cc9d67 WIP: error handling 2016-03-22 07:23:11 +09:00
John Estropia 1507ac63f9 WIP: objective C storages 2016-03-18 20:32:23 +09:00
John Rommel Estropia f2df8f7171 WIP: objective C interface 2016-03-18 02:39:18 +09:00
John Rommel Estropia 3ddfd3cccc WIP: objc setup 2016-03-17 07:51:22 +09:00
John Estropia 21f57518c8 WIP: Objective-C bridge 2016-03-16 21:23:41 +09:00
John Rommel Estropia d9422f7f2e Changed error-handling method to rely on new enum CoreStoreError instead of NSErrors 2016-03-16 07:56:19 +09:00
John Estropia 245ec25ad8 Update README.md 2016-03-15 16:24:51 +09:00
John Rommel Estropia 0ce89b8460 WIP: documentation 2016-03-15 07:57:02 +09:00
John Rommel Estropia 42a889a28e WIP: documentation 2016-03-14 07:57:49 +09:00
John Rommel Estropia 456977bf12 renamed default directories 2016-03-13 11:21:01 +09:00
John Rommel Estropia ea8412ab93 removed Nimble 2016-03-13 11:10:09 +09:00
John Rommel Estropia 603dffffb0 WIP: documentation and unit tests 2016-03-12 20:13:38 +09:00
John Rommel Estropia 8a1144b1be Merge branch 'develop' into corestore2_develop
# Conflicts:
#	README.md
2016-03-12 10:37:33 +09:00
John Rommel Estropia c323a28c19 fix warnings in demo app 2016-03-12 09:27:59 +09:00
John Rommel Estropia 4ff7b2d6d9 WIP: documentation 2016-03-12 00:16:54 +09:00
John Estropia 64ad7b3bfd Update README.md 2016-03-11 20:59:52 +09:00
John Estropia df441c5d04 Update README.md 2016-03-11 20:58:33 +09:00
John Estropia fa947faa57 make demo app for migrations initialize smoother 2016-03-10 20:28:19 +09:00
John Estropia 6822a4579e WIP: clean up persistent store setup 2016-03-10 20:19:52 +09:00
John Estropia a89dd76906 WIP: tidy up 2016-03-09 19:42:17 +09:00
John Estropia c85ef16ad0 WIP: tidy up 2016-03-09 18:49:00 +09:00
John Estropia 67f1bd9a63 updated travis.yml 2016-03-09 17:51:45 +09:00
John Estropia 39540628df updated travis.yml 2016-03-09 17:48:54 +09:00
John Estropia c86ca06bd4 Swift Package Manager support 2016-03-09 17:47:46 +09:00
John Estropia 40c27b9fcb Merge branch 'master' into corestore2_develop 2016-03-08 15:54:24 +09:00
John Rommel Estropia 2f8c100cb6 WIP: StorageInterface 2016-03-08 07:55:15 +09:00
John Rommel Estropia 34495d7163 WIP: prevent error when adding non-existent file 2016-03-07 07:35:55 +09:00
John Rommel Estropia 75a4ebb49b WIP: StorageInterface methods 2016-03-07 07:23:44 +09:00
John Rommel Estropia 3c514830d9 WIP: SQLiteStore implementation 2016-03-04 07:51:35 +09:00
John Estropia b283fbf5ab WIP: StorageInterface 2016-03-03 20:03:13 +09:00
John Estropia c1e087b8c1 goodbye strongSelf 2016-03-03 12:51:56 +09:00
John Rommel Estropia ad1ebb3501 WIP: StorageInterface protocol 2016-03-03 07:50:43 +09:00
John Rommel Estropia 99189d160f WIP: Storage protocol 2016-03-02 08:02:33 +09:00
John Estropia 3c2fb28644 added Packaged.swift 2016-03-01 19:42:28 +09:00
John Rommel Estropia f71ad4c577 WIP: Storage protocols 2016-03-01 08:01:40 +09:00
John Rommel Estropia d05fcc5103 updated demo app for deprecated methods 2016-02-29 22:26:34 +09:00
John Rommel Estropia e9329fc93c better quality image 2016-02-28 01:21:00 +09:00
John Rommel Estropia 1ea773f0ec added CoreStore logo 2016-02-27 16:01:48 +09:00
John Rommel Estropia c68c2bdc0a Merge branch 'develop' into corestore2_develop
Conflicts:
	CoreStore.podspec
	CoreStore/Info.plist
2016-02-26 01:51:35 +09:00
John Estropia e66a13632a Merge branch 'develop' 2016-02-25 15:52:59 +09:00
John Estropia 4c78a309bc deprecated NSFetchedResultsController initializer in favor of static factory method 2016-02-25 15:52:49 +09:00
John Estropia 9055daa58c Merge branch 'develop' 2016-02-25 15:11:40 +09:00
John Estropia 3905423038 fix compile error 2016-02-25 15:05:27 +09:00
John Estropia 15353268e2 Allow unsafe transactions to save synchronously 2016-02-25 15:04:05 +09:00
John Rommel Estropia 91dd4b6cb3 tidy up 2016-02-25 07:14:15 +09:00
John Rommel Estropia 0800b706d6 revert 2016-02-24 22:04:14 +09:00
John Rommel Estropia 2071ce722e WIP: iCloud support 2016-02-24 22:03:14 +09:00
John Rommel Estropia df866718cf tidy up 2016-02-24 22:02:26 +09:00
John Rommel Estropia f19a0d29eb added obsolete annotations to previously deprecated methods 2016-02-24 21:52:35 +09:00
John Estropia 8f09f90294 Changed default directories to comply with Apple's guidelines (TODO: update README) 2016-02-24 18:57:03 +09:00
John Estropia 7bddcaa4a2 swift 2.2 (Xcode 7.3 beta 4) updates 2016-02-24 16:54:39 +09:00
John Estropia c12331f403 Merge pull request #53 from mpurbo/patch-1
added missing closing bracket on sample code.
2016-02-22 22:26:38 +09:00
Mamad Purbo a55a8d389c added missing closing bracket on sample code. 2016-02-22 11:50:28 +09:00
John Rommel Estropia 6e88b14237 fixed readme build status 2016-02-20 12:30:02 +09:00
John Rommel Estropia 53700a267f version bump 2016-02-20 12:28:39 +09:00
John Rommel Estropia 6c95b010e9 utility to update an existing ImportableObject from its ImportSource (fixes #52) 2016-02-20 12:26:23 +09:00
John Rommel Estropia 1af675e8b7 tidy up 2016-02-20 12:05:01 +09:00
John Rommel Estropia b85f16cf68 Merge branch 'master' into develop 2016-02-20 01:25:40 +09:00
John Estropia 37bf4179c8 renamed "Incremental Migrations" to "Progressive Migrations" to match the common term used by the community 2016-02-17 15:34:33 +09:00
John Estropia 240dda6ad6 Merge pull request #50 from ReadmeCritic/master
Correct the spelling of Xcode in README
2016-02-17 10:03:47 +09:00
ReadmeCritic ffe73d0f66 Correct the spelling of Xcode in README 2016-02-16 11:47:36 -08:00
John Rommel Estropia 43c4998e20 fix podspec 2016-02-17 02:32:39 +09:00
John Rommel Estropia 0c4e55f061 Merge branch 'develop' 2016-02-17 02:06:57 +09:00
John Rommel Estropia 8c8953c507 updated .travis.yml 2016-02-17 01:57:28 +09:00
John Rommel Estropia 66892f22a3 comments cleanup 2016-02-17 01:38:26 +09:00
John Rommel Estropia def105e73a added utility to query transactions about pending inserts, updates, and deletes 2016-02-17 00:00:25 +09:00
John Rommel Estropia 57bf123fb2 assert missing classes in model 2016-02-16 07:52:34 +09:00
John Rommel Estropia 8efd6572f0 Refetch monitors when persistent stores are added/removed. Allow unsafe transactions to create their own monitors 2016-02-15 07:56:17 +09:00
John Estropia 405e861907 Merge pull request #47 from ReadmeCritic/master
Correct the spelling of CocoaPods in README
2016-02-12 10:37:49 +09:00
ReadmeCritic 74c48c7486 Correct the spelling of CocoaPods in README 2016-02-11 09:45:40 -08:00
John Rommel Estropia e58b3b0131 fixed some typos in the README 2016-02-11 09:25:32 +09:00
John Rommel Estropia b8fad66bfa tidy up: copyright symbol 2016-02-01 01:07:07 +09:00
John Rommel Estropia ff1155dac3 fix OSX compiler error 2016-01-31 23:27:29 +09:00
John Rommel Estropia 5137649b78 Fix for Swift 2.2 compatibility 2016-01-31 17:23:34 +09:00
John Rommel Estropia 7a95267a9c updated Readme 2016-01-26 12:34:06 +09:00
John Rommel Estropia c07435e866 Added utility for re-faulting all objects in a transaction/dataStack 2016-01-26 12:22:30 +09:00
John Rommel Estropia f5627f0855 fixed demo app framework settings 2016-01-23 01:52:27 +09:00
John Estropia d3ea655eb9 Merge branch 'master' into develop
Conflicts:
	README.md
2016-01-19 12:26:37 +09:00
John Estropia fc83180af8 updated README 2016-01-19 12:25:58 +09:00
John Estropia 0c6246475a update README 2016-01-19 12:24:14 +09:00
John Estropia 087480a3a8 update cartfile 2016-01-19 12:22:14 +09:00
John Estropia 83a04e669e updated .travis.yml 2016-01-19 11:55:22 +09:00
John Estropia d05522bb20 tidy up, set default directory to Caches folder on tvOS 2016-01-19 11:38:11 +09:00
Cihat Gündüz 9081b36cca Add tvOS target + Configure target + Add shared scheme for tvOS 2016-01-17 13:30:45 +01:00
Cihat Gündüz 9322371224 Use tvOS_support feature branch of GCDKit (Carthage + git submodules) 2016-01-17 13:11:58 +01:00
John Estropia 26ab6aacd7 exposed utility for extracting the parent transaction for objects created from UnsafeDataTransactions 2016-01-14 17:54:58 +09:00
John Estropia 3e601c1328 tidy up (WIP: queue check for NSManagedObjectContext property updates) 2016-01-08 20:44:42 +09:00
John Estropia 762b877879 Merge pull request #35 from JohnEstropia/modify-gitignore
Update .gitignore: Add .DS_Store
2016-01-08 18:41:29 +09:00
Hiroshi Kimura 084bdc431f Update .gitignore: Add .DS_Store 2016-01-08 18:40:16 +09:00
John Estropia c63bc389b2 updated travis.yml 2016-01-06 19:29:58 +09:00
John Estropia 71c3abc4f3 Let ListMonitor expose methods for Section Indexes (fixes #32) 2016-01-06 19:16:46 +09:00
John Estropia 863d4d1d5a Merge branch 'master' into develop
# Conflicts:
#	README.md
2016-01-06 18:45:45 +09:00
John Estropia 06d177e8bd Update README.md 2016-01-04 19:38:42 +09:00
John Estropia c2bbd537cf Update README.md 2016-01-04 19:38:11 +09:00
John Estropia 761d349b97 Rename CartFile to Cartfile. Sorry about that 2016-01-04 12:38:05 +09:00
John Rommel Estropia 6c28594e41 fixed shouldUpdateFromImportSource() not called from importUniqueObject() (fixes #31) 2015-12-29 08:25:06 +08:00
John Estropia c229af19a2 added GCDKit to Carthage installation guide 2015-12-18 19:28:02 +09:00
John Estropia 8b8a7c7b08 fix macOSX development target 2015-12-16 14:01:56 +09:00
John Estropia eb828d8e42 update deployment version 2015-12-15 21:20:56 +09:00
John Estropia 88a24540c6 remove IPHONEOS_DEPLOYMENT_TARGET flag 2015-12-15 20:51:48 +09:00
John Estropia 74ded8fb7d update .travis.yml 2015-12-15 19:58:59 +09:00
John Estropia 969f4cefb4 use workspaces for better carthage support 2015-12-15 19:56:07 +09:00
John Estropia 1d2947ad26 added Carthage dependency 2015-12-08 18:34:10 +09:00
John Estropia 49274c3c94 fix swift project settings 2015-12-08 16:35:50 +09:00
John Rommel Estropia c0fbb2655b version bump 2015-12-06 20:32:06 +09:00
John Rommel Estropia cefd6f6cbc fix watchOS travis configuration 2015-12-05 20:28:24 +09:00
John Rommel Estropia 2653f7b977 fix watchOS travis configuration 2015-12-05 20:13:52 +09:00
John Rommel Estropia c1163283f5 fix watchOS travis configuration 2015-12-05 20:03:21 +09:00
John Rommel Estropia 529347b6a2 fix watchOS travis configuration 2015-12-05 19:48:40 +09:00
John Rommel Estropia eba7e99374 fixed yml 2015-12-05 19:35:23 +09:00
John Rommel Estropia 3c4350bd5d enable testability 2015-12-05 19:30:04 +09:00
John Rommel Estropia 88b13189e5 fix yml 2015-12-05 19:23:12 +09:00
John Rommel Estropia 03da3544f6 change GCDKit submodule path to public url to make sir Travis happy 2015-12-05 19:20:27 +09:00
John Rommel Estropia 648b59e1ee fix yml 2015-12-05 19:14:35 +09:00
John Rommel Estropia ab3c8ca812 tidy up 2015-12-05 19:01:07 +09:00
John Rommel Estropia 900a31c541 added build status to readme 2015-12-05 18:55:20 +09:00
John Rommel Estropia 656a107767 test travis ci 2015-12-05 18:50:54 +09:00
John Rommel Estropia 4ce3d5de3c undo interface 2015-12-05 18:21:21 +09:00
John Rommel Estropia dec9757dc2 Merge branch 'develop' of github.com:JohnEstropia/CoreStore into develop 2015-12-05 18:19:33 +09:00
John Estropia 578e4966fc added a convenience initializer for clients that only support NSFetchedResultsController (i.e. Objective-C) 2015-11-24 19:12:04 +09:00
John Estropia b741626574 updated GCDKit 2015-11-24 17:50:23 +09:00
John Estropia f79a77ab78 remove unneeded imports in demo app 2015-11-24 17:02:23 +09:00
John Estropia 1f2a70fd42 minor fixes 2015-11-24 16:06:48 +09:00
John Estropia 718d2c9b7d Added ability to initialize ListMonitors asynchronously. This is a deadlock-preventive measure for apps that heavily recreates ListMonitors while updates and saves are running in the background (because NSFetchedResultController's performFetch() locks the whole NSManagedObjectContext chain up until the NSPersistentStoreCoordinator) 2015-11-24 14:49:43 +09:00
John Estropia c5ff02335e debug flag 2015-11-24 12:32:10 +09:00
John Estropia 66b57faa44 Merge branch 'master' into develop 2015-11-24 11:34:35 +09:00
John Estropia eef5a3d80b allow CoreStore installation both through frameworks or through direct linking 2015-11-24 11:33:52 +09:00
John Estropia bc0757cf06 README: Added link to poll for new features 2015-11-18 19:46:17 +09:00
John Rommel Estropia 0c0a2a382c Deprecated rollback() on async and sync transactions. Added undo utilities to unsafe transactions. 2015-11-14 20:00:40 +09:00
John Rommel Estropia 05b4a7092a updated podspec for OSX 2015-10-30 01:46:47 +09:00
John Rommel Estropia 6aed070e7c version bump for OSX support 2015-10-30 01:36:15 +09:00
John Estropia fcb1d7cbbc OSX support!!!11 2015-10-29 17:00:10 +09:00
John Estropia d074aad111 Merge branch 'master' into develop 2015-10-26 14:42:31 +09:00
John Estropia b7685dc747 allow Sequences of NSManagedObject subclasses as argument to delete() method 2015-10-26 14:41:58 +09:00
John Rommel Estropia a185bc96c0 updated README 2015-10-24 11:41:13 +09:00
John Rommel Estropia 91aef44803 fix pod dependency 2015-10-23 00:49:34 +09:00
John Rommel Estropia dcfb09eda7 attempt sight improvement for the FRC bug workaround #20 2015-10-23 00:40:38 +09:00
John Estropia 9ca83d9c5d watchOS support (fixes #19) 2015-10-20 21:01:10 +09:00
John Estropia b00eaf2d0b fix warnings on watchOS 2015-10-20 20:54:09 +09:00
John Estropia dc8bdf3bad watch OS support 2015-10-20 20:38:58 +09:00
John Estropia 4792c4462e fix section index titles when refetching a listMonitor 2015-10-15 18:29:08 +09:00
John Estropia 524757a7cf just a safety measure for the rare case that the FRC delegate gets released earlier than the FRC 2015-10-13 10:47:48 +09:00
John Rommel Estropia 0b6298a802 tidy up 2015-10-07 00:57:48 +09:00
John Estropia ae77558ae8 Merge pull request #16 from mac-cain13/patch-1
Fix FRCdelegate issue where invalid type is passed
2015-10-07 00:44:15 +09:00
Mathijs Kadijk d33aa9c5cf Fix FRCdelegate issue where invalid type is passed
See also https://forums.developer.apple.com/thread/12184#31850
2015-10-06 15:30:22 +02:00
John Estropia d89319d324 Workaround for Xcode 7.0.1+iOS 9 FRC bug 2015-09-30 11:41:27 +09:00
John Estropia cf9af6eef5 Merge branch 'develop' 2015-09-28 20:46:14 +09:00
John Estropia b9ec66f425 fix entityNameMapping bug 2015-09-28 20:44:19 +09:00
John Estropia 2a8df0596d Update README.md 2015-09-24 23:47:06 +09:00
John Rommel Estropia 83e6a41d88 Merge branch 'master' into develop 2015-09-22 11:40:28 +09:00
John Rommel Estropia c6fe494fe1 updated podspec dependency 2015-09-21 23:30:41 +09:00
John Rommel Estropia 7771e047e2 updated GCDKit version to remove warnings 2015-09-21 23:23:22 +09:00
John Rommel Estropia 5b0439835b Deprecated DetachedDataTransaction in favor of UnsafeDataTransaction. beginDetached() methods are also deprecated; use beginUnsafe() instead. 2015-09-21 15:08:46 +09:00
John Rommel Estropia 622c5aa652 Tighter generics implementations. You can now pass any SequenceType's for methods that previously only accepts Array's. 2015-09-19 19:45:01 +09:00
John Rommel Estropia 114b7ce605 Tighter generics implementations. You can now pass any SequenceType's for methods that previously only accepts Array's. 2015-09-19 18:20:52 +09:00
John Rommel Estropia 7451fbe026 added README sections about ImportableObject and ImportableUniqueObject, as well as the new fetchExisting() method usage 2015-09-19 16:23:59 +09:00
John Rommel Estropia ee2398fcdf updated readme 2015-09-18 07:14:41 +09:00
John Rommel Estropia 8d26501040 WIP: Readme 2015-09-14 07:44:23 +09:00
John Estropia 0709fe95cf use transaction queue for refetching instead of a global queue 2015-09-11 15:06:36 +09:00
John Estropia 656a99fe12 added thread safety checks to ListMonitor to prevent deadlocks after calling refetch() 2015-09-11 13:59:28 +09:00
John Estropia 726e0eabe9 dispatch_group seems more semantically fitting than semaphore 2015-09-11 13:50:29 +09:00
John Estropia 032764b9b7 tidy up 2015-09-10 16:59:55 +09:00
John Estropia 5461bb0736 workaround an NSFetchedResultsController bug in Xcode 7 targeted on iOS 8 devices where errant index paths cause crashes 2015-09-10 16:57:35 +09:00
John Estropia 4c6bc4f494 completed appledocs for importing methods 2015-09-10 13:28:53 +09:00
John Rommel Estropia 63a43a6487 WIP: documentation 2015-09-10 07:21:53 +09:00
John Estropia 6a006d5d7c added a flag to inspect the current state of a refetch 2015-09-08 18:12:52 +09:00
John Estropia 399517e357 ListMonitor is now refetch-able. Implement the listMonitorWillRefetch and listMonitorDidRefetch methods of ListObserver and call the refetch(...) method of ListMonitor 2015-09-08 17:21:15 +09:00
John Estropia f47adc12b3 fix typealias name clash when observing both ListMonitor and ObjectMonitor 2015-09-02 13:44:37 +09:00
John Estropia 0de1733efe oops 2015-09-01 21:05:59 +09:00
John Estropia e627cf8161 test improvements to ListMonitor 2015-09-01 20:08:45 +09:00
John Rommel Estropia 22943d2c76 added warn_unused_result annotations where they seem reasonable 2015-08-29 22:29:03 +09:00
John Estropia 56ea14d53c fix disconnected observers when an observer registers itself to multiple ListMonitors 2015-08-28 12:09:55 +09:00
John Rommel Estropia 21a524d725 tidy up 2015-08-28 08:09:06 +09:00
John Estropia d5e769be6c turns out inout arguments in closures are malloc nightmares. this finally fixes it 2015-08-27 22:24:40 +09:00
John Estropia ea6b6f2c37 bandaid solution for over-deallocated sequences bug in swift (for now) 2015-08-27 19:06:52 +09:00
John Estropia c3ef8a4172 bug fix for dictionaries getting deallocated earlier 2015-08-27 17:28:40 +09:00
John Rommel Estropia 16aabe1f3b optimize fetching objects with NSManagedObjectIDs 2015-08-26 23:59:18 +09:00
John Estropia 10e0cf8d2c tidy up 2015-08-25 20:33:36 +09:00
John Estropia 3a0f53321a improved behavior for #12 (as of Xcode 7 beta 6) 2015-08-25 14:35:22 +09:00
John Estropia 0da43d5132 Merge branch 'develop' of https://github.com/JohnEstropia/CoreStore into develop 2015-08-25 14:27:32 +09:00
John Estropia 69f902ef20 XCode7 beta 6 updates 2015-08-25 14:24:18 +09:00
John Estropia d04b4ca085 added utility for ListMonitor to return the index/indexPath of a specified object 2015-08-24 20:40:19 +09:00
John Estropia 8ed6a78609 CoreStore adapter method 2015-08-24 17:36:40 +09:00
John Estropia 0c9e6afe0e added utility to inspect NSEntityDescription for a given NSManagedObject type 2015-08-24 17:33:27 +09:00
John Rommel Estropia ff4629908a Merge branch 'develop' of github.com:JohnEstropia/CoreStore into develop 2015-08-23 14:37:34 +09:00
John Rommel Estropia d3ffe7a8fc add default implementation for souldUpdateFromImportSource 2015-08-23 14:37:21 +09:00
John Rommel Estropia 3919ada428 Merge branch 'master' into develop 2015-08-23 14:29:44 +09:00
John Rommel Estropia 682b13a8d3 version bump 2015-08-23 14:25:18 +09:00
John Rommel Estropia 2f935de04a temporarily fix an Xcode 7 bug (still present as of beta 5) (temporarily fixes #12) 2015-08-23 14:21:12 +09:00
John Rommel Estropia 006d5e1402 rewrote ImportableObject protocol methods 2015-08-23 14:15:48 +09:00
John Rommel Estropia 093c1d410f temporarily fix an Xcode 7 bug (still present as of beta 5) (temporarily fixes #12) 2015-08-23 14:02:27 +09:00
John Estropia 7555ff3ad0 allow preprocessing dictionary mapping before importing objects 2015-08-21 19:48:47 +09:00
John Estropia 4c16a961ba added default implementation to didInsertFromImportSource 2015-08-21 18:28:02 +09:00
John Estropia 1121d44d7b pass transaction to ImportableObject methods 2015-08-21 18:19:21 +09:00
John Rommel Estropia ba4fb5e5cb version bump 2015-08-21 08:03:14 +09:00
John Rommel Estropia d860da2507 Merge branch 'develop' 2015-08-21 08:03:01 +09:00
John Estropia 2bcf8008c5 let transaction fetch existing objects from external contexts 2015-08-20 17:20:38 +09:00
John Estropia 71477c0839 allow equality comparison on ListMonitor and ObjectMonitor to help distinguish senders when observing multiple monitors 2015-08-20 14:25:14 +09:00
John Estropia 3348aa0bef added utility to check if objects exist in a ListMonitor 2015-08-20 13:51:14 +09:00
John Estropia 2ed61fdb17 added utilities to ListMonitor to extract all objects in specified sections 2015-08-20 12:15:20 +09:00
John Estropia 9cfad8a17a oops, GroupBy should not be needed for monitorList() 2015-08-19 21:00:27 +09:00
John Estropia 3bf34f33dc added utilities for ListMonitor to optionally extract objects with potentially invalid indexes/indexPaths 2015-08-19 20:56:50 +09:00
John Estropia 90bfaeaae8 removed unused key tuple 2015-08-19 18:30:39 +09:00
John Estropia a29a4b38fe added utilities to get existing NSManagedObject instances using object IDs 2015-08-19 15:53:20 +09:00
John Estropia 5a96ef13f6 added utility to get NSManagedObjectID from an object URI 2015-08-19 15:07:15 +09:00
John Estropia b92ee76907 added utility to refresh an object 2015-08-19 12:19:14 +09:00
John Estropia 67ccae4ef6 added missing parameters 2015-08-19 11:21:39 +09:00
John Estropia 62b11309f3 expose DataStack vars to CoreStore 2015-08-18 21:49:40 +09:00
John Estropia 8c6a7df731 provide a way to enumerate entities managed by the DataStack 2015-08-18 21:40:33 +09:00
John Rommel Estropia b475afe79f updated Readme 2015-08-17 23:51:08 +09:00
John Rommel Estropia a263851266 import array of ImportableObjects 2015-08-17 23:50:03 +09:00
John Estropia cbc3eb8887 woops, develop branch should be Swift 2.0, not 1.2 2015-08-11 15:37:44 +08:00
John Rommel Estropia 2fb3263aa1 refactored autoreleasepool calls 2015-08-09 18:27:21 +09:00
John Rommel Estropia 64aa97264e added utilities for importing data 2015-08-09 05:06:42 +09:00
John Rommel Estropia 8066bf2a5a fixed assertion failures when fetching from detached data transactions 2015-08-09 05:05:26 +09:00
John Rommel Estropia 283104af3f thanks to protocol extensions, you can now omit ListObserver and ObjectObserver methods you don't need to implement 2015-08-09 05:04:47 +09:00
John Rommel Estropia 83c724f584 updated default logger to still run assertions even on optimized (-O) builds 2015-08-08 22:12:08 +09:00
John Rommel Estropia 59ad525786 fixed for Xcode 7 beta 5 2015-08-08 10:24:40 +09:00
John Rommel Estropia b85d7521e1 version bump 2015-07-29 22:24:11 +09:00
John Rommel Estropia 4dbc4558e3 display explanation dialog for migration demo 2015-07-29 22:21:22 +09:00
John Rommel Estropia 2a56c097f2 Merge branch 'master' into develop 2015-07-29 21:32:17 +09:00
John Estropia d4b95aed64 Merge pull request #10 from bddckr/patch-1
Fix building with Carthage
2015-07-28 12:44:43 +09:00
Christopher - Marcel Böddecker 0d2650c54b Fix building with Carthage 2015-07-27 19:26:19 +02:00
John Rommel Estropia 6a3885edda aesthetic 2015-07-26 21:21:19 +09:00
John Rommel Estropia 1c6085ad82 expose DetachedDataTransaction's context and allow creating children detached transactions (https://github.com/JohnEstropia/CoreStore/issues/9) 2015-07-26 21:20:48 +09:00
John Rommel Estropia 2dae2ae39c update GCDKit submodule version 2015-07-26 17:11:53 +09:00
John Rommel Estropia a1e37975cc updated project settings for Xcode 7 beta 4 2015-07-26 17:08:56 +09:00
John Rommel Estropia 0c8a43c3b0 added shorthand vars for inspecting MigrationType values. updated readme 2015-07-26 17:04:19 +09:00
John Rommel Estropia 9676e3aca2 addSQLiteStoreAndWait() does not support auto-migrating stores anymore; use the asynchronous addSQLiteStore(..., completion:) method instead. 2015-07-26 10:07:42 +09:00
John Rommel Estropia a34d2795af remove queue asserts for detached transactions 2015-07-26 09:27:00 +09:00
John Rommel Estropia 106789d592 refactor some internal methods. renamed addInMemoryStore to addInMemoryStoreAndWait to reflect synchronicity. 2015-07-25 23:05:48 +09:00
John Rommel Estropia edc51de030 catch intentional error in logger demo 2015-07-24 08:06:59 +09:00
John Rommel Estropia f85eb2e057 merge changes to the main context asynchronously (fixes https://github.com/JohnEstropia/CoreStore/issues/7) 2015-07-24 08:05:13 +09:00
John Rommel Estropia f0161b50ed submodule update 2015-07-19 00:07:47 +09:00
John Rommel Estropia 6c780c1282 use GCDKit's swift2.0 supported commit 2015-07-19 00:05:58 +09:00
John Rommel Estropia b711ec9644 gcdkit version 2015-07-18 23:57:59 +09:00
John Rommel Estropia a581f91507 Merge branch 'develop'
Conflicts:
	README.md
2015-07-18 23:53:37 +09:00
John Estropia ebd4df5c2f Update README.md 2015-07-14 13:23:41 +09:00
John Estropia 2780fd7682 Update README.md 2015-07-14 13:23:26 +09:00
John Rommel Estropia 982e75a36e updated README 2015-07-14 07:56:50 +09:00
John Rommel Estropia 79d5598abe updated README 2015-07-14 07:54:23 +09:00
John Rommel Estropia b88679c507 updated README 2015-07-14 07:50:12 +09:00
John Rommel Estropia 858dd0962d updated documentation (in progress) 2015-07-14 07:44:45 +09:00
John Estropia e7bcb501fd fixed migrationchain validation 2015-07-13 16:16:19 +09:00
John Rommel Estropia f99349f99d improved migrationchain validation 2015-07-13 07:47:43 +09:00
John Rommel Estropia a64bcc474e updated error handling for DataStack methods, updated migration demo app 2015-07-12 19:20:38 +09:00
John Rommel Estropia 8cfe8e2500 added NSProgress support for migrations 2015-07-12 00:49:53 +09:00
John Rommel Estropia 33268eeea1 fix demo app: label layout problem on iOS 9 2015-07-10 07:17:22 +09:00
John Estropia b2a190ea33 require explicit parameter for fileName when calling addSQLiteStore() and it's variants 2015-07-09 21:28:37 +09:00
John Estropia 35fbaf9513 updated for Xcode 7 beta 3 2015-07-09 21:25:19 +09:00
John Estropia 450afb00fa Merge branch 'master' into develop
Conflicts:
	CoreStore.podspec
	CoreStore/Info.plist
	CoreStore/Saving and Processing/DataStack+Transaction.swift
2015-07-09 19:01:23 +09:00
John Estropia 7e0d3120e1 fix jump link for readme 2015-07-09 18:34:42 +09:00
John Rommel Estropia acfe5dd7a7 use GCDKit commit with iOS 7 support 2015-07-09 08:10:36 +09:00
John Rommel Estropia 9da323b0b8 assert migration chain when creating a data stack 2015-07-09 08:08:11 +09:00
John Estropia 4f3e679aa1 Merge branch 'master' into develop
Conflicts:
	CoreStoreDemo/CoreStoreDemo.xcodeproj/xcshareddata/xcschemes/CoreStoreDemo.xcscheme
2015-07-08 12:30:41 +09:00
John Estropia 5f04f4c496 reversible migrations 2015-07-07 19:38:46 +09:00
John Rommel Estropia 5b85b0749e migration utilities (beta), swift 2 conversion 2015-07-07 08:03:46 +09:00
John Rommel Estropia bf0eebe057 migration utilities (beta) 2015-07-07 07:58:16 +09:00
John Rommel Estropia 261c3a6001 minor changes before Swift 2.0 2015-07-03 00:22:21 +09:00
John Rommel Estropia 91444b6dd3 Merge branch 'master' into develop 2015-07-02 22:47:36 +09:00
John Rommel Estropia e0b5da27f8 Merge branch 'master' into develop
Conflicts:
	CoreStoreDemo/CoreStoreDemo.xcodeproj/xcuserdata/johnestropia.xcuserdatad/xcdebugger/Breakpoints_v2.xcbkptlist
2015-07-02 00:19:26 +09:00
John Rommel Estropia 40f22761bf Big update. Migration tools in progress 2015-07-01 08:03:09 +09:00
282 changed files with 48550 additions and 8246 deletions
+5
View File
@@ -2,3 +2,8 @@ CoreStoreDemo/CoreStoreDemo.xcodeproj/project.xcworkspace/xcuserdata
CoreStore.xcodeproj/project.xcworkspace/xcuserdata
CoreStore.xcodeproj/xcuserdata
CoreStoreDemo/CoreStoreDemo.xcodeproj/xcuserdata
Carthage/Build
CoreStore.xcworkspace/xcuserdata
.DS_Store
DerivedData
*.orig
-3
View File
@@ -1,3 +0,0 @@
[submodule "Libraries/GCDKit"]
path = Libraries/GCDKit
url = git@github.com:JohnEstropia/GCDKit.git
+1
View File
@@ -0,0 +1 @@
3.1
+45
View File
@@ -0,0 +1,45 @@
language: objective-c
osx_image: xcode8.3
sudo: false
git:
submodules: false
notifications:
email: false
env:
global:
- LC_CTYPE=en_US.UTF-8
- LANG=en_US.UTF-8
matrix:
- DESTINATION="OS=10.3,name=iPhone 7" SCHEME="CoreStore iOS" SDK=iphonesimulator10.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=9.0,name=iPhone 6 Plus" SCHEME="CoreStore iOS" SDK=iphonesimulator10.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.3,name=iPhone 5S" SCHEME="CoreStore iOS" SDK=iphonesimulator10.3 RUN_TESTS="YES" POD_LINT="NO"
- DESTINATION="OS=8.3,name=iPhone 5" SCHEME="CoreStore iOS" SDK=iphonesimulator10.3 RUN_TESTS="YES" POD_LINT="NO"
- 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.12 RUN_TESTS="YES" 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=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:
- gem install cocoapods --no-rdoc --no-ri --no-document --quiet
- gem install xcpretty --no-rdoc --no-ri --no-document --quiet
- curl -OlL "https://github.com/Carthage/Carthage/releases/download/0.20.1/Carthage.pkg"
- sudo installer -pkg "Carthage.pkg" -target /
- rm "Carthage.pkg"
before_script:
- carthage update --use-submodules
script:
- set -o pipefail
- xcodebuild -version
- xcodebuild -showsdks
- if [ $RUN_TESTS == "YES" ]; then
xcodebuild -workspace CoreStore.xcworkspace -scheme "$SCHEME" -sdk "$SDK" -destination "$DESTINATION" -configuration Debug ONLY_ACTIVE_ARCH=NO clean test | xcpretty -c;
xcodebuild -workspace CoreStore.xcworkspace -scheme "$SCHEME" -sdk "$SDK" -destination "$DESTINATION" -configuration Release ONLY_ACTIVE_ARCH=NO clean test | xcpretty -c;
fi
- xcodebuild -workspace "CoreStore.xcworkspace" -scheme "CoreStore iOS" -sdk "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 "iphonesimulator10.3" -destination "OS=10.3,name=iPhone 7" -configuration Release ONLY_ACTIVE_ARCH=NO clean test | xcpretty -c;
- if [ $POD_LINT == "YES" ]; then
pod lib lint --quick;
fi
View File
View File
BIN
View File
Binary file not shown.

After

Width:  |  Height:  |  Size: 53 KiB

+9 -5
View File
@@ -1,16 +1,20 @@
Pod::Spec.new do |s|
s.name = "CoreStore"
s.version = "0.2.1"
s.version = "4.0.0-beta2"
s.license = "MIT"
s.summary = "Simple, elegant, and smart Core Data programming with Swift"
s.summary = "Unleashing the real power of Core Data with the elegance and safety of Swift"
s.homepage = "https://github.com/JohnEstropia/CoreStore"
s.author = { "John Rommel Estropia" => "rommel.estropia@gmail.com" }
s.source = { :git => "https://github.com/JohnEstropia/CoreStore.git", :tag => s.version.to_s }
s.ios.deployment_target = "8.0"
s.osx.deployment_target = "10.10"
s.watchos.deployment_target = "2.0"
s.tvos.deployment_target = "9.0"
s.source_files = "CoreStore", "CoreStore/**/*.{swift}"
s.frameworks = "Foundation", "UIKit", "CoreData"
s.source_files = "Sources", "Sources/**/*.{swift,h,m}"
s.public_header_files = "Sources/**/*.h"
s.frameworks = "Foundation", "CoreData"
s.requires_arc = true
s.dependency "GCDKit", "1.0.1"
s.pod_target_xcconfig = { 'OTHER_SWIFT_FLAGS[config=Debug]' => '-D DEBUG' }
end
BIN
View File
Binary file not shown.
File diff suppressed because it is too large Load Diff
@@ -0,0 +1,30 @@
{
"DVTSourceControlWorkspaceBlueprintPrimaryRemoteRepositoryKey" : "4B60F1BCB491FF717C56441AE7783C74F417BE48",
"DVTSourceControlWorkspaceBlueprintWorkingCopyRepositoryLocationsKey" : {
},
"DVTSourceControlWorkspaceBlueprintWorkingCopyStatesKey" : {
"8B2E522D57154DFA93A06982C36315ECBEA4FA97" : 0,
"4B60F1BCB491FF717C56441AE7783C74F417BE48" : 0
},
"DVTSourceControlWorkspaceBlueprintIdentifierKey" : "F347F55F-7F5C-4476-9148-6E902F06E4AD",
"DVTSourceControlWorkspaceBlueprintWorkingCopyPathsKey" : {
"8B2E522D57154DFA93A06982C36315ECBEA4FA97" : "CoreStoreLibraries\/GCDKit",
"4B60F1BCB491FF717C56441AE7783C74F417BE48" : "CoreStore\/"
},
"DVTSourceControlWorkspaceBlueprintNameKey" : "CoreStore",
"DVTSourceControlWorkspaceBlueprintVersion" : 204,
"DVTSourceControlWorkspaceBlueprintRelativePathToProjectKey" : "CoreStore.xcodeproj",
"DVTSourceControlWorkspaceBlueprintRemoteRepositoriesKey" : [
{
"DVTSourceControlWorkspaceBlueprintRemoteRepositoryURLKey" : "github.com:JohnEstropia\/CoreStore.git",
"DVTSourceControlWorkspaceBlueprintRemoteRepositorySystemKey" : "com.apple.dt.Xcode.sourcecontrol.Git",
"DVTSourceControlWorkspaceBlueprintRemoteRepositoryIdentifierKey" : "4B60F1BCB491FF717C56441AE7783C74F417BE48"
},
{
"DVTSourceControlWorkspaceBlueprintRemoteRepositoryURLKey" : "github.com:JohnEstropia\/GCDKit.git",
"DVTSourceControlWorkspaceBlueprintRemoteRepositorySystemKey" : "com.apple.dt.Xcode.sourcecontrol.Git",
"DVTSourceControlWorkspaceBlueprintRemoteRepositoryIdentifierKey" : "8B2E522D57154DFA93A06982C36315ECBEA4FA97"
}
]
}
@@ -0,0 +1,99 @@
<?xml version="1.0" encoding="UTF-8"?>
<Scheme
LastUpgradeVersion = "0800"
version = "1.3">
<BuildAction
parallelizeBuildables = "YES"
buildImplicitDependencies = "YES">
<BuildActionEntries>
<BuildActionEntry
buildForTesting = "YES"
buildForRunning = "YES"
buildForProfiling = "YES"
buildForArchiving = "YES"
buildForAnalyzing = "YES">
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "B52DD1731BE1F8CC00949AFE"
BuildableName = "CoreStore.framework"
BlueprintName = "CoreStore OSX"
ReferencedContainer = "container:CoreStore.xcodeproj">
</BuildableReference>
</BuildActionEntry>
</BuildActionEntries>
</BuildAction>
<TestAction
buildConfiguration = "Debug"
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
shouldUseLaunchSchemeArgsEnv = "YES">
<Testables>
<TestableReference
skipped = "NO">
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "B52DD17C1BE1F8CC00949AFE"
BuildableName = "CoreStoreTests.xctest"
BlueprintName = "CoreStoreTests OSX"
ReferencedContainer = "container:CoreStore.xcodeproj">
</BuildableReference>
</TestableReference>
</Testables>
<MacroExpansion>
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "B52DD1731BE1F8CC00949AFE"
BuildableName = "CoreStore.framework"
BlueprintName = "CoreStore OSX"
ReferencedContainer = "container:CoreStore.xcodeproj">
</BuildableReference>
</MacroExpansion>
<AdditionalOptions>
</AdditionalOptions>
</TestAction>
<LaunchAction
buildConfiguration = "Debug"
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
launchStyle = "0"
useCustomWorkingDirectory = "NO"
ignoresPersistentStateOnLaunch = "NO"
debugDocumentVersioning = "YES"
debugServiceExtension = "internal"
allowLocationSimulation = "YES">
<MacroExpansion>
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "B52DD1731BE1F8CC00949AFE"
BuildableName = "CoreStore.framework"
BlueprintName = "CoreStore OSX"
ReferencedContainer = "container:CoreStore.xcodeproj">
</BuildableReference>
</MacroExpansion>
<AdditionalOptions>
</AdditionalOptions>
</LaunchAction>
<ProfileAction
buildConfiguration = "Release"
shouldUseLaunchSchemeArgsEnv = "YES"
savedToolIdentifier = ""
useCustomWorkingDirectory = "NO"
debugDocumentVersioning = "YES">
<MacroExpansion>
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "B52DD1731BE1F8CC00949AFE"
BuildableName = "CoreStore.framework"
BlueprintName = "CoreStore OSX"
ReferencedContainer = "container:CoreStore.xcodeproj">
</BuildableReference>
</MacroExpansion>
</ProfileAction>
<AnalyzeAction
buildConfiguration = "Debug">
</AnalyzeAction>
<ArchiveAction
buildConfiguration = "Release"
revealArchiveInOrganizer = "YES">
</ArchiveAction>
</Scheme>
@@ -1,6 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<Scheme
LastUpgradeVersion = "0630"
LastUpgradeVersion = "0800"
version = "1.3">
<BuildAction
parallelizeBuildables = "YES"
@@ -16,31 +16,31 @@
BuildableIdentifier = "primary"
BlueprintIdentifier = "2F03A52F19C5C6DA005002A5"
BuildableName = "CoreStore.framework"
BlueprintName = "CoreStore"
BlueprintName = "CoreStore iOS"
ReferencedContainer = "container:CoreStore.xcodeproj">
</BuildableReference>
</BuildActionEntry>
<BuildActionEntry
buildForTesting = "YES"
buildForRunning = "YES"
buildForRunning = "NO"
buildForProfiling = "NO"
buildForArchiving = "NO"
buildForAnalyzing = "YES">
buildForAnalyzing = "NO">
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "2F03A53A19C5C6DA005002A5"
BuildableName = "CoreStoreTests.xctest"
BlueprintName = "CoreStoreTests"
BlueprintName = "CoreStoreTests iOS"
ReferencedContainer = "container:CoreStore.xcodeproj">
</BuildableReference>
</BuildActionEntry>
</BuildActionEntries>
</BuildAction>
<TestAction
buildConfiguration = "Debug"
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
shouldUseLaunchSchemeArgsEnv = "YES"
buildConfiguration = "Debug">
shouldUseLaunchSchemeArgsEnv = "YES">
<Testables>
<TestableReference
skipped = "NO">
@@ -48,7 +48,7 @@
BuildableIdentifier = "primary"
BlueprintIdentifier = "2F03A53A19C5C6DA005002A5"
BuildableName = "CoreStoreTests.xctest"
BlueprintName = "CoreStoreTests"
BlueprintName = "CoreStoreTests iOS"
ReferencedContainer = "container:CoreStore.xcodeproj">
</BuildableReference>
</TestableReference>
@@ -58,26 +58,34 @@
BuildableIdentifier = "primary"
BlueprintIdentifier = "2F03A52F19C5C6DA005002A5"
BuildableName = "CoreStore.framework"
BlueprintName = "CoreStore"
BlueprintName = "CoreStore iOS"
ReferencedContainer = "container:CoreStore.xcodeproj">
</BuildableReference>
</MacroExpansion>
<AdditionalOptions>
<AdditionalOption
key = "NSZombieEnabled"
value = "YES"
isEnabled = "YES">
</AdditionalOption>
</AdditionalOptions>
</TestAction>
<LaunchAction
buildConfiguration = "Debug"
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
launchStyle = "0"
useCustomWorkingDirectory = "NO"
buildConfiguration = "Debug"
ignoresPersistentStateOnLaunch = "NO"
debugDocumentVersioning = "YES"
debugServiceExtension = "internal"
allowLocationSimulation = "YES">
<MacroExpansion>
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "2F03A52F19C5C6DA005002A5"
BuildableName = "CoreStore.framework"
BlueprintName = "CoreStore"
BlueprintName = "CoreStore iOS"
ReferencedContainer = "container:CoreStore.xcodeproj">
</BuildableReference>
</MacroExpansion>
@@ -85,17 +93,17 @@
</AdditionalOptions>
</LaunchAction>
<ProfileAction
buildConfiguration = "Release"
shouldUseLaunchSchemeArgsEnv = "YES"
savedToolIdentifier = ""
useCustomWorkingDirectory = "NO"
buildConfiguration = "Release"
debugDocumentVersioning = "YES">
<MacroExpansion>
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "2F03A52F19C5C6DA005002A5"
BuildableName = "CoreStore.framework"
BlueprintName = "CoreStore"
BlueprintName = "CoreStore iOS"
ReferencedContainer = "container:CoreStore.xcodeproj">
</BuildableReference>
</MacroExpansion>
@@ -0,0 +1,99 @@
<?xml version="1.0" encoding="UTF-8"?>
<Scheme
LastUpgradeVersion = "0800"
version = "1.3">
<BuildAction
parallelizeBuildables = "YES"
buildImplicitDependencies = "YES">
<BuildActionEntries>
<BuildActionEntry
buildForTesting = "YES"
buildForRunning = "YES"
buildForProfiling = "YES"
buildForArchiving = "YES"
buildForAnalyzing = "YES">
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "82BA18881C4BBCBA00A0916E"
BuildableName = "CoreStore.framework"
BlueprintName = "CoreStore tvOS"
ReferencedContainer = "container:CoreStore.xcodeproj">
</BuildableReference>
</BuildActionEntry>
</BuildActionEntries>
</BuildAction>
<TestAction
buildConfiguration = "Debug"
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
shouldUseLaunchSchemeArgsEnv = "YES">
<Testables>
<TestableReference
skipped = "NO">
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "82BA18911C4BBCBA00A0916E"
BuildableName = "CoreStoreTests.xctest"
BlueprintName = "CoreStoreTests tvOS"
ReferencedContainer = "container:CoreStore.xcodeproj">
</BuildableReference>
</TestableReference>
</Testables>
<MacroExpansion>
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "82BA18881C4BBCBA00A0916E"
BuildableName = "CoreStore.framework"
BlueprintName = "CoreStore tvOS"
ReferencedContainer = "container:CoreStore.xcodeproj">
</BuildableReference>
</MacroExpansion>
<AdditionalOptions>
</AdditionalOptions>
</TestAction>
<LaunchAction
buildConfiguration = "Debug"
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
launchStyle = "0"
useCustomWorkingDirectory = "NO"
ignoresPersistentStateOnLaunch = "NO"
debugDocumentVersioning = "YES"
debugServiceExtension = "internal"
allowLocationSimulation = "YES">
<MacroExpansion>
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "82BA18881C4BBCBA00A0916E"
BuildableName = "CoreStore.framework"
BlueprintName = "CoreStore tvOS"
ReferencedContainer = "container:CoreStore.xcodeproj">
</BuildableReference>
</MacroExpansion>
<AdditionalOptions>
</AdditionalOptions>
</LaunchAction>
<ProfileAction
buildConfiguration = "Release"
shouldUseLaunchSchemeArgsEnv = "YES"
savedToolIdentifier = ""
useCustomWorkingDirectory = "NO"
debugDocumentVersioning = "YES">
<MacroExpansion>
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "82BA18881C4BBCBA00A0916E"
BuildableName = "CoreStore.framework"
BlueprintName = "CoreStore tvOS"
ReferencedContainer = "container:CoreStore.xcodeproj">
</BuildableReference>
</MacroExpansion>
</ProfileAction>
<AnalyzeAction
buildConfiguration = "Debug">
</AnalyzeAction>
<ArchiveAction
buildConfiguration = "Release"
revealArchiveInOrganizer = "YES">
</ArchiveAction>
</Scheme>
@@ -0,0 +1,80 @@
<?xml version="1.0" encoding="UTF-8"?>
<Scheme
LastUpgradeVersion = "0800"
version = "1.3">
<BuildAction
parallelizeBuildables = "YES"
buildImplicitDependencies = "YES">
<BuildActionEntries>
<BuildActionEntry
buildForTesting = "YES"
buildForRunning = "YES"
buildForProfiling = "YES"
buildForArchiving = "YES"
buildForAnalyzing = "YES">
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "B563216E1BD65082006C9394"
BuildableName = "CoreStore.framework"
BlueprintName = "CoreStore watchOS"
ReferencedContainer = "container:CoreStore.xcodeproj">
</BuildableReference>
</BuildActionEntry>
</BuildActionEntries>
</BuildAction>
<TestAction
buildConfiguration = "Debug"
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
shouldUseLaunchSchemeArgsEnv = "YES">
<Testables>
</Testables>
<AdditionalOptions>
</AdditionalOptions>
</TestAction>
<LaunchAction
buildConfiguration = "Debug"
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
launchStyle = "0"
useCustomWorkingDirectory = "NO"
ignoresPersistentStateOnLaunch = "NO"
debugDocumentVersioning = "YES"
debugServiceExtension = "internal"
allowLocationSimulation = "YES">
<MacroExpansion>
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "B563216E1BD65082006C9394"
BuildableName = "CoreStore.framework"
BlueprintName = "CoreStore watchOS"
ReferencedContainer = "container:CoreStore.xcodeproj">
</BuildableReference>
</MacroExpansion>
<AdditionalOptions>
</AdditionalOptions>
</LaunchAction>
<ProfileAction
buildConfiguration = "Release"
shouldUseLaunchSchemeArgsEnv = "YES"
savedToolIdentifier = ""
useCustomWorkingDirectory = "NO"
debugDocumentVersioning = "YES">
<MacroExpansion>
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "B563216E1BD65082006C9394"
BuildableName = "CoreStore.framework"
BlueprintName = "CoreStore watchOS"
ReferencedContainer = "container:CoreStore.xcodeproj">
</BuildableReference>
</MacroExpansion>
</ProfileAction>
<AnalyzeAction
buildConfiguration = "Debug">
</AnalyzeAction>
<ArchiveAction
buildConfiguration = "Release"
revealArchiveInOrganizer = "YES">
</ArchiveAction>
</Scheme>
+10
View File
@@ -0,0 +1,10 @@
<?xml version="1.0" encoding="UTF-8"?>
<Workspace
version = "1.0">
<FileRef
location = "group:CoreStore.xcodeproj">
</FileRef>
<FileRef
location = "group:CoreStoreDemo/CoreStoreDemo.xcodeproj">
</FileRef>
</Workspace>
@@ -0,0 +1,37 @@
{
"DVTSourceControlWorkspaceBlueprintPrimaryRemoteRepositoryKey" : "4B60F1BCB491FF717C56441AE7783C74F417BE48",
"DVTSourceControlWorkspaceBlueprintWorkingCopyRepositoryLocationsKey" : {
},
"DVTSourceControlWorkspaceBlueprintWorkingCopyStatesKey" : {
"8B2E522D57154DFA93A06982C36315ECBEA4FA97" : 0,
"95438028B10BBB846574013D29F154A00556A9D1" : 0,
"4B60F1BCB491FF717C56441AE7783C74F417BE48" : 0
},
"DVTSourceControlWorkspaceBlueprintIdentifierKey" : "EBFDEFFE-8BA0-441A-862A-1DE28AA5CD21",
"DVTSourceControlWorkspaceBlueprintWorkingCopyPathsKey" : {
"8B2E522D57154DFA93A06982C36315ECBEA4FA97" : "CoreStore\/Carthage\/Checkouts\/GCDKit\/",
"95438028B10BBB846574013D29F154A00556A9D1" : "CoreStore\/Carthage\/Checkouts\/Nimble\/",
"4B60F1BCB491FF717C56441AE7783C74F417BE48" : "CoreStore\/"
},
"DVTSourceControlWorkspaceBlueprintNameKey" : "CoreStore",
"DVTSourceControlWorkspaceBlueprintVersion" : 204,
"DVTSourceControlWorkspaceBlueprintRelativePathToProjectKey" : "CoreStore.xcworkspace",
"DVTSourceControlWorkspaceBlueprintRemoteRepositoriesKey" : [
{
"DVTSourceControlWorkspaceBlueprintRemoteRepositoryURLKey" : "https:\/\/github.com\/JohnEstropia\/CoreStore",
"DVTSourceControlWorkspaceBlueprintRemoteRepositorySystemKey" : "com.apple.dt.Xcode.sourcecontrol.Git",
"DVTSourceControlWorkspaceBlueprintRemoteRepositoryIdentifierKey" : "4B60F1BCB491FF717C56441AE7783C74F417BE48"
},
{
"DVTSourceControlWorkspaceBlueprintRemoteRepositoryURLKey" : "https:\/\/github.com\/JohnEstropia\/GCDKit.git",
"DVTSourceControlWorkspaceBlueprintRemoteRepositorySystemKey" : "com.apple.dt.Xcode.sourcecontrol.Git",
"DVTSourceControlWorkspaceBlueprintRemoteRepositoryIdentifierKey" : "8B2E522D57154DFA93A06982C36315ECBEA4FA97"
},
{
"DVTSourceControlWorkspaceBlueprintRemoteRepositoryURLKey" : "https:\/\/github.com\/Quick\/Nimble.git",
"DVTSourceControlWorkspaceBlueprintRemoteRepositorySystemKey" : "com.apple.dt.Xcode.sourcecontrol.Git",
"DVTSourceControlWorkspaceBlueprintRemoteRepositoryIdentifierKey" : "95438028B10BBB846574013D29F154A00556A9D1"
}
]
}
@@ -1,271 +0,0 @@
//
// BaseDataTransaction+Querying.swift
// CoreStore
//
// Copyright (c) 2015 John Rommel Estropia
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in all
// copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
// SOFTWARE.
//
import Foundation
import CoreData
// MARK: - DataTransaction
public extension BaseDataTransaction {
// MARK: Public
/**
Fetches the first `NSManagedObject` instance that satisfies the specified `FetchClause`s. Accepts `Where`, `OrderBy`, and `Tweak` clauses.
:param: from a `From` clause indicating the entity type
:param: fetchClauses a series of `FetchClause` instances for the fetch request. Accepts `Where`, `OrderBy`, and `Tweak` clauses.
:returns: the first `NSManagedObject` instance that satisfies the specified `FetchClause`s
*/
public func fetchOne<T: NSManagedObject>(from: From<T>, _ fetchClauses: FetchClause...) -> T? {
CoreStore.assert(self.transactionQueue.isCurrentExecutionContext(), "Attempted to fetch from a \(typeName(self)) outside its designated queue.")
return self.context.fetchOne(from, fetchClauses)
}
/**
Fetches the first `NSManagedObject` instance that satisfies the specified `FetchClause`s. Accepts `Where`, `OrderBy`, and `Tweak` clauses.
:param: from a `From` clause indicating the entity type
:param: fetchClauses a series of `FetchClause` instances for the fetch request. Accepts `Where`, `OrderBy`, and `Tweak` clauses.
:returns: the first `NSManagedObject` instance that satisfies the specified `FetchClause`s
*/
public func fetchOne<T: NSManagedObject>(from: From<T>, _ fetchClauses: [FetchClause]) -> T? {
CoreStore.assert(self.transactionQueue.isCurrentExecutionContext(), "Attempted to fetch from a \(typeName(self)) outside its designated queue.")
return self.context.fetchOne(from, fetchClauses)
}
/**
Fetches all `NSManagedObject` instances that satisfy the specified `FetchClause`s. Accepts `Where`, `OrderBy`, and `Tweak` clauses.
:param: from a `From` clause indicating the entity type
:param: fetchClauses a series of `FetchClause` instances for the fetch request. Accepts `Where`, `OrderBy`, and `Tweak` clauses.
:returns: all `NSManagedObject` instances that satisfy the specified `FetchClause`s
*/
public func fetchAll<T: NSManagedObject>(from: From<T>, _ fetchClauses: FetchClause...) -> [T]? {
CoreStore.assert(self.transactionQueue.isCurrentExecutionContext(), "Attempted to fetch from a \(typeName(self)) outside its designated queue.")
return self.context.fetchAll(from, fetchClauses)
}
/**
Fetches all `NSManagedObject` instances that satisfy the specified `FetchClause`s. Accepts `Where`, `OrderBy`, and `Tweak` clauses.
:param: from a `From` clause indicating the entity type
:param: fetchClauses a series of `FetchClause` instances for the fetch request. Accepts `Where`, `OrderBy`, and `Tweak` clauses.
:returns: all `NSManagedObject` instances that satisfy the specified `FetchClause`s
*/
public func fetchAll<T: NSManagedObject>(from: From<T>, _ fetchClauses: [FetchClause]) -> [T]? {
CoreStore.assert(self.transactionQueue.isCurrentExecutionContext(), "Attempted to fetch from a \(typeName(self)) outside its designated queue.")
return self.context.fetchAll(from, fetchClauses)
}
/**
Fetches the number of `NSManagedObject`'s that satisfy the specified `FetchClause`s. Accepts `Where`, `OrderBy`, and `Tweak` clauses.
:param: from a `From` clause indicating the entity type
:param: fetchClauses a series of `FetchClause` instances for the fetch request. Accepts `Where`, `OrderBy`, and `Tweak` clauses.
:returns: the number `NSManagedObject`'s that satisfy the specified `FetchClause`s
*/
public func fetchCount<T: NSManagedObject>(from: From<T>, _ fetchClauses: FetchClause...) -> Int? {
CoreStore.assert(self.transactionQueue.isCurrentExecutionContext(), "Attempted to fetch from a \(typeName(self)) outside its designated queue.")
return self.context.fetchCount(from, fetchClauses)
}
/**
Fetches the number of `NSManagedObject`'s that satisfy the specified `FetchClause`s. Accepts `Where`, `OrderBy`, and `Tweak` clauses.
:param: from a `From` clause indicating the entity type
:param: fetchClauses a series of `FetchClause` instances for the fetch request. Accepts `Where`, `OrderBy`, and `Tweak` clauses.
:returns: the number `NSManagedObject`'s that satisfy the specified `FetchClause`s
*/
public func fetchCount<T: NSManagedObject>(from: From<T>, _ fetchClauses: [FetchClause]) -> Int? {
CoreStore.assert(self.transactionQueue.isCurrentExecutionContext(), "Attempted to fetch from a \(typeName(self)) outside its designated queue.")
return self.context.fetchCount(from, fetchClauses)
}
/**
Fetches the `NSManagedObjectID` for the first `NSManagedObject` that satisfies the specified `FetchClause`s. Accepts `Where`, `OrderBy`, and `Tweak` clauses.
:param: from a `From` clause indicating the entity type
:param: fetchClauses a series of `FetchClause` instances for the fetch request. Accepts `Where`, `OrderBy`, and `Tweak` clauses.
:returns: the `NSManagedObjectID` for the first `NSManagedObject` that satisfies the specified `FetchClause`s
*/
public func fetchObjectID<T: NSManagedObject>(from: From<T>, _ fetchClauses: FetchClause...) -> NSManagedObjectID? {
CoreStore.assert(self.transactionQueue.isCurrentExecutionContext(), "Attempted to fetch from a \(typeName(self)) outside its designated queue.")
return self.context.fetchObjectID(from, fetchClauses)
}
/**
Fetches the `NSManagedObjectID` for the first `NSManagedObject` that satisfies the specified `FetchClause`s. Accepts `Where`, `OrderBy`, and `Tweak` clauses.
:param: from a `From` clause indicating the entity type
:param: fetchClauses a series of `FetchClause` instances for the fetch request. Accepts `Where`, `OrderBy`, and `Tweak` clauses.
:returns: the `NSManagedObjectID` for the first `NSManagedObject` that satisfies the specified `FetchClause`s
*/
public func fetchObjectID<T: NSManagedObject>(from: From<T>, _ fetchClauses: [FetchClause]) -> NSManagedObjectID? {
CoreStore.assert(self.transactionQueue.isCurrentExecutionContext(), "Attempted to fetch from a \(typeName(self)) outside its designated queue.")
return self.context.fetchObjectID(from, fetchClauses)
}
/**
Fetches the `NSManagedObjectID` for all `NSManagedObject`'s that satisfy the specified `FetchClause`s. Accepts `Where`, `OrderBy`, and `Tweak` clauses.
:param: from a `From` clause indicating the entity type
:param: fetchClauses a series of `FetchClause` instances for the fetch request. Accepts `Where`, `OrderBy`, and `Tweak` clauses.
:returns: the `NSManagedObjectID` for all `NSManagedObject`'s that satisfy the specified `FetchClause`s
*/
public func fetchObjectIDs<T: NSManagedObject>(from: From<T>, _ fetchClauses: FetchClause...) -> [NSManagedObjectID]? {
CoreStore.assert(self.transactionQueue.isCurrentExecutionContext(), "Attempted to fetch from a \(typeName(self)) outside its designated queue.")
return self.context.fetchObjectIDs(from, fetchClauses)
}
/**
Fetches the `NSManagedObjectID` for all `NSManagedObject`'s that satisfy the specified `FetchClause`s. Accepts `Where`, `OrderBy`, and `Tweak` clauses.
:param: from a `From` clause indicating the entity type
:param: fetchClauses a series of `FetchClause` instances for the fetch request. Accepts `Where`, `OrderBy`, and `Tweak` clauses.
:returns: the `NSManagedObjectID` for all `NSManagedObject`'s that satisfy the specified `FetchClause`s
*/
public func fetchObjectIDs<T: NSManagedObject>(from: From<T>, _ fetchClauses: [FetchClause]) -> [NSManagedObjectID]? {
CoreStore.assert(self.transactionQueue.isCurrentExecutionContext(), "Attempted to fetch from a \(typeName(self)) outside its designated queue.")
return self.context.fetchObjectIDs(from, fetchClauses)
}
/**
Deletes all `NSManagedObject`'s that satisfy the specified `DeleteClause`s. Accepts `Where`, `OrderBy`, and `Tweak` clauses.
:param: from a `From` clause indicating the entity type
:param: deleteClauses a series of `DeleteClause` instances for the delete request. Accepts `Where`, `OrderBy`, and `Tweak` clauses.
:returns: the number of `NSManagedObject`'s deleted
*/
public func deleteAll<T: NSManagedObject>(from: From<T>, _ deleteClauses: DeleteClause...) -> Int? {
CoreStore.assert(self.transactionQueue.isCurrentExecutionContext(), "Attempted to delete from a \(typeName(self)) outside its designated queue.")
return self.context.deleteAll(from, deleteClauses)
}
/**
Deletes all `NSManagedObject`'s that satisfy the specified `DeleteClause`s. Accepts `Where`, `OrderBy`, and `Tweak` clauses.
:param: from a `From` clause indicating the entity type
:param: deleteClauses a series of `DeleteClause` instances for the delete request. Accepts `Where`, `OrderBy`, and `Tweak` clauses.
:returns: the number of `NSManagedObject`'s deleted
*/
public func deleteAll<T: NSManagedObject>(from: From<T>, _ deleteClauses: [DeleteClause]) -> Int? {
CoreStore.assert(self.transactionQueue.isCurrentExecutionContext(), "Attempted to delete from a \(typeName(self)) outside its designated queue.")
return self.context.deleteAll(from, deleteClauses)
}
/**
Queries aggregate values as specified by the `QueryClause`'s. Requires at least a `Select` clause, and optional `Where`, `OrderBy`, `GroupBy`, and `Tweak` clauses.
A "query" differs from a "fetch" in that it only retrieves values already stored in the persistent store. As such, values from unsaved transactions or contexts will not be incorporated in the query result.
:param: from a `From` clause indicating the entity type
:param: selectClause a `Select<U>` clause indicating the properties to fetch, and with the generic type indicating the return type.
:param: queryClauses a series of `QueryClause` instances for the query request. Accepts `Where`, `OrderBy`, `GroupBy`, and `Tweak` clauses.
:returns: the result of the the query. The type of the return value is specified by the generic type of the `Select<U>` parameter.
*/
public func queryValue<T: NSManagedObject, U: SelectValueResultType>(from: From<T>, _ selectClause: Select<U>, _ queryClauses: QueryClause...) -> U? {
CoreStore.assert(self.transactionQueue.isCurrentExecutionContext(), "Attempted to query from a \(typeName(self)) outside its designated queue.")
return self.context.queryValue(from, selectClause, queryClauses)
}
/**
Queries aggregate values or aggregates as specified by the `QueryClause`'s. Requires at least a `Select` clause, and optional `Where`, `OrderBy`, `GroupBy`, and `Tweak` clauses.
A "query" differs from a "fetch" in that it only retrieves values already stored in the persistent store. As such, values from unsaved transactions or contexts will not be incorporated in the query result.
:param: from a `From` clause indicating the entity type
:param: selectClause a `Select<U>` clause indicating the properties to fetch, and with the generic type indicating the return type.
:param: queryClauses a series of `QueryClause` instances for the query request. Accepts `Where`, `OrderBy`, `GroupBy`, and `Tweak` clauses.
:returns: the result of the the query. The type of the return value is specified by the generic type of the `Select<U>` parameter.
*/
public func queryValue<T: NSManagedObject, U: SelectValueResultType>(from: From<T>, _ selectClause: Select<U>, _ queryClauses: [QueryClause]) -> U? {
CoreStore.assert(self.transactionQueue.isCurrentExecutionContext(), "Attempted to query from a \(typeName(self)) outside its designated queue.")
return self.context.queryValue(from, selectClause, queryClauses)
}
/**
Queries a dictionary of attribute values as specified by the `QueryClause`'s. Requires at least a `Select` clause, and optional `Where`, `OrderBy`, `GroupBy`, and `Tweak` clauses.
A "query" differs from a "fetch" in that it only retrieves values already stored in the persistent store. As such, values from unsaved transactions or contexts will not be incorporated in the query result.
:param: from a `From` clause indicating the entity type
:param: selectClause a `Select<U>` clause indicating the properties to fetch, and with the generic type indicating the return type.
:param: queryClauses a series of `QueryClause` instances for the query request. Accepts `Where`, `OrderBy`, `GroupBy`, and `Tweak` clauses.
:returns: the result of the the query. The type of the return value is specified by the generic type of the `Select<U>` parameter.
*/
public func queryAttributes<T: NSManagedObject>(from: From<T>, _ selectClause: Select<NSDictionary>, _ queryClauses: QueryClause...) -> [[NSString: AnyObject]]? {
CoreStore.assert(self.transactionQueue.isCurrentExecutionContext(), "Attempted to query from a \(typeName(self)) outside its designated queue.")
return self.context.queryAttributes(from, selectClause, queryClauses)
}
/**
Queries a dictionary of attribute values as specified by the `QueryClause`'s. Requires at least a `Select` clause, and optional `Where`, `OrderBy`, `GroupBy`, and `Tweak` clauses.
A "query" differs from a "fetch" in that it only retrieves values already stored in the persistent store. As such, values from unsaved transactions or contexts will not be incorporated in the query result.
:param: from a `From` clause indicating the entity type
:param: selectClause a `Select<U>` clause indicating the properties to fetch, and with the generic type indicating the return type.
:param: queryClauses a series of `QueryClause` instances for the query request. Accepts `Where`, `OrderBy`, `GroupBy`, and `Tweak` clauses.
:returns: the result of the the query. The type of the return value is specified by the generic type of the `Select<U>` parameter.
*/
public func queryAttributes<T: NSManagedObject>(from: From<T>, _ selectClause: Select<NSDictionary>, _ queryClauses: [QueryClause]) -> [[NSString: AnyObject]]? {
CoreStore.assert(self.transactionQueue.isCurrentExecutionContext(), "Attempted to query from a \(typeName(self)) outside its designated queue.")
return self.context.queryAttributes(from, selectClause, queryClauses)
}
}
@@ -1,158 +0,0 @@
//
// From.swift
// CoreStore
//
// Copyright (c) 2015 John Rommel Estropia
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in all
// copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
// SOFTWARE.
//
import Foundation
import CoreData
// MARK: - From
/**
A `Form` clause binds the `NSManagedObject` entity type to the generics type system.
*/
public struct From<T: NSManagedObject> {
// MARK: Public
public init(){
self.findPersistentStores = { _ in nil }
}
public init(_ entity: T.Type) {
self.findPersistentStores = { _ in nil }
}
public init(_ configurations: String?...) {
self.init(configurations: configurations)
}
public init(_ configurations: [String?]) {
self.init(configurations: configurations)
}
public init(_ entity: T.Type, _ configurations: String?...) {
self.init(configurations: configurations)
}
public init(_ entity: T.Type, _ configurations: [String?]) {
self.init(configurations: configurations)
}
public init(_ storeURLs: NSURL...) {
self.init(storeURLs: storeURLs)
}
public init(_ storeURLs: [NSURL]) {
self.init(storeURLs: storeURLs)
}
public init(_ entity: T.Type, _ storeURLs: NSURL...) {
self.init(storeURLs: storeURLs)
}
public init(_ entity: T.Type, _ storeURLs: [NSURL]) {
self.init(storeURLs: storeURLs)
}
public init(_ persistentStores: NSPersistentStore...) {
self.init(persistentStores: persistentStores)
}
public init(_ persistentStores: [NSPersistentStore]) {
self.init(persistentStores: persistentStores)
}
public init(_ entity: T.Type, _ persistentStores: NSPersistentStore...) {
self.init(persistentStores: persistentStores)
}
public init(_ entity: T.Type, _ persistentStores: [NSPersistentStore]) {
self.init(persistentStores: persistentStores)
}
// MARK: Internal
internal func applyToFetchRequest(fetchRequest: NSFetchRequest, context: NSManagedObjectContext) {
fetchRequest.entity = context.entityDescriptionForEntityClass(T.self)
fetchRequest.affectedStores = self.findPersistentStores(context: context)
}
// MARK: Private
private let findPersistentStores: (context: NSManagedObjectContext) -> [NSPersistentStore]?
private init(configurations: [String?]) {
let configurationsSet = Set(configurations.map { $0 ?? Into.defaultConfigurationName })
self.findPersistentStores = { (context: NSManagedObjectContext) -> [NSPersistentStore]? in
return context.parentStack?.persistentStoresForEntityClass(T.self)?.filter {
return configurationsSet.contains($0.configurationName)
}
}
}
private init(storeURLs: [NSURL]) {
let storeURLsSet = Set(storeURLs)
self.findPersistentStores = { (context: NSManagedObjectContext) -> [NSPersistentStore]? in
return context.parentStack?.persistentStoresForEntityClass(T.self)?.filter {
return $0.URL != nil && storeURLsSet.contains($0.URL!)
}
}
}
private init(persistentStores: [NSPersistentStore]) {
let persistentStores = Set(persistentStores)
self.findPersistentStores = { (context: NSManagedObjectContext) -> [NSPersistentStore]? in
return context.parentStack?.persistentStoresForEntityClass(T.self)?.filter {
return persistentStores.contains($0)
}
}
}
}
@@ -1,148 +0,0 @@
//
// OrderBy.swift
// CoreStore
//
// Copyright (c) 2015 John Rommel Estropia
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in all
// copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
// SOFTWARE.
//
import Foundation
public func +(left: OrderBy, right: OrderBy) -> OrderBy {
return OrderBy(left.sortDescriptors + right.sortDescriptors)
}
public func +=(inout left: OrderBy, right: OrderBy) {
left = left + right
}
// MARK: - KeyPath
public typealias KeyPath = String
// MARK: - SortKey
/**
The `SortKey` is passed to the `OrderBy` clause to indicate the sort keys and their sort direction.
*/
public enum SortKey {
/**
Indicates that the `KeyPath` should be sorted in ascending order
*/
case Ascending(KeyPath)
/**
Indicates that the `KeyPath` should be sorted in descending order
*/
case Descending(KeyPath)
}
// MARK: - OrderBy
/**
The `OrderBy` clause specifies the sort order for results for a fetch or a query.
*/
public struct OrderBy: FetchClause, QueryClause, DeleteClause {
// MARK: Public
/**
Initializes a `OrderBy` clause with a list of sort descriptors
:param: sortDescriptors a series of `NSSortDescriptor`'s
*/
public init(_ sortDescriptors: [NSSortDescriptor]) {
self.sortDescriptors = sortDescriptors
}
/**
Initializes a `OrderBy` clause with an empty list of sort descriptors
*/
public init() {
self.init([NSSortDescriptor]())
}
/**
Initializes a `OrderBy` clause with a single sort descriptor
:param: sortDescriptor a `NSSortDescriptor`
*/
public init(_ sortDescriptor: NSSortDescriptor) {
self.init([sortDescriptor])
}
/**
Initializes a `OrderBy` clause with a series of `SortKey`'s
:param: sortKey a series of `SortKey`'s
*/
public init(_ sortKey: [SortKey]) {
self.init(
sortKey.map { SortKey -> NSSortDescriptor in
switch SortKey {
case .Ascending(let keyPath):
return NSSortDescriptor(key: keyPath, ascending: true)
case .Descending(let keyPath):
return NSSortDescriptor(key: keyPath, ascending: false)
}
}
)
}
/**
Initializes a `OrderBy` clause with a series of `SortKey`'s
:param: sortKey a single `SortKey`
:param: sortKeys a series of `SortKey`'s
*/
public init(_ sortKey: SortKey, _ sortKeys: SortKey...) {
self.init([sortKey] + sortKeys)
}
public let sortDescriptors: [NSSortDescriptor]
// MARK: FetchClause, QueryClause, DeleteClause
public func applyToFetchRequest(fetchRequest: NSFetchRequest) {
if fetchRequest.sortDescriptors != nil {
CoreStore.log(.Warning, message: "Existing sortDescriptors for the <\(NSFetchRequest.self)> was overwritten by \(typeName(self)) query clause.")
}
fetchRequest.sortDescriptors = self.sortDescriptors
}
}
@@ -1,663 +0,0 @@
//
// Select.swift
// CoreStore
//
// Copyright (c) 2015 John Rommel Estropia
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in all
// copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
// SOFTWARE.
//
import Foundation
import CoreData
// MARK: - SelectResultType
/**
The `SelectResultType` protocol is implemented by return types supported by the `Select` clause.
*/
public protocol SelectResultType { }
// MARK: - SelectValueResultType
/**
The `SelectValueResultType` protocol is implemented by return types supported by the `queryValue(...)` methods.
*/
public protocol SelectValueResultType: SelectResultType {
static func fromResultObject(result: AnyObject) -> Self?
}
// MARK: - SelectAttributesResultType
/**
The `SelectValueResultType` protocol is implemented by return types supported by the `queryAttributes(...)` methods.
*/
public protocol SelectAttributesResultType: SelectResultType {
static func fromResultObjects(result: [AnyObject]) -> [[NSString: AnyObject]]
}
// MARK: - SelectTerm
/**
The `SelectTerm` is passed to the `Select` clause to indicate the attributes/aggregate keys to be queried.
*/
public enum SelectTerm: StringLiteralConvertible {
// MARK: Public
/**
Provides a `SelectTerm` to a `Select` clause for querying an entity attribute. A shorter way to do the same is to assign from the string keypath directly:
let fullName = CoreStore.queryValue(
From(MyPersonEntity),
Select<String>(.Attribute("fullName")),
Where("employeeID", isEqualTo: 1111)
)
is equivalent to:
let fullName = CoreStore.queryValue(
From(MyPersonEntity),
Select<String>("fullName"),
Where("employeeID", isEqualTo: 1111)
)
:param: keyPath the attribute name
:returns: a `SelectTerm` to a `Select` clause for querying an entity attribute
*/
public static func Attribute(keyPath: KeyPath) -> SelectTerm {
return ._Attribute(keyPath)
}
/**
Provides a `SelectTerm` to a `Select` clause for querying the average value of an attribute.
let averageAge = CoreStore.queryValue(
From(MyPersonEntity),
Select<Int>(.Average("age"))
)
:param: keyPath the attribute name
:param: alias the dictionary key to use to access the result. Ignored when the query return value is not an `NSDictionary`. If `nil`, the default key "average(<attributeName>)" is used
:returns: a `SelectTerm` to a `Select` clause for querying the average value of an attribute
*/
public static func Average(keyPath: KeyPath, As alias: KeyPath? = nil) -> SelectTerm {
return ._Aggregate(
function: "average:",
keyPath,
As: alias ?? "average(\(keyPath))",
nativeType: .DecimalAttributeType
)
}
/**
Provides a `SelectTerm` to a `Select` clause for a count query.
let numberOfEmployees = CoreStore.queryValue(
From(MyPersonEntity),
Select<Int>(.Count("employeeID"))
)
:param: keyPath the attribute name
:param: alias the dictionary key to use to access the result. Ignored when the query return value is not an `NSDictionary`. If `nil`, the default key "count(<attributeName>)" is used
:returns: a `SelectTerm` to a `Select` clause for a count query
*/
public static func Count(keyPath: KeyPath, As alias: KeyPath? = nil) -> SelectTerm {
return ._Aggregate(
function: "count:",
keyPath,
As: alias ?? "count(\(keyPath))",
nativeType: .Integer64AttributeType
)
}
/**
Provides a `SelectTerm` to a `Select` clause for querying the maximum value for an attribute.
let maximumAge = CoreStore.queryValue(
From(MyPersonEntity),
Select<Int>(.Maximum("age"))
)
:param: keyPath the attribute name
:param: alias the dictionary key to use to access the result. Ignored when the query return value is not an `NSDictionary`. If `nil`, the default key "max(<attributeName>)" is used
:returns: a `SelectTerm` to a `Select` clause for querying the maximum value for an attribute
*/
public static func Maximum(keyPath: KeyPath, As alias: KeyPath? = nil) -> SelectTerm {
return ._Aggregate(
function: "max:",
keyPath,
As: alias ?? "max(\(keyPath))",
nativeType: .UndefinedAttributeType
)
}
/**
Provides a `SelectTerm` to a `Select` clause for querying the minimum value for an attribute.
let minimumAge = CoreStore.queryValue(
From(MyPersonEntity),
Select<Int>(.Minimum("age"))
)
:param: keyPath the attribute name
:param: alias the dictionary key to use to access the result. Ignored when the query return value is not an `NSDictionary`. If `nil`, the default key "min(<attributeName>)" is used
:returns: a `SelectTerm` to a `Select` clause for querying the minimum value for an attribute
*/
public static func Minimum(keyPath: KeyPath, As alias: KeyPath? = nil) -> SelectTerm {
return ._Aggregate(
function: "min:",
keyPath,
As: alias ?? "min(\(keyPath))",
nativeType: .UndefinedAttributeType
)
}
/**
Provides a `SelectTerm` to a `Select` clause for querying the sum value for an attribute.
let totalAge = CoreStore.queryValue(
From(MyPersonEntity),
Select<Int>(.Sum("age"))
)
:param: keyPath the attribute name
:param: alias the dictionary key to use to access the result. Ignored when the query return value is not an `NSDictionary`. If `nil`, the default key "sum(<attributeName>)" is used
:returns: a `SelectTerm` to a `Select` clause for querying the sum value for an attribute
*/
public static func Sum(keyPath: KeyPath, As alias: KeyPath? = nil) -> SelectTerm {
return ._Aggregate(
function: "sum:",
keyPath,
As: alias ?? "sum(\(keyPath))",
nativeType: .DecimalAttributeType
)
}
// MARK: StringLiteralConvertible
public init(stringLiteral value: KeyPath) {
self = ._Attribute(value)
}
public init(unicodeScalarLiteral value: KeyPath) {
self = ._Attribute(value)
}
public init(extendedGraphemeClusterLiteral value: KeyPath) {
self = ._Attribute(value)
}
// MARK: Internal
case _Attribute(KeyPath)
case _Aggregate(function: String, KeyPath, As: String, nativeType: NSAttributeType)
}
// MARK: - Select
/**
The `Select` clause indicates the attribute / aggregate value to be queried. The generic type is a `SelectResultType`, and will be used as the return type for the query.
You can bind the return type by specializing the initializer:
let maximumAge = CoreStore.queryValue(
From(MyPersonEntity),
Select<Int>(.Maximum("age"))
)
or by casting the type of the return value:
let maximumAge: Int = CoreStore.queryValue(
From(MyPersonEntity),
Select(.Maximum("age"))
)
Valid return types depend on the query:
- for `queryValue(...)` methods:
- `Bool`
- `Int8`
- `Int16`
- `Int32`
- `Int64`
- `Double`
- `Float`
- `String`
- `NSNumber`
- `NSString`
- `NSDecimalNumber`
- `NSDate`
- `NSData`
- `NSManagedObjectID`
- `NSString`
- for `queryAttributes(...)` methods:
- `NSDictionary`
:param: sortDescriptors a series of `NSSortDescriptor`'s
*/
public struct Select<T: SelectResultType> {
// MARK: Public
/**
The `SelectResultType` type for the query's return value
*/
public typealias ReturnType = T
/**
Initializes a `Select` clause with a list of `SelectTerm`'s
:param: selectTerm a `SelectTerm`
:param: selectTerms a series of `SelectTerm`'s
*/
public init(_ selectTerm: SelectTerm, _ selectTerms: SelectTerm...) {
self.selectTerms = [selectTerm] + selectTerms
}
// MARK: Internal
internal func applyToFetchRequest(fetchRequest: NSFetchRequest) {
if fetchRequest.propertiesToFetch != nil {
CoreStore.log(.Warning, message: "An existing \"propertiesToFetch\" for the <\(NSFetchRequest.self)> was overwritten by \(typeName(self)) query clause.")
}
fetchRequest.includesPendingChanges = false
fetchRequest.resultType = .DictionaryResultType
let entityDescription = fetchRequest.entity!
let propertiesByName = entityDescription.propertiesByName
let attributesByName = entityDescription.attributesByName
var propertiesToFetch = [AnyObject]()
for term in self.selectTerms {
switch term {
case ._Attribute(let keyPath):
if let propertyDescription = propertiesByName[keyPath] as? NSPropertyDescription {
propertiesToFetch.append(propertyDescription)
}
else {
CoreStore.log(.Warning, message: "The property \"\(keyPath)\" does not exist in entity <\(entityDescription.managedObjectClassName)> and will be ignored by \(typeName(self)) query clause.")
}
case ._Aggregate(let function, let keyPath, let alias, let nativeType):
if let attributeDescription = attributesByName[keyPath] as? NSAttributeDescription {
let expressionDescription = NSExpressionDescription()
expressionDescription.name = alias
if nativeType == .UndefinedAttributeType {
expressionDescription.expressionResultType = attributeDescription.attributeType
}
else {
expressionDescription.expressionResultType = nativeType
}
expressionDescription.expression = NSExpression(
forFunction: function,
arguments: [NSExpression(forKeyPath: keyPath)]
)
propertiesToFetch.append(expressionDescription)
}
else {
CoreStore.log(.Warning, message: "The attribute \"\(keyPath)\" does not exist in entity <\(entityDescription.managedObjectClassName)> and will be ignored by \(typeName(self)) query clause.")
}
}
}
fetchRequest.propertiesToFetch = propertiesToFetch
}
internal func keyPathForFirstSelectTerm() -> KeyPath {
switch self.selectTerms.first! {
case ._Attribute(let keyPath):
return keyPath
case ._Aggregate(_, _, let alias, _):
return alias
}
}
// MARK: Private
private let selectTerms: [SelectTerm]
}
// MARK: - Bool: SelectValueResultType
extension Bool: SelectValueResultType {
public static var attributeType: NSAttributeType {
return .BooleanAttributeType
}
public static func fromResultObject(result: AnyObject) -> Bool? {
return (result as? NSNumber)?.boolValue
}
}
// MARK: - Int8: SelectValueResultType
extension Int8: SelectValueResultType {
public static var attributeType: NSAttributeType {
return .Integer64AttributeType
}
public static func fromResultObject(result: AnyObject) -> Int8? {
if let value = (result as? NSNumber)?.longLongValue {
return numericCast(value) as Int8
}
return nil
}
}
// MARK: - Int16: SelectValueResultType
extension Int16: SelectValueResultType {
public static var attributeType: NSAttributeType {
return .Integer64AttributeType
}
public static func fromResultObject(result: AnyObject) -> Int16? {
if let value = (result as? NSNumber)?.longLongValue {
return numericCast(value) as Int16
}
return nil
}
}
// MARK: - Int32: SelectValueResultType
extension Int32: SelectValueResultType {
public static var attributeType: NSAttributeType {
return .Integer64AttributeType
}
public static func fromResultObject(result: AnyObject) -> Int32? {
if let value = (result as? NSNumber)?.longLongValue {
return numericCast(value) as Int32
}
return nil
}
}
// MARK: - Int64: SelectValueResultType
extension Int64: SelectValueResultType {
public static var attributeType: NSAttributeType {
return .Integer64AttributeType
}
public static func fromResultObject(result: AnyObject) -> Int64? {
return (result as? NSNumber)?.longLongValue
}
}
// MARK: - Int: SelectValueResultType
extension Int: SelectValueResultType {
public static var attributeType: NSAttributeType {
return .Integer64AttributeType
}
public static func fromResultObject(result: AnyObject) -> Int? {
if let value = (result as? NSNumber)?.longLongValue {
return numericCast(value) as Int
}
return nil
}
}
// MARK: - Double : SelectValueResultType
extension Double: SelectValueResultType {
public static var attributeType: NSAttributeType {
return .DoubleAttributeType
}
public static func fromResultObject(result: AnyObject) -> Double? {
return (result as? NSNumber)?.doubleValue
}
}
// MARK: - Float: SelectValueResultType
extension Float: SelectValueResultType {
public static var attributeType: NSAttributeType {
return .FloatAttributeType
}
public static func fromResultObject(result: AnyObject) -> Float? {
return (result as? NSNumber)?.floatValue
}
}
// MARK: - String: SelectValueResultType
extension String: SelectValueResultType {
public static var attributeType: NSAttributeType {
return .StringAttributeType
}
public static func fromResultObject(result: AnyObject) -> String? {
return result as? NSString as? String
}
}
// MARK: - NSNumber: SelectValueResultType
extension NSNumber: SelectValueResultType {
public class var attributeType: NSAttributeType {
return .Integer64AttributeType
}
public class func fromResultObject(result: AnyObject) -> Self? {
func forceCast<T: NSNumber>(object: AnyObject) -> T? {
return (object as? T)
}
return forceCast(result)
}
}
// MARK: - NSString: SelectValueResultType
extension NSString: SelectValueResultType {
public class var attributeType: NSAttributeType {
return .StringAttributeType
}
public class func fromResultObject(result: AnyObject) -> Self? {
func forceCast<T: NSString>(object: AnyObject) -> T? {
return (object as? T)
}
return forceCast(result)
}
}
// MARK: - NSDecimalNumber: SelectValueResultType
extension NSDecimalNumber: SelectValueResultType {
public override class var attributeType: NSAttributeType {
return .DecimalAttributeType
}
public override class func fromResultObject(result: AnyObject) -> Self? {
func forceCast<T: NSDecimalNumber>(object: AnyObject) -> T? {
return (object as? T)
}
return forceCast(result)
}
}
// MARK: - NSDate: SelectValueResultType
extension NSDate: SelectValueResultType {
public class var attributeType: NSAttributeType {
return .DateAttributeType
}
public class func fromResultObject(result: AnyObject) -> Self? {
func forceCast<T: NSDate>(object: AnyObject) -> T? {
return (object as? T)
}
return forceCast(result)
}
}
// MARK: - NSData: SelectValueResultType
extension NSData: SelectValueResultType {
public class var attributeType: NSAttributeType {
return .BinaryDataAttributeType
}
public class func fromResultObject(result: AnyObject) -> Self? {
func forceCast<T: NSData>(object: AnyObject) -> T? {
return (object as? T)
}
return forceCast(result)
}
}
// MARK: - NSManagedObjectID: SelectValueResultType
extension NSManagedObjectID: SelectValueResultType {
public class var attributeType: NSAttributeType {
return .ObjectIDAttributeType
}
public class func fromResultObject(result: AnyObject) -> Self? {
func forceCast<T: NSManagedObjectID>(object: AnyObject) -> T? {
return (object as? T)
}
return forceCast(result)
}
}
// MARK: - NSManagedObjectID: SelectAttributesResultType
extension NSDictionary: SelectAttributesResultType {
// MARK: SelectAttributesResultType
public class func fromResultObjects(result: [AnyObject]) -> [[NSString: AnyObject]] {
return result as! [[NSString: AnyObject]]
}
}
@@ -1,131 +0,0 @@
//
// Where.swift
// CoreStore
//
// Copyright (c) 2015 John Rommel Estropia
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in all
// copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
// SOFTWARE.
//
import Foundation
public func &&(left: Where, right: Where) -> Where {
return Where(NSCompoundPredicate(type: .AndPredicateType, subpredicates: [left.predicate, right.predicate]))
}
public func ||(left: Where, right: Where) -> Where {
return Where(NSCompoundPredicate(type: .OrPredicateType, subpredicates: [left.predicate, right.predicate]))
}
public prefix func !(clause: Where) -> Where {
return Where(NSCompoundPredicate(type: .NotPredicateType, subpredicates: [clause.predicate]))
}
// MARK: - Where
/**
The `Where` clause specifies the conditions for a fetch or a query.
*/
public struct Where: FetchClause, QueryClause, DeleteClause {
// MARK: Public
/**
Initializes a `Where` clause with an `NSPredicate`
:param: predicate the `NSPredicate` for the fetch or query
*/
public init(_ predicate: NSPredicate) {
self.predicate = predicate
}
/**
Initializes a `Where` clause with a predicate that always evaluates to `true`
*/
public init() {
self.init(true)
}
/**
Initializes a `Where` clause with a predicate that always evaluates to the specified boolean value
:param: value the boolean value for the predicate
*/
public init(_ value: Bool) {
self.init(NSPredicate(value: value))
}
/**
Initializes a `Where` clause with a predicate using the specified string format and arguments
:param: format the format string for the predicate
:param: args the arguments for `format`
*/
public init(_ format: String, _ args: NSObject...) {
self.init(NSPredicate(format: format, argumentArray: args))
}
/**
Initializes a `Where` clause with a predicate using the specified string format and arguments
:param: format the format string for the predicate
:param: argumentArray the arguments for `format`
*/
public init(_ format: String, argumentArray: [NSObject]?) {
self.init(NSPredicate(format: format, argumentArray: argumentArray))
}
/**
Initializes a `Where` clause with a predicate using the specified string format and arguments
:param: format the format string for the predicate
:param: argumentArray the arguments for `format`
*/
public init(_ keyPath: KeyPath, isEqualTo value: NSObject?) {
self.init(value == nil
? NSPredicate(format: "\(keyPath) == nil")
: NSPredicate(format: "\(keyPath) == %@", value!))
}
public let predicate: NSPredicate
// MARK: FetchClause, QueryClause, DeleteClause
public func applyToFetchRequest(fetchRequest: NSFetchRequest) {
if fetchRequest.predicate != nil {
CoreStore.log(.Warning, message: "An existing predicate for the <\(NSFetchRequest.self)> was overwritten by \(typeName(self)) query clause.")
}
fetchRequest.predicate = self.predicate
}
}
@@ -1,213 +0,0 @@
//
// CoreStore+Querying.swift
// CoreStore
//
// Copyright (c) 2015 John Rommel Estropia
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in all
// copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
// SOFTWARE.
//
import Foundation
// MARK: - CoreStore
public extension CoreStore {
// MARK: Public
/**
Using the `defaultStack`, fetches the first `NSManagedObject` instance that satisfies the specified `FetchClause`s. Accepts `Where`, `OrderBy`, and `Tweak` clauses.
:param: from a `From` clause indicating the entity type
:param: fetchClauses a series of `FetchClause` instances for the fetch request. Accepts `Where`, `OrderBy`, and `Tweak` clauses.
:returns: the first `NSManagedObject` instance that satisfies the specified `FetchClause`s
*/
public static func fetchOne<T: NSManagedObject>(from: From<T>, _ fetchClauses: FetchClause...) -> T? {
return self.defaultStack.fetchOne(from, fetchClauses)
}
/**
Using the `defaultStack`, fetches the first `NSManagedObject` instance that satisfies the specified `FetchClause`s. Accepts `Where`, `OrderBy`, and `Tweak` clauses.
:param: from a `From` clause indicating the entity type
:param: fetchClauses a series of `FetchClause` instances for the fetch request. Accepts `Where`, `OrderBy`, and `Tweak` clauses.
:returns: the first `NSManagedObject` instance that satisfies the specified `FetchClause`s
*/
public static func fetchOne<T: NSManagedObject>(from: From<T>, _ fetchClauses: [FetchClause]) -> T? {
return self.defaultStack.fetchOne(from, fetchClauses)
}
/**
Using the `defaultStack`, fetches all `NSManagedObject` instances that satisfy the specified `FetchClause`s. Accepts `Where`, `OrderBy`, and `Tweak` clauses.
:param: from a `From` clause indicating the entity type
:param: fetchClauses a series of `FetchClause` instances for the fetch request. Accepts `Where`, `OrderBy`, and `Tweak` clauses.
:returns: all `NSManagedObject` instances that satisfy the specified `FetchClause`s
*/
public static func fetchAll<T: NSManagedObject>(from: From<T>, _ fetchClauses: FetchClause...) -> [T]? {
return self.defaultStack.fetchAll(from, fetchClauses)
}
/**
Using the `defaultStack`, fetches all `NSManagedObject` instances that satisfy the specified `FetchClause`s. Accepts `Where`, `OrderBy`, and `Tweak` clauses.
:param: from a `From` clause indicating the entity type
:param: fetchClauses a series of `FetchClause` instances for the fetch request. Accepts `Where`, `OrderBy`, and `Tweak` clauses.
:returns: all `NSManagedObject` instances that satisfy the specified `FetchClause`s
*/
public static func fetchAll<T: NSManagedObject>(from: From<T>, _ fetchClauses: [FetchClause]) -> [T]? {
return self.defaultStack.fetchAll(from, fetchClauses)
}
/**
Using the `defaultStack`, fetches the number of `NSManagedObject`'s that satisfy the specified `FetchClause`s. Accepts `Where`, `OrderBy`, and `Tweak` clauses.
:param: from a `From` clause indicating the entity type
:param: fetchClauses a series of `FetchClause` instances for the fetch request. Accepts `Where`, `OrderBy`, and `Tweak` clauses.
:returns: the number `NSManagedObject`'s that satisfy the specified `FetchClause`s
*/
public static func fetchCount<T: NSManagedObject>(from: From<T>, _ fetchClauses: FetchClause...) -> Int? {
return self.defaultStack.fetchCount(from, fetchClauses)
}
/**
Using the `defaultStack`, fetches the number of `NSManagedObject`'s that satisfy the specified `FetchClause`s. Accepts `Where`, `OrderBy`, and `Tweak` clauses.
:param: from a `From` clause indicating the entity type
:param: fetchClauses a series of `FetchClause` instances for the fetch request. Accepts `Where`, `OrderBy`, and `Tweak` clauses.
:returns: the number `NSManagedObject`'s that satisfy the specified `FetchClause`s
*/
public static func fetchCount<T: NSManagedObject>(from: From<T>, _ fetchClauses: [FetchClause]) -> Int? {
return self.defaultStack.fetchCount(from, fetchClauses)
}
/**
Using the `defaultStack`, fetches the `NSManagedObjectID` for the first `NSManagedObject` that satisfies the specified `FetchClause`s. Accepts `Where`, `OrderBy`, and `Tweak` clauses.
:param: from a `From` clause indicating the entity type
:param: fetchClauses a series of `FetchClause` instances for the fetch request. Accepts `Where`, `OrderBy`, and `Tweak` clauses.
:returns: the `NSManagedObjectID` for the first `NSManagedObject` that satisfies the specified `FetchClause`s
*/
public static func fetchObjectID<T: NSManagedObject>(from: From<T>, _ fetchClauses: FetchClause...) -> NSManagedObjectID? {
return self.defaultStack.fetchObjectID(from, fetchClauses)
}
/**
Using the `defaultStack`, fetches the `NSManagedObjectID` for the first `NSManagedObject` that satisfies the specified `FetchClause`s. Accepts `Where`, `OrderBy`, and `Tweak` clauses.
:param: from a `From` clause indicating the entity type
:param: fetchClauses a series of `FetchClause` instances for the fetch request. Accepts `Where`, `OrderBy`, and `Tweak` clauses.
:returns: the `NSManagedObjectID` for the first `NSManagedObject` that satisfies the specified `FetchClause`s
*/
public static func fetchObjectID<T: NSManagedObject>(from: From<T>, _ fetchClauses: [FetchClause]) -> NSManagedObjectID? {
return self.defaultStack.fetchObjectID(from, fetchClauses)
}
/**
Using the `defaultStack`, fetches the `NSManagedObjectID` for all `NSManagedObject`'s that satisfy the specified `FetchClause`s. Accepts `Where`, `OrderBy`, and `Tweak` clauses.
:param: from a `From` clause indicating the entity type
:param: fetchClauses a series of `FetchClause` instances for the fetch request. Accepts `Where`, `OrderBy`, and `Tweak` clauses.
:returns: the `NSManagedObjectID` for all `NSManagedObject`'s that satisfy the specified `FetchClause`s
*/
public static func fetchObjectIDs<T: NSManagedObject>(from: From<T>, _ fetchClauses: FetchClause...) -> [NSManagedObjectID]? {
return self.defaultStack.fetchObjectIDs(from, fetchClauses)
}
/**
Using the `defaultStack`, fetches the `NSManagedObjectID` for all `NSManagedObject`'s that satisfy the specified `FetchClause`s. Accepts `Where`, `OrderBy`, and `Tweak` clauses.
:param: from a `From` clause indicating the entity type
:param: fetchClauses a series of `FetchClause` instances for the fetch request. Accepts `Where`, `OrderBy`, and `Tweak` clauses.
:returns: the `NSManagedObjectID` for all `NSManagedObject`'s that satisfy the specified `FetchClause`s
*/
public static func fetchObjectIDs<T: NSManagedObject>(from: From<T>, _ fetchClauses: [FetchClause]) -> [NSManagedObjectID]? {
return self.defaultStack.fetchObjectIDs(from, fetchClauses)
}
/**
Using the `defaultStack`, queries aggregate values as specified by the `QueryClause`'s. Requires at least a `Select` clause, and optional `Where`, `OrderBy`, `GroupBy`, and `Tweak` clauses.
A "query" differs from a "fetch" in that it only retrieves values already stored in the persistent store. As such, values from unsaved transactions or contexts will not be incorporated in the query result.
:param: from a `From` clause indicating the entity type
:param: selectClause a `Select<U>` clause indicating the properties to fetch, and with the generic type indicating the return type.
:param: queryClauses a series of `QueryClause` instances for the query request. Accepts `Where`, `OrderBy`, `GroupBy`, and `Tweak` clauses.
:returns: the result of the the query. The type of the return value is specified by the generic type of the `Select<U>` parameter.
*/
public static func queryValue<T: NSManagedObject, U: SelectValueResultType>(from: From<T>, _ selectClause: Select<U>, _ queryClauses: QueryClause...) -> U? {
return self.defaultStack.queryValue(from, selectClause, queryClauses)
}
/**
Using the `defaultStack`, queries aggregate values as specified by the `QueryClause`'s. Requires at least a `Select` clause, and optional `Where`, `OrderBy`, `GroupBy`, and `Tweak` clauses.
A "query" differs from a "fetch" in that it only retrieves values already stored in the persistent store. As such, values from unsaved transactions or contexts will not be incorporated in the query result.
:param: from a `From` clause indicating the entity type
:param: selectClause a `Select<U>` clause indicating the properties to fetch, and with the generic type indicating the return type.
:param: queryClauses a series of `QueryClause` instances for the query request. Accepts `Where`, `OrderBy`, `GroupBy`, and `Tweak` clauses.
:returns: the result of the the query. The type of the return value is specified by the generic type of the `Select<U>` parameter.
*/
public static func queryValue<T: NSManagedObject, U: SelectValueResultType>(from: From<T>, _ selectClause: Select<U>, _ queryClauses: [QueryClause]) -> U? {
return self.defaultStack.queryValue(from, selectClause, queryClauses)
}
/**
Using the `defaultStack`, queries a dictionary of attribtue values as specified by the `QueryClause`'s. Requires at least a `Select` clause, and optional `Where`, `OrderBy`, `GroupBy`, and `Tweak` clauses.
A "query" differs from a "fetch" in that it only retrieves values already stored in the persistent store. As such, values from unsaved transactions or contexts will not be incorporated in the query result.
:param: from a `From` clause indicating the entity type
:param: selectClause a `Select<U>` clause indicating the properties to fetch, and with the generic type indicating the return type.
:param: queryClauses a series of `QueryClause` instances for the query request. Accepts `Where`, `OrderBy`, `GroupBy`, and `Tweak` clauses.
:returns: the result of the the query. The type of the return value is specified by the generic type of the `Select<U>` parameter.
*/
public static func queryAttributes<T: NSManagedObject>(from: From<T>, _ selectClause: Select<NSDictionary>, _ queryClauses: QueryClause...) -> [[NSString: AnyObject]]? {
return self.defaultStack.queryAttributes(from, selectClause, queryClauses)
}
/**
Using the `defaultStack`, queries a dictionary of attribute values as specified by the `QueryClause`'s. Requires at least a `Select` clause, and optional `Where`, `OrderBy`, `GroupBy`, and `Tweak` clauses.
A "query" differs from a "fetch" in that it only retrieves values already stored in the persistent store. As such, values from unsaved transactions or contexts will not be incorporated in the query result.
:param: from a `From` clause indicating the entity type
:param: selectClause a `Select<U>` clause indicating the properties to fetch, and with the generic type indicating the return type.
:param: queryClauses a series of `QueryClause` instances for the query request. Accepts `Where`, `OrderBy`, `GroupBy`, and `Tweak` clauses.
:returns: the result of the the query. The type of the return value is specified by the generic type of the `Select<U>` parameter.
*/
public static func queryAttributes<T: NSManagedObject>(from: From<T>, _ selectClause: Select<NSDictionary>, _ queryClauses: [QueryClause]) -> [[NSString: AnyObject]]? {
return self.defaultStack.queryAttributes(from, selectClause, queryClauses)
}
}
@@ -1,244 +0,0 @@
//
// DataStack+Querying.swift
// CoreStore
//
// Copyright (c) 2015 John Rommel Estropia
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in all
// copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
// SOFTWARE.
//
import Foundation
import CoreData
import GCDKit
// MARK: - DataStack
public extension DataStack {
// MARK: Public
/**
Fetches the first `NSManagedObject` instance that satisfies the specified `FetchClause`s. Accepts `Where`, `OrderBy`, and `Tweak` clauses.
:param: from a `From` clause indicating the entity type
:param: fetchClauses a series of `FetchClause` instances for the fetch request. Accepts `Where`, `OrderBy`, and `Tweak` clauses.
:returns: the first `NSManagedObject` instance that satisfies the specified `FetchClause`s
*/
public func fetchOne<T: NSManagedObject>(from: From<T>, _ fetchClauses: FetchClause...) -> T? {
CoreStore.assert(NSThread.isMainThread(), "Attempted to fetch from a \(typeName(self)) outside the main thread.")
return self.mainContext.fetchOne(from, fetchClauses)
}
/**
Fetches the first `NSManagedObject` instance that satisfies the specified `FetchClause`s. Accepts `Where`, `OrderBy`, and `Tweak` clauses.
:param: from a `From` clause indicating the entity type
:param: fetchClauses a series of `FetchClause` instances for the fetch request. Accepts `Where`, `OrderBy`, and `Tweak` clauses.
:returns: the first `NSManagedObject` instance that satisfies the specified `FetchClause`s
*/
public func fetchOne<T: NSManagedObject>(from: From<T>, _ fetchClauses: [FetchClause]) -> T? {
CoreStore.assert(NSThread.isMainThread(), "Attempted to fetch from a \(typeName(self)) outside the main thread.")
return self.mainContext.fetchOne(from, fetchClauses)
}
/**
Fetches all `NSManagedObject` instances that satisfy the specified `FetchClause`s. Accepts `Where`, `OrderBy`, and `Tweak` clauses.
:param: from a `From` clause indicating the entity type
:param: fetchClauses a series of `FetchClause` instances for the fetch request. Accepts `Where`, `OrderBy`, and `Tweak` clauses.
:returns: all `NSManagedObject` instances that satisfy the specified `FetchClause`s
*/
public func fetchAll<T: NSManagedObject>(from: From<T>, _ fetchClauses: FetchClause...) -> [T]? {
CoreStore.assert(NSThread.isMainThread(), "Attempted to fetch from a \(typeName(self)) outside the main thread.")
return self.mainContext.fetchAll(from, fetchClauses)
}
/**
Fetches all `NSManagedObject` instances that satisfy the specified `FetchClause`s. Accepts `Where`, `OrderBy`, and `Tweak` clauses.
:param: from a `From` clause indicating the entity type
:param: fetchClauses a series of `FetchClause` instances for the fetch request. Accepts `Where`, `OrderBy`, and `Tweak` clauses.
:returns: all `NSManagedObject` instances that satisfy the specified `FetchClause`s
*/
public func fetchAll<T: NSManagedObject>(from: From<T>, _ fetchClauses: [FetchClause]) -> [T]? {
CoreStore.assert(NSThread.isMainThread(), "Attempted to fetch from a \(typeName(self)) outside the main thread.")
return self.mainContext.fetchAll(from, fetchClauses)
}
/**
Fetches the number of `NSManagedObject`'s that satisfy the specified `FetchClause`s. Accepts `Where`, `OrderBy`, and `Tweak` clauses.
:param: from a `From` clause indicating the entity type
:param: fetchClauses a series of `FetchClause` instances for the fetch request. Accepts `Where`, `OrderBy`, and `Tweak` clauses.
:returns: the number `NSManagedObject`'s that satisfy the specified `FetchClause`s
*/
public func fetchCount<T: NSManagedObject>(from: From<T>, _ fetchClauses: FetchClause...) -> Int? {
CoreStore.assert(NSThread.isMainThread(), "Attempted to fetch from a \(typeName(self)) outside the main thread.")
return self.mainContext.fetchCount(from, fetchClauses)
}
/**
Fetches the number of `NSManagedObject`'s that satisfy the specified `FetchClause`s. Accepts `Where`, `OrderBy`, and `Tweak` clauses.
:param: from a `From` clause indicating the entity type
:param: fetchClauses a series of `FetchClause` instances for the fetch request. Accepts `Where`, `OrderBy`, and `Tweak` clauses.
:returns: the number `NSManagedObject`'s that satisfy the specified `FetchClause`s
*/
public func fetchCount<T: NSManagedObject>(from: From<T>, _ fetchClauses: [FetchClause]) -> Int? {
CoreStore.assert(NSThread.isMainThread(), "Attempted to fetch from a \(typeName(self)) outside the main thread.")
return self.mainContext.fetchCount(from, fetchClauses)
}
/**
Fetches the `NSManagedObjectID` for the first `NSManagedObject` that satisfies the specified `FetchClause`s. Accepts `Where`, `OrderBy`, and `Tweak` clauses.
:param: from a `From` clause indicating the entity type
:param: fetchClauses a series of `FetchClause` instances for the fetch request. Accepts `Where`, `OrderBy`, and `Tweak` clauses.
:returns: the `NSManagedObjectID` for the first `NSManagedObject` that satisfies the specified `FetchClause`s
*/
public func fetchObjectID<T: NSManagedObject>(from: From<T>, _ fetchClauses: FetchClause...) -> NSManagedObjectID? {
CoreStore.assert(NSThread.isMainThread(), "Attempted to fetch from a \(typeName(self)) outside the main thread.")
return self.mainContext.fetchObjectID(from, fetchClauses)
}
/**
Fetches the `NSManagedObjectID` for the first `NSManagedObject` that satisfies the specified `FetchClause`s. Accepts `Where`, `OrderBy`, and `Tweak` clauses.
:param: from a `From` clause indicating the entity type
:param: fetchClauses a series of `FetchClause` instances for the fetch request. Accepts `Where`, `OrderBy`, and `Tweak` clauses.
:returns: the `NSManagedObjectID` for the first `NSManagedObject` that satisfies the specified `FetchClause`s
*/
public func fetchObjectID<T: NSManagedObject>(from: From<T>, _ fetchClauses: [FetchClause]) -> NSManagedObjectID? {
CoreStore.assert(NSThread.isMainThread(), "Attempted to fetch from a \(typeName(self)) outside the main thread.")
return self.mainContext.fetchObjectID(from, fetchClauses)
}
/**
Fetches the `NSManagedObjectID` for all `NSManagedObject`'s that satisfy the specified `FetchClause`s. Accepts `Where`, `OrderBy`, and `Tweak` clauses.
:param: from a `From` clause indicating the entity type
:param: fetchClauses a series of `FetchClause` instances for the fetch request. Accepts `Where`, `OrderBy`, and `Tweak` clauses.
:returns: the `NSManagedObjectID` for all `NSManagedObject`'s that satisfy the specified `FetchClause`s
*/
public func fetchObjectIDs<T: NSManagedObject>(from: From<T>, _ fetchClauses: FetchClause...) -> [NSManagedObjectID]? {
CoreStore.assert(NSThread.isMainThread(), "Attempted to fetch from a \(typeName(self)) outside the main thread.")
return self.mainContext.fetchObjectIDs(from, fetchClauses)
}
/**
Fetches the `NSManagedObjectID` for all `NSManagedObject`'s that satisfy the specified `FetchClause`s. Accepts `Where`, `OrderBy`, and `Tweak` clauses.
:param: from a `From` clause indicating the entity type
:param: fetchClauses a series of `FetchClause` instances for the fetch request. Accepts `Where`, `OrderBy`, and `Tweak` clauses.
:returns: the `NSManagedObjectID` for all `NSManagedObject`'s that satisfy the specified `FetchClause`s
*/
public func fetchObjectIDs<T: NSManagedObject>(from: From<T>, _ fetchClauses: [FetchClause]) -> [NSManagedObjectID]? {
CoreStore.assert(NSThread.isMainThread(), "Attempted to fetch from a \(typeName(self)) outside the main thread.")
return self.mainContext.fetchObjectIDs(from, fetchClauses)
}
/**
Queries aggregate values as specified by the `QueryClause`'s. Requires at least a `Select` clause, and optional `Where`, `OrderBy`, `GroupBy`, and `Tweak` clauses.
A "query" differs from a "fetch" in that it only retrieves values already stored in the persistent store. As such, values from unsaved transactions or contexts will not be incorporated in the query result.
:param: from a `From` clause indicating the entity type
:param: selectClause a `Select<U>` clause indicating the properties to fetch, and with the generic type indicating the return type.
:param: queryClauses a series of `QueryClause` instances for the query request. Accepts `Where`, `OrderBy`, `GroupBy`, and `Tweak` clauses.
:returns: the result of the the query. The type of the return value is specified by the generic type of the `Select<U>` parameter.
*/
public func queryValue<T: NSManagedObject, U: SelectValueResultType>(from: From<T>, _ selectClause: Select<U>, _ queryClauses: QueryClause...) -> U? {
CoreStore.assert(NSThread.isMainThread(), "Attempted to query from a \(typeName(self)) outside the main thread.")
return self.mainContext.queryValue(from, selectClause, queryClauses)
}
/**
Queries aggregate values as specified by the `QueryClause`'s. Requires at least a `Select` clause, and optional `Where`, `OrderBy`, `GroupBy`, and `Tweak` clauses.
A "query" differs from a "fetch" in that it only retrieves values already stored in the persistent store. As such, values from unsaved transactions or contexts will not be incorporated in the query result.
:param: from a `From` clause indicating the entity type
:param: selectClause a `Select<U>` clause indicating the properties to fetch, and with the generic type indicating the return type.
:param: queryClauses a series of `QueryClause` instances for the query request. Accepts `Where`, `OrderBy`, `GroupBy`, and `Tweak` clauses.
:returns: the result of the the query. The type of the return value is specified by the generic type of the `Select<U>` parameter.
*/
public func queryValue<T: NSManagedObject, U: SelectValueResultType>(from: From<T>, _ selectClause: Select<U>, _ queryClauses: [QueryClause]) -> U? {
CoreStore.assert(NSThread.isMainThread(), "Attempted to query from a \(typeName(self)) outside the main thread.")
return self.mainContext.queryValue(from, selectClause, queryClauses)
}
/**
Queries a dictionary of attribute values as specified by the `QueryClause`'s. Requires at least a `Select` clause, and optional `Where`, `OrderBy`, `GroupBy`, and `Tweak` clauses.
A "query" differs from a "fetch" in that it only retrieves values already stored in the persistent store. As such, values from unsaved transactions or contexts will not be incorporated in the query result.
:param: from a `From` clause indicating the entity type
:param: selectClause a `Select<U>` clause indicating the properties to fetch, and with the generic type indicating the return type.
:param: queryClauses a series of `QueryClause` instances for the query request. Accepts `Where`, `OrderBy`, `GroupBy`, and `Tweak` clauses.
:returns: the result of the the query. The type of the return value is specified by the generic type of the `Select<U>` parameter.
*/
public func queryAttributes<T: NSManagedObject>(from: From<T>, _ selectClause: Select<NSDictionary>, _ queryClauses: QueryClause...) -> [[NSString: AnyObject]]? {
CoreStore.assert(NSThread.isMainThread(), "Attempted to query from a \(typeName(self)) outside the main thread.")
return self.mainContext.queryAttributes(from, selectClause, queryClauses)
}
/**
Queries a dictionary of attribute values as specified by the `QueryClause`'s. Requires at least a `Select` clause, and optional `Where`, `OrderBy`, `GroupBy`, and `Tweak` clauses.
A "query" differs from a "fetch" in that it only retrieves values already stored in the persistent store. As such, values from unsaved transactions or contexts will not be incorporated in the query result.
:param: from a `From` clause indicating the entity type
:param: selectClause a `Select<U>` clause indicating the properties to fetch, and with the generic type indicating the return type.
:param: queryClauses a series of `QueryClause` instances for the query request. Accepts `Where`, `OrderBy`, `GroupBy`, and `Tweak` clauses.
:returns: the result of the the query. The type of the return value is specified by the generic type of the `Select<U>` parameter.
*/
public func queryAttributes<T: NSManagedObject>(from: From<T>, _ selectClause: Select<NSDictionary>, _ queryClauses: [QueryClause]) -> [[NSString: AnyObject]]? {
CoreStore.assert(NSThread.isMainThread(), "Attempted to query from a \(typeName(self)) outside the main thread.")
return self.mainContext.queryAttributes(from, selectClause, queryClauses)
}
}
@@ -1,68 +0,0 @@
//
// NSObject+CoreStore.swift
// CoreStore
//
// Copyright (c) 2014 John Rommel Estropia
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in all
// copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
// SOFTWARE.
//
import Foundation
internal func getAssociatedObjectForKey<T: AnyObject>(key: UnsafePointer<Void>, inObject object: AnyObject) -> T? {
switch objc_getAssociatedObject(object, key) {
case let associatedObject as T:
return associatedObject
case let associatedObject as WeakObject:
return associatedObject.object as? T
default:
return nil
}
}
internal func setAssociatedRetainedObject<T: AnyObject>(associatedObject: T?, forKey key: UnsafePointer<Void>, inObject object: AnyObject) {
objc_setAssociatedObject(object, key, associatedObject, UInt(OBJC_ASSOCIATION_RETAIN_NONATOMIC))
}
internal func setAssociatedCopiedObject<T: AnyObject>(associatedObject: T?, forKey key: UnsafePointer<Void>, inObject object: AnyObject) {
objc_setAssociatedObject(object, key, associatedObject, UInt(OBJC_ASSOCIATION_COPY_NONATOMIC))
}
internal func setAssociatedAssignedObject<T: AnyObject>(associatedObject: T?, forKey key: UnsafePointer<Void>, inObject object: AnyObject) {
objc_setAssociatedObject(object, key, associatedObject, UInt(OBJC_ASSOCIATION_ASSIGN))
}
internal func setAssociatedWeakObject<T: AnyObject>(associatedObject: T?, forKey key: UnsafePointer<Void>, inObject object: AnyObject) {
if let associatedObject = associatedObject {
objc_setAssociatedObject(object, key, WeakObject(associatedObject), UInt(OBJC_ASSOCIATION_RETAIN_NONATOMIC))
}
else {
objc_setAssociatedObject(object, key, nil, UInt(OBJC_ASSOCIATION_RETAIN_NONATOMIC))
}
}
@@ -1,106 +0,0 @@
//
// NSManagedObject+Transaction.swift
// CoreStore
//
// Copyright (c) 2014 John Rommel Estropia
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in all
// copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
// SOFTWARE.
//
import Foundation
import CoreData
// MARK: - NSManagedObject
internal extension NSManagedObject {
// MARK: Internal
internal class func createInContext(context: NSManagedObjectContext) -> Self {
return self(
entity: context.entityDescriptionForEntityClass(self)!,
insertIntoManagedObjectContext: context
)
}
internal class func inContext(context: NSManagedObjectContext, withObjectID objectID: NSManagedObjectID) -> Self? {
return self.typedObjectInContext(context, objectID: objectID)
}
internal func inContext(context: NSManagedObjectContext) -> Self? {
return self.typedObjectInContext(context)
}
internal func deleteFromContext() {
self.managedObjectContext?.deleteObject(self)
}
// MARK: Private
private class func typedObjectInContext<T: NSManagedObject>(context: NSManagedObjectContext, objectID: NSManagedObjectID) -> T? {
var error: NSError?
if let existingObject = context.existingObjectWithID(objectID, error: &error) {
return (existingObject as! T)
}
CoreStore.handleError(
error ?? NSError(coreStoreErrorCode: .UnknownError),
"Failed to load existing \(typeName(self)) in context.")
return nil;
}
private func typedObjectInContext<T: NSManagedObject>(context: NSManagedObjectContext) -> T? {
let objectID = self.objectID
if objectID.temporaryID {
var error: NSError?
let didSucceed = withExtendedLifetime(self.managedObjectContext) {
return $0?.obtainPermanentIDsForObjects([self], error: &error)
}
if didSucceed != true {
CoreStore.handleError(
error ?? NSError(coreStoreErrorCode: .UnknownError),
"Failed to obtain permanent ID for object.")
return nil
}
}
var error: NSError?
if let existingObject = context.existingObjectWithID(objectID, error: &error) {
return (existingObject as! T)
}
CoreStore.handleError(
error ?? NSError(coreStoreErrorCode: .UnknownError),
"Failed to load existing \(typeName(self)) in context.")
return nil;
}
}
@@ -1,330 +0,0 @@
//
// NSManagedObjectContext+Querying.swift
// CoreStore
//
// Copyright (c) 2015 John Rommel Estropia
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in all
// copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
// SOFTWARE.
//
import Foundation
import CoreData
// MARK: - NSManagedObjectContext
internal extension NSManagedObjectContext {
// MARK: Public
internal func fetchOne<T: NSManagedObject>(from: From<T>, _ fetchClauses: FetchClause...) -> T? {
return self.fetchOne(from, fetchClauses)
}
internal func fetchOne<T: NSManagedObject>(from: From<T>, _ fetchClauses: [FetchClause]) -> T? {
let fetchRequest = NSFetchRequest()
from.applyToFetchRequest(fetchRequest, context: self)
fetchRequest.fetchLimit = 1
fetchRequest.resultType = .ManagedObjectResultType
for clause in fetchClauses {
clause.applyToFetchRequest(fetchRequest)
}
var fetchResults: [T]?
var error: NSError?
self.performBlockAndWait {
fetchResults = self.executeFetchRequest(fetchRequest, error: &error) as? [T]
}
if fetchResults == nil {
CoreStore.handleError(
error ?? NSError(coreStoreErrorCode: .UnknownError),
"Failed executing fetch request.")
return nil
}
return fetchResults?.first
}
internal func fetchAll<T: NSManagedObject>(from: From<T>, _ fetchClauses: FetchClause...) -> [T]? {
return self.fetchAll(from, fetchClauses)
}
internal func fetchAll<T: NSManagedObject>(from: From<T>, _ fetchClauses: [FetchClause]) -> [T]? {
let fetchRequest = NSFetchRequest()
from.applyToFetchRequest(fetchRequest, context: self)
fetchRequest.fetchLimit = 0
fetchRequest.resultType = .ManagedObjectResultType
for clause in fetchClauses {
clause.applyToFetchRequest(fetchRequest)
}
var fetchResults: [T]?
var error: NSError?
self.performBlockAndWait {
fetchResults = self.executeFetchRequest(fetchRequest, error: &error) as? [T]
}
if fetchResults == nil {
CoreStore.handleError(
error ?? NSError(coreStoreErrorCode: .UnknownError),
"Failed executing fetch request.")
return nil
}
return fetchResults
}
internal func fetchCount<T: NSManagedObject>(from: From<T>, _ fetchClauses: FetchClause...) -> Int? {
return self.fetchCount(from, fetchClauses)
}
internal func fetchCount<T: NSManagedObject>(from: From<T>, _ fetchClauses: [FetchClause]) -> Int? {
let fetchRequest = NSFetchRequest()
from.applyToFetchRequest(fetchRequest, context: self)
for clause in fetchClauses {
clause.applyToFetchRequest(fetchRequest)
}
var count = 0
var error: NSError?
self.performBlockAndWait {
count = self.countForFetchRequest(fetchRequest, error: &error)
}
if count == NSNotFound {
CoreStore.handleError(
error ?? NSError(coreStoreErrorCode: .UnknownError),
"Failed executing fetch request.")
return nil
}
return count
}
internal func fetchObjectID<T: NSManagedObject>(from: From<T>, _ fetchClauses: FetchClause...) -> NSManagedObjectID? {
return self.fetchObjectID(from, fetchClauses)
}
internal func fetchObjectID<T: NSManagedObject>(from: From<T>, _ fetchClauses: [FetchClause]) -> NSManagedObjectID? {
let fetchRequest = NSFetchRequest()
from.applyToFetchRequest(fetchRequest, context: self)
fetchRequest.fetchLimit = 1
fetchRequest.resultType = .ManagedObjectIDResultType
for clause in fetchClauses {
clause.applyToFetchRequest(fetchRequest)
}
var fetchResults: [NSManagedObjectID]?
var error: NSError?
self.performBlockAndWait {
fetchResults = self.executeFetchRequest(fetchRequest, error: &error) as? [NSManagedObjectID]
}
if fetchResults == nil {
CoreStore.handleError(
error ?? NSError(coreStoreErrorCode: .UnknownError),
"Failed executing fetch request.")
return nil
}
return fetchResults?.first
}
internal func fetchObjectIDs<T: NSManagedObject>(from: From<T>, _ fetchClauses: FetchClause...) -> [NSManagedObjectID]? {
return self.fetchObjectIDs(from, fetchClauses)
}
internal func fetchObjectIDs<T: NSManagedObject>(from: From<T>, _ fetchClauses: [FetchClause]) -> [NSManagedObjectID]? {
let fetchRequest = NSFetchRequest()
from.applyToFetchRequest(fetchRequest, context: self)
fetchRequest.fetchLimit = 0
fetchRequest.resultType = .ManagedObjectIDResultType
for clause in fetchClauses {
clause.applyToFetchRequest(fetchRequest)
}
var fetchResults: [NSManagedObjectID]?
var error: NSError?
self.performBlockAndWait {
fetchResults = self.executeFetchRequest(fetchRequest, error: &error) as? [NSManagedObjectID]
}
if fetchResults == nil {
CoreStore.handleError(
error ?? NSError(coreStoreErrorCode: .UnknownError),
"Failed executing fetch request.")
return nil
}
return fetchResults
}
internal func deleteAll<T: NSManagedObject>(from: From<T>, _ deleteClauses: DeleteClause...) -> Int? {
return self.deleteAll(from, deleteClauses)
}
internal func deleteAll<T: NSManagedObject>(from: From<T>, _ deleteClauses: [DeleteClause]) -> Int? {
let fetchRequest = NSFetchRequest()
from.applyToFetchRequest(fetchRequest, context: self)
fetchRequest.fetchLimit = 0
fetchRequest.resultType = .ManagedObjectResultType
fetchRequest.returnsObjectsAsFaults = true
for clause in deleteClauses {
clause.applyToFetchRequest(fetchRequest)
}
var numberOfDeletedObjects: Int?
var error: NSError?
self.performBlockAndWait {
autoreleasepool {
if let fetchResults = self.executeFetchRequest(fetchRequest, error: &error) as? [T] {
numberOfDeletedObjects = fetchResults.count
for object in fetchResults {
self.deleteObject(object)
}
}
}
}
if numberOfDeletedObjects == nil {
CoreStore.handleError(
error ?? NSError(coreStoreErrorCode: .UnknownError),
"Failed executing fetch request.")
return nil
}
return numberOfDeletedObjects
}
internal func queryValue<T: NSManagedObject, U: SelectValueResultType>(from: From<T>, _ selectClause: Select<U>, _ queryClauses: QueryClause...) -> U? {
return self.queryValue(from, selectClause, queryClauses)
}
internal func queryValue<T: NSManagedObject, U: SelectValueResultType>(from: From<T>, _ selectClause: Select<U>, _ queryClauses: [QueryClause]) -> U? {
let fetchRequest = NSFetchRequest()
from.applyToFetchRequest(fetchRequest, context: self)
fetchRequest.fetchLimit = 0
selectClause.applyToFetchRequest(fetchRequest)
for clause in queryClauses {
clause.applyToFetchRequest(fetchRequest)
}
var fetchResults: [AnyObject]?
var error: NSError?
self.performBlockAndWait {
fetchResults = self.executeFetchRequest(fetchRequest, error: &error)
}
if let fetchResults = fetchResults {
if let rawResult = fetchResults.first as? NSDictionary,
let rawObject: AnyObject = rawResult[selectClause.keyPathForFirstSelectTerm()] {
return Select<U>.ReturnType.fromResultObject(rawObject)
}
return nil
}
CoreStore.handleError(
error ?? NSError(coreStoreErrorCode: .UnknownError),
"Failed executing fetch request.")
return nil
}
internal func queryAttributes<T: NSManagedObject>(from: From<T>, _ selectClause: Select<NSDictionary>, _ queryClauses: QueryClause...) -> [[NSString: AnyObject]]? {
return self.queryAttributes(from, selectClause, queryClauses)
}
internal func queryAttributes<T: NSManagedObject>(from: From<T>, _ selectClause: Select<NSDictionary>, _ queryClauses: [QueryClause]) -> [[NSString: AnyObject]]? {
let fetchRequest = NSFetchRequest()
from.applyToFetchRequest(fetchRequest, context: self)
fetchRequest.fetchLimit = 0
selectClause.applyToFetchRequest(fetchRequest)
for clause in queryClauses {
clause.applyToFetchRequest(fetchRequest)
}
var fetchResults: [AnyObject]?
var error: NSError?
self.performBlockAndWait {
fetchResults = self.executeFetchRequest(fetchRequest, error: &error)
}
if let fetchResults = fetchResults {
return Select<NSDictionary>.ReturnType.fromResultObjects(fetchResults)
}
CoreStore.handleError(
error ?? NSError(coreStoreErrorCode: .UnknownError),
"Failed executing fetch request.")
return nil
}
}
@@ -1,123 +0,0 @@
//
// NSManagedObjectContext+Setup.swift
// CoreStore
//
// Copyright (c) 2015 John Rommel Estropia
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in all
// copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
// SOFTWARE.
//
import Foundation
import CoreData
// MARK: - NSManagedObjectContext
internal extension NSManagedObjectContext {
// MARK: Internal
internal weak var parentStack: DataStack? {
get {
if let parentContext = self.parentContext {
return parentContext.parentStack
}
return getAssociatedObjectForKey(&PropertyKeys.parentStack, inObject: self)
}
set {
if self.parentContext != nil {
return
}
setAssociatedWeakObject(
newValue,
forKey: &PropertyKeys.parentStack,
inObject: self
)
}
}
internal class func rootSavingContextForCoordinator(coordinator: NSPersistentStoreCoordinator) -> NSManagedObjectContext {
let context = NSManagedObjectContext(concurrencyType: .PrivateQueueConcurrencyType)
context.persistentStoreCoordinator = coordinator
context.mergePolicy = NSMergeByPropertyObjectTrumpMergePolicy
context.undoManager = nil
context.setupForCoreStoreWithContextName("com.corestore.rootcontext")
return context
}
internal class func mainContextForRootContext(rootContext: NSManagedObjectContext) -> NSManagedObjectContext {
let context = NSManagedObjectContext(concurrencyType: .MainQueueConcurrencyType)
context.parentContext = rootContext
context.shouldCascadeSavesToParent = true
context.undoManager = nil
context.setupForCoreStoreWithContextName("com.corestore.maincontext")
context.observerForDidSaveNotification = NotificationObserver(
notificationName: NSManagedObjectContextDidSaveNotification,
object: rootContext,
closure: { [weak context] (note) -> Void in
context?.performBlockAndWait { () -> Void in
context?.mergeChangesFromContextDidSaveNotification(note)
}
return
}
)
return context
}
// MARK: Private
private struct PropertyKeys {
static var parentStack: Void?
static var observerForDidSaveNotification: Void?
}
private var observerForDidSaveNotification: NotificationObserver? {
get {
return getAssociatedObjectForKey(
&PropertyKeys.observerForDidSaveNotification,
inObject: self
)
}
set {
setAssociatedRetainedObject(
newValue,
forKey: &PropertyKeys.observerForDidSaveNotification,
inObject: self
)
}
}
}
@@ -1,188 +0,0 @@
//
// NSManagedObjectContext+Transaction.swift
// CoreStore
//
// Copyright (c) 2015 John Rommel Estropia
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in all
// copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
// SOFTWARE.
//
import Foundation
import CoreData
import GCDKit
// MARK: - NSManagedObjectContext
internal extension NSManagedObjectContext {
// MARK: Internal
internal weak var parentTransaction: BaseDataTransaction? {
get {
return getAssociatedObjectForKey(
&PropertyKeys.parentTransaction,
inObject: self
)
}
set {
setAssociatedWeakObject(
newValue,
forKey: &PropertyKeys.parentTransaction,
inObject: self
)
}
}
internal func temporaryContextInTransactionWithConcurrencyType(concurrencyType: NSManagedObjectContextConcurrencyType) -> NSManagedObjectContext {
let context = NSManagedObjectContext(concurrencyType: concurrencyType)
context.parentContext = self
context.parentStack = self.parentStack
context.setupForCoreStoreWithContextName("com.corestore.temporarycontext")
context.shouldCascadeSavesToParent = (self.parentStack?.rootSavingContext == self)
context.retainsRegisteredObjects = true
return context
}
internal func saveSynchronously() -> SaveResult {
var result = SaveResult(hasChanges: false)
self.performBlockAndWait {
[unowned self] () -> Void in
if !self.hasChanges {
return
}
var saveError: NSError?
if self.save(&saveError) {
if self.shouldCascadeSavesToParent {
if let parentContext = self.parentContext {
switch parentContext.saveSynchronously() {
case .Success(let hasChanges):
result = SaveResult(hasChanges: true)
case .Failure(let error):
result = SaveResult(error)
}
return
}
}
result = SaveResult(hasChanges: true)
}
else if let error = saveError {
CoreStore.handleError(
error,
"Failed to save <\(NSManagedObjectContext.self)>.")
result = SaveResult(error)
}
else {
result = SaveResult(hasChanges: false)
}
}
return result
}
internal func saveAsynchronouslyWithCompletion(completion: ((result: SaveResult) -> Void)?) {
self.performBlock { () -> Void in
if !self.hasChanges {
if let completion = completion {
GCDQueue.Main.async {
completion(result: SaveResult(hasChanges: false))
}
}
return
}
var saveError: NSError?
if self.save(&saveError) {
if self.shouldCascadeSavesToParent {
if let parentContext = self.parentContext {
let result = parentContext.saveSynchronously()
if let completion = completion {
GCDQueue.Main.async {
completion(result: result)
}
}
return
}
}
if let completion = completion {
GCDQueue.Main.async {
completion(result: SaveResult(hasChanges: true))
}
}
}
else if let error = saveError {
CoreStore.handleError(
error,
"Failed to save <\(NSManagedObjectContext.self)>.")
if let completion = completion {
GCDQueue.Main.async {
completion(result: SaveResult(error))
}
}
}
else if let completion = completion {
GCDQueue.Main.async {
completion(result: SaveResult(hasChanges: false))
}
}
}
}
// MARK: Private
private struct PropertyKeys {
static var parentTransaction: Void?
}
}
-90
View File
@@ -1,90 +0,0 @@
//
// CoreStoreLogger.swift
// CoreStore
//
// Copyright (c) 2015 John Rommel Estropia
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in all
// copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
// SOFTWARE.
//
import Foundation
// MARK: - LogLevel
/**
The `LogLevel` indicates the severity of a log message.
*/
public enum LogLevel {
case Trace
case Notice
case Warning
case Fatal
}
// MARK: - CoreStoreLogger
/**
Custom loggers should implement the `CoreStoreLogger` protocol and pass its instance to `CoreStore.logger`. Calls to `log(...)`, `handleError(...)`, and `assert(...)` are not tied to a specific queue/thread, so it is the implementer's job to handle thread-safety.
*/
public protocol CoreStoreLogger {
/**
Handles log messages sent by the `CoreStore` framework.
:level: the severity of the log message
:message: the log message
:fileName: the source file name
:lineNumber: the source line number
:functionName: the source function name
*/
func log(#level: LogLevel, message: String, fileName: StaticString, lineNumber: Int, functionName: StaticString)
/**
Handles errors sent by the `CoreStore` framework.
:error: the error
:message: the error message
:fileName: the source file name
:lineNumber: the source line number
:functionName: the source function name
*/
func handleError(#error: NSError, message: String, fileName: StaticString, lineNumber: Int, functionName: StaticString)
/**
Handles assertions made throughout the `CoreStore` framework.
:condition: the assertion condition
:message: the assertion message
:fileName: the source file name
:lineNumber: the source line number
:functionName: the source function name
*/
func assert(@autoclosure condition: () -> Bool, message: String, fileName: StaticString, lineNumber: Int, functionName: StaticString)
}
// MARK: - Utilities
internal func typeName<T>(value: T) -> String {
return "<\(_stdlib_getDemangledTypeName(value))>"
}
-69
View File
@@ -1,69 +0,0 @@
//
// DefaultLogger.swift
// CoreStore
//
// Copyright (c) 2015 John Rommel Estropia
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in all
// copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
// SOFTWARE.
//
import Foundation
// MARK: - DefaultLogger
/**
The `DefaultLogger` is a basic implementation of the `CoreStoreLogger` protocol.
- The `log(...)` method calls `println(...)` to print the level, source file name, line number, function name, and the log message.
- The `handleError(...)` method calls `println(...)` to print the source file name, line number, function name, and the error message.
- The `assert(...)` method calls `assert(...)` on the arguments.
*/
public final class DefaultLogger: CoreStoreLogger {
public init() { }
public func log(#level: LogLevel, message: String, fileName: StaticString, lineNumber: Int, functionName: StaticString) {
#if DEBUG
let levelString: String
switch level {
case .Trace: levelString = "Trace"
case .Notice: levelString = "Notice"
case .Warning: levelString = "Warning"
case .Fatal: levelString = "Fatal"
}
Swift.println("[CoreStore:\(levelString)] \(fileName.stringValue.lastPathComponent):\(lineNumber) \(functionName)\n ↪︎ \(message)\n")
#endif
}
public func handleError(#error: NSError, message: String, fileName: StaticString, lineNumber: Int, functionName: StaticString) {
#if DEBUG
Swift.println("[CoreStore:Error] \(fileName.stringValue.lastPathComponent):\(lineNumber) \(functionName)\n ↪︎ \(message): \(error)\n")
#endif
}
public func assert(@autoclosure condition: () -> Bool, message: String, fileName: StaticString, lineNumber: Int, functionName: StaticString) {
#if DEBUG
Swift.assert(condition, message, file: fileName, line: numericCast(lineNumber))
#endif
}
}
@@ -1,357 +0,0 @@
//
// DataStack+Migration.swift
// CoreStore
//
// Copyright (c) 2015 John Rommel Estropia
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in all
// copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
// SOFTWARE.
//
import Foundation
import CoreData
import GCDKit
// MARK: - DataStack
public extension DataStack {
// MARK: Public
/**
Initializes a `DataStack` from the specified model name and a version-specific model name.
:param: rootModelName the name of the (.xcdatamodeld) model file
:param: versionModelName the name of the version-specific (.xcdatamodeld) model file
*/
public convenience init(rootModelName: String, versionModelName: String) {
let modelVersionURL: NSURL! = NSBundle.mainBundle().URLForResource(
rootModelName.stringByAppendingPathExtension("momd")!.stringByAppendingPathComponent(versionModelName),
withExtension: "mom"
)
CoreStore.assert(modelVersionURL != nil, "Could not find a \"mom\" resource from the main bundle.")
let managedObjectModel: NSManagedObjectModel! = NSManagedObjectModel(contentsOfURL: modelVersionURL)
CoreStore.assert(managedObjectModel != nil, "Could not create an <\(NSManagedObjectModel.self)> from the resource at URL \"\(modelVersionURL)\".")
self.init(managedObjectModel: managedObjectModel)
}
/**
Checks if the store at the specified filename and configuration needs to be migrated to the `DataStack`'s managed object model version.
:param: fileName the local filename for the SQLite persistent store in the "Application Support" directory.
:param: configuration an optional configuration name from the model file. If not specified, defaults to `nil`, the "Default" configuration.
*/
public func needsMigrationForSQLiteStore(fileName: String, configuration: String? = nil) -> Bool? {
return needsMigrationForSQLiteStore(
fileURL: applicationSupportDirectory.URLByAppendingPathComponent(
fileName,
isDirectory: false
),
configuration: configuration
)
}
/**
Checks if the store at the specified file URL and configuration needs to be migrated to the `DataStack`'s managed object model version.
:param: fileName the local filename for the SQLite persistent store in the "Application Support" directory.
:param: configuration an optional configuration name from the model file. If not specified, defaults to `nil`, the "Default" configuration.
*/
public func needsMigrationForSQLiteStore(fileURL: NSURL = defaultSQLiteStoreURL, configuration: String? = nil) -> Bool? {
var error: NSError?
let metadata = NSPersistentStoreCoordinator.metadataForPersistentStoreOfType(
NSSQLiteStoreType,
URL: fileURL,
error: &error
)
if metadata == nil {
CoreStore.handleError(
error ?? NSError(coreStoreErrorCode: .UnknownError),
"Failed to add SQLite <\(NSPersistentStore.self)> at \"\(fileURL)\".")
return nil
}
return !self.coordinator.managedObjectModel.isConfiguration(
configuration,
compatibleWithStoreMetadata: metadata
)
}
/**
EXPERIMENTAL
*/
private func upgradeSQLiteStoreIfNeeded(fileName: String, configuration: String? = nil, completion: (PersistentStoreResult) -> Void) {
self.upgradeSQLiteStoreIfNeeded(
fileURL: applicationSupportDirectory.URLByAppendingPathComponent(
fileName,
isDirectory: false
),
configuration: configuration,
completion: completion
)
}
/**
EXPERIMENTAL
*/
private func upgradeSQLiteStoreIfNeeded(fileURL: NSURL = defaultSQLiteStoreURL, configuration: String? = nil, completion: (PersistentStoreResult) -> Void) {
var metadataError: NSError?
let metadata: [NSObject: AnyObject]! = NSPersistentStoreCoordinator.metadataForPersistentStoreOfType(
NSSQLiteStoreType,
URL: fileURL,
error: &metadataError
)
if metadata == nil {
CoreStore.handleError(
metadataError ?? NSError(coreStoreErrorCode: .UnknownError),
"Failed to load SQLite <\(NSPersistentStore.self)> metadata at \"\(fileURL)\".")
GCDQueue.Main.async {
// TODO: inspect valid errors for metadataForPersistentStoreOfType()
completion(PersistentStoreResult(.PersistentStoreNotFound))
}
return
}
let coordinator = self.coordinator;
if let store = coordinator.persistentStoreForURL(fileURL) {
let isExistingStoreAutomigrating = ((store.options?[NSMigratePersistentStoresAutomaticallyOption] as? Bool) ?? false)
if store.type == NSSQLiteStoreType
&& isExistingStoreAutomigrating
&& store.configurationName == (configuration ?? Into.defaultConfigurationName) {
GCDQueue.Main.async {
completion(PersistentStoreResult(store))
}
return
}
CoreStore.handleError(
NSError(coreStoreErrorCode: .DifferentPersistentStoreExistsAtURL),
"Failed to add SQLite <\(NSPersistentStore.self)> at \"\(fileURL)\" because a different <\(NSPersistentStore.self)> at that URL already exists.")
GCDQueue.Main.async {
completion(PersistentStoreResult(.DifferentPersistentStoreExistsAtURL))
}
return
}
let managedObjectModel = self.coordinator.managedObjectModel
let migrationManager = NSMigrationManager(
sourceModel: NSManagedObjectModel(
byMergingModels: [managedObjectModel],
forStoreMetadata: metadata!
)!,
destinationModel: managedObjectModel
)
var mappingModel: NSMappingModel! = NSMappingModel(
fromBundles: nil, // TODO: parametize
forSourceModel: migrationManager.sourceModel,
destinationModel: migrationManager.destinationModel
)
var modelError: NSError?
if mappingModel == nil {
mappingModel = NSMappingModel.inferredMappingModelForSourceModel(
migrationManager.sourceModel,
destinationModel: migrationManager.destinationModel,
error: &modelError
)
}
if mappingModel == nil {
CoreStore.handleError(
NSError(coreStoreErrorCode: .UnknownError),
"Failed to load an <\(NSMappingModel.self)> for migration from version model \"\(migrationManager.sourceModel)\" to version model \"\(migrationManager.destinationModel)\".")
GCDQueue.Main.async {
completion(PersistentStoreResult(.MappingModelNotFound))
}
return
}
let temporaryFileURL = NSURL(fileURLWithPath: NSTemporaryDirectory(), isDirectory: true)!.URLByAppendingPathComponent(NSProcessInfo().globallyUniqueString)
var migrationError: NSError?
if !migrationManager.migrateStoreFromURL(
fileURL,
type: NSSQLiteStoreType,
options: nil,
withMappingModel: mappingModel,
toDestinationURL: temporaryFileURL,
destinationType: NSSQLiteStoreType,
destinationOptions: nil,
error: &migrationError
) {
CoreStore.handleError(
migrationError ?? NSError(coreStoreErrorCode: .UnknownError),
"Failed to prepare for migration from version model \"\(migrationManager.sourceModel)\" to version model \"\(migrationManager.destinationModel)\".")
GCDQueue.Main.async {
completion(PersistentStoreResult(.MigrationFailed))
}
return
}
}
/**
Asynchronously adds to the stack an SQLite store from the given SQLite file name. Note that using `addSQLiteStore(...)` instead of `addSQLiteStoreAndWait(...)` implies that the migrations are allowed and expected (thus the asynchronous `completion`.)
:param: fileName the local filename for the SQLite persistent store in the "Application Support" directory. A new SQLite file will be created if it does not exist. Note that if you have multiple configurations, you will need to specify a different `fileName` explicitly for each of them.
:param: configuration an optional configuration name from the model file. If not specified, defaults to `nil`, the "Default" configuration. Note that if you have multiple configurations, you will need to specify a different `fileName` explicitly for each of them.
:param: completion the closure to be executed on the main queue when the process completes, either due to success or failure. The closure's `PersistentStoreResult` argument indicates the result.
*/
public func addSQLiteStore(fileName: String, configuration: String? = nil, completion: (PersistentStoreResult) -> Void) {
self.addSQLiteStore(
fileURL: applicationSupportDirectory.URLByAppendingPathComponent(
fileName,
isDirectory: false
),
configuration: configuration,
completion: completion
)
}
/**
Asynchronously adds to the stack an SQLite store from the given SQLite file URL. Note that using `addSQLiteStore(...)` instead of `addSQLiteStoreAndWait(...)` implies that the migrations are allowed and expected (thus the asynchronous `completion`.)
:param: fileURL the local file URL for the SQLite persistent store. A new SQLite file will be created if it does not exist. If not specified, defaults to a file URL pointing to a "<Application name>.sqlite" file in the "Application Support" directory. Note that if you have multiple configurations, you will need to specify a different `fileURL` explicitly for each of them.
:param: configuration an optional configuration name from the model file. If not specified, defaults to `nil`, the "Default" configuration. Note that if you have multiple configurations, you will need to specify a different `fileURL` explicitly for each of them.
:param: completion the closure to be executed on the main queue when the process completes, either due to success or failure. The closure's `PersistentStoreResult` argument indicates the result.
*/
public func addSQLiteStore(fileURL: NSURL = defaultSQLiteStoreURL, configuration: String? = nil, completion: (PersistentStoreResult) -> Void) {
var error: NSError?
let metadata = NSPersistentStoreCoordinator.metadataForPersistentStoreOfType(
NSSQLiteStoreType,
URL: fileURL,
error: &error
)
if metadata == nil {
CoreStore.handleError(
error ?? NSError(coreStoreErrorCode: .UnknownError),
"Failed to load SQLite <\(NSPersistentStore.self)> metadata at \"\(fileURL)\".")
GCDQueue.Main.async {
completion(PersistentStoreResult(.UnknownError))
}
return
}
let coordinator = self.coordinator;
if let store = coordinator.persistentStoreForURL(fileURL) {
let isExistingStoreAutomigrating = ((store.options?[NSMigratePersistentStoresAutomaticallyOption] as? Bool) ?? false)
if store.type == NSSQLiteStoreType
&& isExistingStoreAutomigrating
&& store.configurationName == (configuration ?? Into.defaultConfigurationName) {
GCDQueue.Main.async {
completion(PersistentStoreResult(store))
}
return
}
CoreStore.handleError(
NSError(coreStoreErrorCode: .DifferentPersistentStoreExistsAtURL),
"Failed to add SQLite <\(NSPersistentStore.self)> at \"\(fileURL)\" because a different <\(NSPersistentStore.self)> at that URL already exists.")
GCDQueue.Main.async {
completion(PersistentStoreResult(.DifferentPersistentStoreExistsAtURL))
}
return
}
let fileManager = NSFileManager.defaultManager()
var directoryError: NSError?
if !fileManager.createDirectoryAtURL(
fileURL.URLByDeletingLastPathComponent!,
withIntermediateDirectories: true,
attributes: nil,
error: &directoryError) {
CoreStore.handleError(
directoryError ?? NSError(coreStoreErrorCode: .UnknownError),
"Failed to create directory for SQLite store at \"\(fileURL)\".")
GCDQueue.Main.async {
completion(PersistentStoreResult(directoryError!))
}
return
}
coordinator.performBlock {
var persistentStoreError: NSError?
let store = coordinator.addPersistentStoreWithType(
NSSQLiteStoreType,
configuration: configuration,
URL: fileURL,
options: [NSSQLitePragmasOption: ["WAL": "journal_mode"],
NSInferMappingModelAutomaticallyOption: true,
NSMigratePersistentStoresAutomaticallyOption: true],
error: &persistentStoreError)
if let store = store {
GCDQueue.Main.async {
self.updateMetadataForPersistentStore(store)
completion(PersistentStoreResult(store))
}
}
else {
GCDQueue.Main.async {
CoreStore.handleError(
persistentStoreError ?? NSError(coreStoreErrorCode: .UnknownError),
"Failed to add SQLite <\(NSPersistentStore.self)> at \"\(fileURL)\".")
completion(PersistentStoreResult(.UnknownError))
}
}
}
}
}
-94
View File
@@ -1,94 +0,0 @@
//
// NSError+CoreStore.swift
// CoreStore
//
// Copyright (c) 2014 John Rommel Estropia
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in all
// copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
// SOFTWARE.
//
import Foundation
/**
The `NSError` error domain for `CoreStore`.
*/
public let CoreStoreErrorDomain = "com.corestore.error"
/**
The `NSError` error codes for `CoreStoreErrorDomain`.
*/
public enum CoreStoreErrorCode: Int {
/**
A failure occured because of an unknown error.
*/
case UnknownError
/**
The `NSPersistentStore` could note be initialized because another store existed at the specified `NSURL`.
*/
case DifferentPersistentStoreExistsAtURL
/**
The `NSPersistentStore` specified could not be found.
*/
case PersistentStoreNotFound
/**
An `NSMappingModel` could not be found for a specific source and destination model versions.
*/
case MappingModelNotFound
/**
An `NSMigrationManager` prepared to migrate the store.
*/
case MigrationFailed
}
// MARK: - NSError+CoreStore
public extension NSError {
/**
If the error's domain is equal to `CoreStoreErrorDomain`, returns the associated `CoreStoreErrorCode`. For other domains, returns `nil`.
*/
public var coreStoreErrorCode: CoreStoreErrorCode? {
return (self.domain == CoreStoreErrorDomain
? CoreStoreErrorCode(rawValue: self.code)
: nil)
}
// MARK: Internal
internal convenience init(coreStoreErrorCode: CoreStoreErrorCode) {
self.init(coreStoreErrorCode: coreStoreErrorCode, userInfo: nil)
}
internal convenience init(coreStoreErrorCode: CoreStoreErrorCode, userInfo: [NSObject: AnyObject]?) {
self.init(
domain: CoreStoreErrorDomain,
code: coreStoreErrorCode.rawValue,
userInfo: userInfo)
}
}
@@ -1,96 +0,0 @@
//
// CoreStore+Observing.swift
// CoreStore
//
// Copyright (c) 2015 John Rommel Estropia
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in all
// copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
// SOFTWARE.
//
import Foundation
import CoreData
// MARK: - CoreStore
public extension CoreStore {
// MARK: Public
/**
Using the `defaultStack`, creates a `ManagedObjectController` for the specified `NSManagedObject`. Multiple `ManagedObjectObserver`'s may then register themselves to be notified when changes are made to the `NSManagedObject`.
:param: object the `NSManagedObject` to observe changes from
:returns: a `ManagedObjectController` that monitors changes to `object`
*/
public static func observeObject<T: NSManagedObject>(object: T) -> ManagedObjectController<T> {
return self.defaultStack.observeObject(object)
}
/**
Using the `defaultStack`, creates a `ManagedObjectListController` for a list of `NSManagedObject`'s that satisfy the specified fetch clauses. Multiple `ManagedObjectListObserver`'s may then register themselves to be notified when changes are made to the list.
:param: from a `From` clause indicating the entity type
:param: fetchClauses a series of `FetchClause` instances for fetching the object list. Accepts `Where`, `OrderBy`, and `Tweak` clauses.
:returns: a `ManagedObjectListController` instance that monitors changes to the list
*/
public static func observeObjectList<T: NSManagedObject>(from: From<T>, _ groupBy: GroupBy? = nil, _ queryClauses: FetchClause...) -> ManagedObjectListController<T> {
return self.defaultStack.observeObjectList(from, queryClauses)
}
/**
Using the `defaultStack`, creates a `ManagedObjectListController` for a list of `NSManagedObject`'s that satisfy the specified fetch clauses. Multiple `ManagedObjectListObserver`'s may then register themselves to be notified when changes are made to the list.
:param: from a `From` clause indicating the entity type
:param: fetchClauses a series of `FetchClause` instances for fetching the object list. Accepts `Where`, `OrderBy`, and `Tweak` clauses.
:returns: a `ManagedObjectListController` instance that monitors changes to the list
*/
public static func observeObjectList<T: NSManagedObject>(from: From<T>, _ groupBy: GroupBy? = nil, _ queryClauses: [FetchClause]) -> ManagedObjectListController<T> {
return self.defaultStack.observeObjectList(from, queryClauses)
}
/**
Using the `defaultStack`, creates a `ManagedObjectListController` for a sectioned list of `NSManagedObject`'s that satisfy the specified fetch clauses. Multiple `ManagedObjectListObserver`'s may then register themselves to be notified when changes are made to the list.
:param: from a `From` clause indicating the entity type
:param: sectionedBy a `SectionedBy` clause indicating the keyPath for the attribute to use when sorting the list into sections.
:param: fetchClauses a series of `FetchClause` instances for fetching the object list. Accepts `Where`, `OrderBy`, and `Tweak` clauses.
:returns: a `ManagedObjectListController` instance that monitors changes to the list
*/
public static func observeSectionedList<T: NSManagedObject>(from: From<T>, _ sectionedBy: SectionedBy, _ fetchClauses: FetchClause...) -> ManagedObjectListController<T> {
return self.defaultStack.observeSectionedList(from, sectionedBy, fetchClauses)
}
/**
Using the `defaultStack`, creates a `ManagedObjectListController` for a sectioned list of `NSManagedObject`'s that satisfy the specified fetch clauses. Multiple `ManagedObjectListObserver`'s may then register themselves to be notified when changes are made to the list.
:param: from a `From` clause indicating the entity type
:param: sectionedBy a `SectionedBy` clause indicating the keyPath for the attribute to use when sorting the list into sections.
:param: fetchClauses a series of `FetchClause` instances for fetching the object list. Accepts `Where`, `OrderBy`, and `Tweak` clauses.
:returns: a `ManagedObjectListController` instance that monitors changes to the list
*/
public static func observeSectionedList<T: NSManagedObject>(from: From<T>, _ sectionedBy: SectionedBy, _ fetchClauses: [FetchClause]) -> ManagedObjectListController<T> {
return self.defaultStack.observeSectionedList(from, sectionedBy, fetchClauses)
}
}
@@ -1,116 +0,0 @@
//
// DataStack+Observing.swift
// CoreStore
//
// Copyright (c) 2015 John Rommel Estropia
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in all
// copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
// SOFTWARE.
//
import Foundation
import CoreData
import GCDKit
// MARK: - DataStack
public extension DataStack {
// MARK: Public
/**
Creates a `ManagedObjectController` for the specified `NSManagedObject`. Multiple `ManagedObjectObserver`'s may then register themselves to be notified when changes are made to the `NSManagedObject`.
:param: object the `NSManagedObject` to observe changes from
:returns: a `ManagedObjectController` that monitors changes to `object`
*/
public func observeObject<T: NSManagedObject>(object: T) -> ManagedObjectController<T> {
CoreStore.assert(NSThread.isMainThread(), "Attempted to observe objects from \(typeName(self)) outside the main thread.")
return ManagedObjectController(
dataStack: self,
object: object
)
}
/**
Creates a `ManagedObjectListController` for a list of `NSManagedObject`'s that satisfy the specified fetch clauses. Multiple `ManagedObjectListObserver`'s may then register themselves to be notified when changes are made to the list.
:param: from a `From` clause indicating the entity type
:param: fetchClauses a series of `FetchClause` instances for fetching the object list. Accepts `Where`, `OrderBy`, and `Tweak` clauses.
:returns: a `ManagedObjectListController` instance that monitors changes to the list
*/
public func observeObjectList<T: NSManagedObject>(from: From<T>, _ fetchClauses: FetchClause...) -> ManagedObjectListController<T> {
return self.observeObjectList(from, fetchClauses)
}
/**
Creates a `ManagedObjectListController` for a list of `NSManagedObject`'s that satisfy the specified fetch clauses. Multiple `ManagedObjectListObserver`'s may then register themselves to be notified when changes are made to the list.
:param: from a `From` clause indicating the entity type
:param: fetchClauses a series of `FetchClause` instances for fetching the object list. Accepts `Where`, `OrderBy`, and `Tweak` clauses.
:returns: a `ManagedObjectListController` instance that monitors changes to the list
*/
public func observeObjectList<T: NSManagedObject>(from: From<T>, _ fetchClauses: [FetchClause]) -> ManagedObjectListController<T> {
CoreStore.assert(NSThread.isMainThread(), "Attempted to observe objects from \(typeName(self)) outside the main thread.")
return ManagedObjectListController(
dataStack: self,
from: from,
sectionedBy: nil,
fetchClauses: fetchClauses
)
}
/**
Creates a `ManagedObjectListController` for a sectioned list of `NSManagedObject`'s that satisfy the specified fetch clauses. Multiple `ManagedObjectListObserver`'s may then register themselves to be notified when changes are made to the list.
:param: from a `From` clause indicating the entity type
:param: sectionedBy a `SectionedBy` clause indicating the keyPath for the attribute to use when sorting the list into sections.
:param: fetchClauses a series of `FetchClause` instances for fetching the object list. Accepts `Where`, `OrderBy`, and `Tweak` clauses.
:returns: a `ManagedObjectListController` instance that monitors changes to the list
*/
public func observeSectionedList<T: NSManagedObject>(from: From<T>, _ sectionedBy: SectionedBy, _ fetchClauses: FetchClause...) -> ManagedObjectListController<T> {
return self.observeSectionedList(from, sectionedBy, fetchClauses)
}
/**
Creates a `ManagedObjectListController` for a sectioned list of `NSManagedObject`'s that satisfy the specified fetch clauses. Multiple `ManagedObjectListObserver`'s may then register themselves to be notified when changes are made to the list.
:param: from a `From` clause indicating the entity type
:param: sectionedBy a `SectionedBy` clause indicating the keyPath for the attribute to use when sorting the list into sections.
:param: fetchClauses a series of `FetchClause` instances for fetching the object list. Accepts `Where`, `OrderBy`, and `Tweak` clauses.
:returns: a `ManagedObjectListController` instance that monitors changes to the list
*/
public func observeSectionedList<T: NSManagedObject>(from: From<T>, _ sectionedBy: SectionedBy, _ fetchClauses: [FetchClause]) -> ManagedObjectListController<T> {
CoreStore.assert(NSThread.isMainThread(), "Attempted to observe objects from \(typeName(self)) outside the main thread.")
return ManagedObjectListController(
dataStack: self,
from: from,
sectionedBy: sectionedBy,
fetchClauses: fetchClauses
)
}
}
@@ -1,346 +0,0 @@
//
// ManagedObjectController.swift
// CoreStore
//
// Copyright (c) 2015 John Rommel Estropia
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in all
// copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
// SOFTWARE.
//
import Foundation
import CoreData
import GCDKit
private let ManagedObjectListControllerWillChangeObjectNotification = "ManagedObjectListControllerWillChangeObjectNotification"
private let ManagedObjectListControllerDidDeleteObjectNotification = "ManagedObjectListControllerDidDeleteObjectNotification"
private let ManagedObjectListControllerDidUpdateObjectNotification = "ManagedObjectListControllerDidUpdateObjectNotification"
private let UserInfoKeyObject = "UserInfoKeyObject"
private struct NotificationKey {
static var willChangeObject: Void?
static var didDeleteObject: Void?
static var didUpdateObject: Void?
}
// MARK: - ManagedObjectController
/**
The `ManagedObjectController` monitors changes to a single `NSManagedObject` instance. Observers that implement the `ManagedObjectObserver` protocol may then register themselves to the `ManagedObjectController`'s `addObserver(_:)` method:
let objectController = CoreStore.observeObject(object)
objectController.addObserver(self)
The created `ManagedObjectController` instance needs to be held on (retained) for as long as the object needs to be observed.
Observers registered via `addObserver(_:)` are not retained. `ManagedObjectController` only keeps a `weak` reference to all observers, thus keeping itself free from retain-cycles.
*/
public final class ManagedObjectController<T: NSManagedObject> {
// MARK: Public
/**
Returns the `NSManagedObject` instance being observed, or `nil` if the object was already deleted.
*/
public var object: T? {
return self.fetchedResultsController.fetchedObjects?.first as? T
}
/**
Returns `true` if the `NSManagedObject` instance being observed still exists, or `false` if the object was already deleted.
*/
public var isObjectDeleted: Bool {
return self.object?.managedObjectContext == nil
}
/**
Registers a `ManagedObjectObserver` to be notified when changes to the receiver's `object` are made.
To prevent retain-cycles, `ManagedObjectController` only keeps `weak` references to its observers.
For thread safety, this method needs to be called from the main thread. An assertion failure will occur (on debug builds only) if called from any thread other than the main thread.
Calling `addObserver(_:)` multiple times on the same observer is safe, as `ManagedObjectController` unregisters previous notifications to the observer before re-registering them.
:param: observer a `ManagedObjectObserver` to send change notifications to
*/
public func addObserver<U: ManagedObjectObserver where U.EntityType == T>(observer: U) {
CoreStore.assert(NSThread.isMainThread(), "Attempted to add an observer of type \(typeName(observer)) outside the main thread.")
self.removeObserver(observer)
self.registerChangeNotification(
&NotificationKey.willChangeObject,
name: ManagedObjectListControllerWillChangeObjectNotification,
toObserver: observer,
callback: { [weak self, weak observer] (objectController) -> Void in
if let strongSelf = self, let object = strongSelf.object, let observer = observer {
observer.managedObjectWillUpdate(objectController, object: object)
}
}
)
self.registerObjectNotification(
&NotificationKey.didDeleteObject,
name: ManagedObjectListControllerDidDeleteObjectNotification,
toObserver: observer,
callback: { [weak self, weak observer] (objectController, object) -> Void in
if let strongSelf = self, let observer = observer {
observer.managedObjectWasDeleted(objectController, object: object)
}
}
)
self.registerObjectNotification(
&NotificationKey.didUpdateObject,
name: ManagedObjectListControllerDidUpdateObjectNotification,
toObserver: observer,
callback: { [weak self, weak observer] (objectController, object) -> Void in
if let strongSelf = self, let observer = observer {
let previousCommitedAttributes = strongSelf.lastCommittedAttributes
let currentCommitedAttributes = object.committedValuesForKeys(nil) as! [NSString: NSObject]
var changedKeys = Set<String>()
for key in currentCommitedAttributes.keys {
if previousCommitedAttributes[key] != currentCommitedAttributes[key] {
changedKeys.insert(key as String)
}
}
strongSelf.lastCommittedAttributes = currentCommitedAttributes
observer.managedObjectWasUpdated(
objectController,
object: object,
changedPersistentKeys: changedKeys
)
}
}
)
}
/**
Unregisters a `ManagedObjectObserver` from receiving notifications for changes to the receiver's `object`.
For thread safety, this method needs to be called from the main thread. An assertion failure will occur (on debug builds only) if called from any thread other than the main thread.
:param: observer a `ManagedObjectObserver` to unregister notifications to
*/
public func removeObserver<U: ManagedObjectObserver where U.EntityType == T>(observer: U) {
CoreStore.assert(NSThread.isMainThread(), "Attempted to remove an observer of type \(typeName(observer)) outside the main thread.")
let nilValue: AnyObject? = nil
setAssociatedRetainedObject(nilValue, forKey: &NotificationKey.willChangeObject, inObject: observer)
setAssociatedRetainedObject(nilValue, forKey: &NotificationKey.didDeleteObject, inObject: observer)
setAssociatedRetainedObject(nilValue, forKey: &NotificationKey.didUpdateObject, inObject: observer)
}
// MARK: Internal
internal init(dataStack: DataStack, object: T) {
let context = dataStack.mainContext
let fetchRequest = NSFetchRequest()
fetchRequest.entity = context.entityDescriptionForEntityClass(T.self)
fetchRequest.fetchLimit = 1
fetchRequest.resultType = .ManagedObjectResultType
fetchRequest.sortDescriptors = []
let originalObjectID = object.objectID
Where("SELF", isEqualTo: originalObjectID).applyToFetchRequest(fetchRequest)
let fetchedResultsController = NSFetchedResultsController(
fetchRequest: fetchRequest,
managedObjectContext: context,
sectionNameKeyPath: nil,
cacheName: nil
)
let fetchedResultsControllerDelegate = FetchedResultsControllerDelegate()
self.originalObjectID = originalObjectID
self.fetchedResultsController = fetchedResultsController
self.fetchedResultsControllerDelegate = fetchedResultsControllerDelegate
self.parentStack = dataStack
fetchedResultsControllerDelegate.handler = self
fetchedResultsControllerDelegate.fetchedResultsController = fetchedResultsController
var error: NSError?
if !fetchedResultsController.performFetch(&error) {
CoreStore.handleError(
error ?? NSError(coreStoreErrorCode: .UnknownError),
"Failed to perform fetch on <\(NSFetchedResultsController.self)>.")
}
self.lastCommittedAttributes = (self.object?.committedValuesForKeys(nil) as? [NSString: NSObject]) ?? [:]
}
// MARK: Private
private let originalObjectID: NSManagedObjectID
private let fetchedResultsController: NSFetchedResultsController
private let fetchedResultsControllerDelegate: FetchedResultsControllerDelegate
private var lastCommittedAttributes = [NSString: NSObject]()
private weak var parentStack: DataStack?
private func registerChangeNotification(notificationKey: UnsafePointer<Void>, name: String, toObserver observer: AnyObject, callback: (objectController: ManagedObjectController<T>) -> Void) {
setAssociatedRetainedObject(
NotificationObserver(
notificationName: name,
object: self,
closure: { [weak self] (note) -> Void in
if let strongSelf = self {
callback(objectController: strongSelf)
}
}
),
forKey: notificationKey,
inObject: observer
)
}
private func registerObjectNotification(notificationKey: UnsafePointer<Void>, name: String, toObserver observer: AnyObject, callback: (objectController: ManagedObjectController<T>, object: T) -> Void) {
setAssociatedRetainedObject(
NotificationObserver(
notificationName: name,
object: self,
closure: { [weak self] (note) -> Void in
if let strongSelf = self,
let userInfo = note.userInfo,
let object = userInfo[UserInfoKeyObject] as? T {
callback(
objectController: strongSelf,
object: object
)
}
}
),
forKey: notificationKey,
inObject: observer
)
}
}
// MARK: - ManagedObjectController: FetchedResultsControllerHandler
extension ManagedObjectController: FetchedResultsControllerHandler {
// MARK: FetchedResultsControllerHandler
private func controller(controller: NSFetchedResultsController, didChangeObject anObject: AnyObject, atIndexPath indexPath: NSIndexPath?, forChangeType type: NSFetchedResultsChangeType, newIndexPath: NSIndexPath?) {
switch type {
case .Delete:
NSNotificationCenter.defaultCenter().postNotificationName(
ManagedObjectListControllerDidDeleteObjectNotification,
object: self,
userInfo: [UserInfoKeyObject: anObject]
)
case .Update:
NSNotificationCenter.defaultCenter().postNotificationName(
ManagedObjectListControllerDidUpdateObjectNotification,
object: self,
userInfo: [UserInfoKeyObject: anObject]
)
default:
break
}
}
private func controllerWillChangeContent(controller: NSFetchedResultsController) {
NSNotificationCenter.defaultCenter().postNotificationName(
ManagedObjectListControllerWillChangeObjectNotification,
object: self
)
}
}
// MARK: - FetchedResultsControllerHandler
private protocol FetchedResultsControllerHandler: class {
func controller(controller: NSFetchedResultsController, didChangeObject anObject: AnyObject, atIndexPath indexPath: NSIndexPath?, forChangeType type: NSFetchedResultsChangeType, newIndexPath: NSIndexPath?)
func controllerWillChangeContent(controller: NSFetchedResultsController)
}
// MARK: - FetchedResultsControllerDelegate
private final class FetchedResultsControllerDelegate: NSFetchedResultsControllerDelegate {
// MARK: NSFetchedResultsControllerDelegate
@objc func controllerWillChangeContent(controller: NSFetchedResultsController) {
self.handler?.controllerWillChangeContent(controller)
}
@objc func controller(controller: NSFetchedResultsController, didChangeObject anObject: AnyObject, atIndexPath indexPath: NSIndexPath?, forChangeType type: NSFetchedResultsChangeType, newIndexPath: NSIndexPath?) {
self.handler?.controller(controller, didChangeObject: anObject, atIndexPath: indexPath, forChangeType: type, newIndexPath: newIndexPath)
}
// MARK: Private
weak var handler: FetchedResultsControllerHandler?
weak var fetchedResultsController: NSFetchedResultsController? {
didSet {
oldValue?.delegate = nil
self.fetchedResultsController?.delegate = self
}
}
deinit {
self.fetchedResultsController?.delegate = nil
}
}
@@ -1,832 +0,0 @@
//
// ManagedObjectListController.swift
// CoreStore
//
// Copyright (c) 2015 John Rommel Estropia
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in all
// copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
// SOFTWARE.
//
import Foundation
import CoreData
import GCDKit
// MARK: - SectionedBy
/**
The `SectionedBy` clause indicates the key path to use to group the `ManagedObjectListController` objects into sections. An optional closure can also be provided to transform the value into an appropriate section name:
let listController = CoreStore.observeSectionedList(
From(MyPersonEntity),
SectionedBy("age") { "Age \($0)" },
OrderBy(.Ascending("lastName"))
)
*/
public struct SectionedBy {
// MARK: Public
/**
Initializes a `SectionedBy` clause with the key path to use to group `ManagedObjectListController` objects into sections
:param: sectionKeyPath the key path to use to group the objects into sections
*/
public init(_ sectionKeyPath: KeyPath) {
self.init(sectionKeyPath, { $0 })
}
/**
Initializes a `SectionedBy` clause with the key path to use to group `ManagedObjectListController` objects into sections, and a closure to transform the value for the key path to an appropriate section name
:param: sectionKeyPath the key path to use to group the objects into sections
:param: sectionIndexTransformer a closure to transform the value for the key path to an appropriate section name
*/
public init(_ sectionKeyPath: KeyPath, _ sectionIndexTransformer: (sectionName: String?) -> String?) {
self.sectionKeyPath = sectionKeyPath
self.sectionIndexTransformer = sectionIndexTransformer
}
// MARK: Internal
internal let sectionKeyPath: KeyPath
internal let sectionIndexTransformer: (sectionName: KeyPath?) -> String?
}
// MARK: - ManagedObjectListController
/**
The `ManagedObjectListController` monitors changes to a list of `NSManagedObject` instances. Observers that implement the `ManagedObjectListChangeObserver` protocol may then register themselves to the `ManagedObjectListController`'s `addObserver(_:)` method:
let listController = CoreStore.observeObjectList(
From(MyPersonEntity),
Where("title", isEqualTo: "Engineer"),
OrderBy(.Ascending("lastName"))
)
listController.addObserver(self)
The `ManagedObjectListController` instance needs to be held on (retained) for as long as the list needs to be observed.
Observers registered via `addObserver(_:)` are not retained. `ManagedObjectListController` only keeps a `weak` reference to all observers, thus keeping itself free from retain-cycles.
Lists created with `observeObjectList(...)` keep a single-section list of objects, where each object can be accessed by index:
let firstPerson: MyPersonEntity = listController[0]
Accessing the list with an index above the valid range will throw an exception.
Creating a sectioned-list is also possible with the `observeSectionedList(...)` method:
let listController = CoreStore.observeSectionedList(
From(MyPersonEntity),
SectionedBy("age") { "Age \($0)" },
Where("title", isEqualTo: "Engineer"),
OrderBy(.Ascending("lastName"))
)
listController.addObserver(self)
Objects from `ManagedObjectListController`'s created this way can be accessed either by an `NSIndexPath` or a tuple:
let indexPath = NSIndexPath(forItem: 3, inSection: 2)
let person1 = listController[indexPath]
let person2 = listController[2, 3]
In the example above, both `person1` and `person2` will contain the object at section=2, index=3.
*/
public final class ManagedObjectListController<T: NSManagedObject> {
// MARK: Public
/**
Accesses the object at the given index within the first section. This subscript indexer is typically used for `ManagedObjectListController`'s created with `addObserver(_:)`.
:param: index the index of the object. Using an index above the valid range will throw an exception.
*/
public subscript(index: Int) -> T {
return self.fetchedResultsController.objectAtIndexPath(NSIndexPath(forItem: index, inSection: 0)) as! T
}
/**
Accesses the object at the given `NSIndexPath`. This subscript indexer is typically used for `ManagedObjectListController`'s created with `observeSectionedList(_:)`.
:param: indexPath the `NSIndexPath` for the object. Using an `indexPath` with an invalid range will throw an exception.
*/
public subscript(indexPath: NSIndexPath) -> T {
return self.fetchedResultsController.objectAtIndexPath(indexPath) as! T
}
/**
Accesses the object at the given `sectionIndex` and `itemIndex`. This subscript indexer is typically used for `ManagedObjectListController`'s created with `observeSectionedList(_:)`.
:param: sectionIndex the section index for the object. Using a `sectionIndex` with an invalid range will throw an exception.
:param: itemIndex the index for the object within the section. Using an `itemIndex` with an invalid range will throw an exception.
*/
public subscript(sectionIndex: Int, itemIndex: Int) -> T {
return self.fetchedResultsController.objectAtIndexPath(NSIndexPath(forItem: itemIndex, inSection: sectionIndex)) as! T
}
/**
Returns the number of sections
*/
public func numberOfSections() -> Int {
return self.fetchedResultsController.sections?.count ?? 0
}
/**
Returns the number of objects in the specified section
:param: section the section index
*/
public func numberOfObjectsInSection(section: Int) -> Int {
return (self.fetchedResultsController.sections?[section] as? NSFetchedResultsSectionInfo)?.numberOfObjects ?? 0
}
/**
Returns the `NSFetchedResultsSectionInfo` for the specified section
:param: section the section index
*/
public func sectionInfoAtIndex(section: Int) -> NSFetchedResultsSectionInfo {
return self.fetchedResultsController.sections![section] as! NSFetchedResultsSectionInfo
}
/**
Registers a `ManagedObjectListChangeObserver` to be notified when changes to the receiver's list occur.
To prevent retain-cycles, `ManagedObjectListController` only keeps `weak` references to its observers.
For thread safety, this method needs to be called from the main thread. An assertion failure will occur (on debug builds only) if called from any thread other than the main thread.
Calling `addObserver(_:)` multiple times on the same observer is safe, as `ManagedObjectListController` unregisters previous notifications to the observer before re-registering them.
:param: observer a `ManagedObjectListChangeObserver` to send change notifications to
*/
public func addObserver<U: ManagedObjectListChangeObserver where U.EntityType == T>(observer: U) {
CoreStore.assert(NSThread.isMainThread(), "Attempted to add an observer of type \(typeName(observer)) outside the main thread.")
self.removeObserver(observer)
self.registerChangeNotification(
&NotificationKey.willChangeList,
name: ManagedObjectListControllerWillChangeListNotification,
toObserver: observer,
callback: { [weak observer] (listController) -> Void in
if let observer = observer {
observer.managedObjectListWillChange(listController)
}
}
)
self.registerChangeNotification(
&NotificationKey.didChangeList,
name: ManagedObjectListControllerDidChangeListNotification,
toObserver: observer,
callback: { [weak observer] (listController) -> Void in
if let observer = observer {
observer.managedObjectListDidChange(listController)
}
}
)
}
/**
Registers a `ManagedObjectListObjectObserver` to be notified when changes to the receiver's list occur.
To prevent retain-cycles, `ManagedObjectListController` only keeps `weak` references to its observers.
For thread safety, this method needs to be called from the main thread. An assertion failure will occur (on debug builds only) if called from any thread other than the main thread.
Calling `addObserver(_:)` multiple times on the same observer is safe, as `ManagedObjectListController` unregisters previous notifications to the observer before re-registering them.
:param: observer a `ManagedObjectListObjectObserver` to send change notifications to
*/
public func addObserver<U: ManagedObjectListObjectObserver where U.EntityType == T>(observer: U) {
CoreStore.assert(NSThread.isMainThread(), "Attempted to add an observer of type \(typeName(observer)) outside the main thread.")
self.removeObserver(observer)
self.registerChangeNotification(
&NotificationKey.willChangeList,
name: ManagedObjectListControllerWillChangeListNotification,
toObserver: observer,
callback: { [weak observer] (listController) -> Void in
if let observer = observer {
observer.managedObjectListWillChange(listController)
}
}
)
self.registerChangeNotification(
&NotificationKey.didChangeList,
name: ManagedObjectListControllerDidChangeListNotification,
toObserver: observer,
callback: { [weak observer] (listController) -> Void in
if let observer = observer {
observer.managedObjectListDidChange(listController)
}
}
)
self.registerObjectNotification(
&NotificationKey.didInsertObject,
name: ManagedObjectListControllerDidInsertObjectNotification,
toObserver: observer,
callback: { [weak observer] (listController, object, indexPath, newIndexPath) -> Void in
if let observer = observer {
observer.managedObjectList(
listController,
didInsertObject: object,
toIndexPath: newIndexPath!
)
}
}
)
self.registerObjectNotification(
&NotificationKey.didDeleteObject,
name: ManagedObjectListControllerDidDeleteObjectNotification,
toObserver: observer,
callback: { [weak observer] (listController, object, indexPath, newIndexPath) -> Void in
if let observer = observer {
observer.managedObjectList(
listController,
didDeleteObject: object,
fromIndexPath: indexPath!
)
}
}
)
self.registerObjectNotification(
&NotificationKey.didUpdateObject,
name: ManagedObjectListControllerDidUpdateObjectNotification,
toObserver: observer,
callback: { [weak observer] (listController, object, indexPath, newIndexPath) -> Void in
if let observer = observer {
observer.managedObjectList(
listController,
didUpdateObject: object,
atIndexPath: indexPath!
)
}
}
)
self.registerObjectNotification(
&NotificationKey.didMoveObject,
name: ManagedObjectListControllerDidMoveObjectNotification,
toObserver: observer,
callback: { [weak observer] (listController, object, indexPath, newIndexPath) -> Void in
if let observer = observer {
observer.managedObjectList(
listController,
didMoveObject: object,
fromIndexPath: indexPath!,
toIndexPath: newIndexPath!
)
}
}
)
}
/**
Registers a `ManagedObjectListSectionObserver` to be notified when changes to the receiver's list occur.
To prevent retain-cycles, `ManagedObjectListController` only keeps `weak` references to its observers.
For thread safety, this method needs to be called from the main thread. An assertion failure will occur (on debug builds only) if called from any thread other than the main thread.
Calling `addObserver(_:)` multiple times on the same observer is safe, as `ManagedObjectListController` unregisters previous notifications to the observer before re-registering them.
:param: observer a `ManagedObjectListSectionObserver` to send change notifications to
*/
public func addObserver<U: ManagedObjectListSectionObserver where U.EntityType == T>(observer: U) {
CoreStore.assert(NSThread.isMainThread(), "Attempted to add an observer of type \(typeName(observer)) outside the main thread.")
self.removeObserver(observer)
self.registerChangeNotification(
&NotificationKey.willChangeList,
name: ManagedObjectListControllerWillChangeListNotification,
toObserver: observer,
callback: { [weak observer] (listController) -> Void in
if let observer = observer {
observer.managedObjectListWillChange(listController)
}
}
)
self.registerChangeNotification(
&NotificationKey.didChangeList,
name: ManagedObjectListControllerDidChangeListNotification,
toObserver: observer,
callback: { [weak observer] (listController) -> Void in
if let observer = observer {
observer.managedObjectListDidChange(listController)
}
}
)
self.registerObjectNotification(
&NotificationKey.didInsertObject,
name: ManagedObjectListControllerDidInsertObjectNotification,
toObserver: observer,
callback: { [weak observer] (listController, object, indexPath, newIndexPath) -> Void in
if let observer = observer {
observer.managedObjectList(
listController,
didInsertObject: object,
toIndexPath: newIndexPath!
)
}
}
)
self.registerObjectNotification(
&NotificationKey.didDeleteObject,
name: ManagedObjectListControllerDidDeleteObjectNotification,
toObserver: observer,
callback: { [weak observer] (listController, object, indexPath, newIndexPath) -> Void in
if let observer = observer {
observer.managedObjectList(
listController,
didDeleteObject: object,
fromIndexPath: indexPath!
)
}
}
)
self.registerObjectNotification(
&NotificationKey.didUpdateObject,
name: ManagedObjectListControllerDidUpdateObjectNotification,
toObserver: observer,
callback: { [weak observer] (listController, object, indexPath, newIndexPath) -> Void in
if let observer = observer {
observer.managedObjectList(
listController,
didUpdateObject: object,
atIndexPath: indexPath!
)
}
}
)
self.registerObjectNotification(
&NotificationKey.didMoveObject,
name: ManagedObjectListControllerDidMoveObjectNotification,
toObserver: observer,
callback: { [weak observer] (listController, object, indexPath, newIndexPath) -> Void in
if let observer = observer {
observer.managedObjectList(
listController,
didMoveObject: object,
fromIndexPath: indexPath!,
toIndexPath: newIndexPath!
)
}
}
)
self.registerSectionNotification(
&NotificationKey.didInsertSection,
name: ManagedObjectListControllerDidInsertSectionNotification,
toObserver: observer,
callback: { [weak observer] (listController, sectionInfo, sectionIndex) -> Void in
if let observer = observer {
observer.managedObjectList(
listController,
didInsertSection: sectionInfo,
toSectionIndex: sectionIndex
)
}
}
)
self.registerSectionNotification(
&NotificationKey.didDeleteSection,
name: ManagedObjectListControllerDidDeleteSectionNotification,
toObserver: observer,
callback: { [weak observer] (listController, sectionInfo, sectionIndex) -> Void in
if let observer = observer {
observer.managedObjectList(
listController,
didDeleteSection: sectionInfo,
fromSectionIndex: sectionIndex
)
}
}
)
}
/**
Unregisters a `ManagedObjectListChangeObserver` from receiving notifications for changes to the receiver's list.
For thread safety, this method needs to be called from the main thread. An assertion failure will occur (on debug builds only) if called from any thread other than the main thread.
:param: observer a `ManagedObjectListChangeObserver` to unregister notifications to
*/
public func removeObserver<U: ManagedObjectListChangeObserver where U.EntityType == T>(observer: U) {
CoreStore.assert(NSThread.isMainThread(), "Attempted to remove an observer of type \(typeName(observer)) outside the main thread.")
let nilValue: AnyObject? = nil
setAssociatedRetainedObject(nilValue, forKey: &NotificationKey.willChangeList, inObject: observer)
setAssociatedRetainedObject(nilValue, forKey: &NotificationKey.didChangeList, inObject: observer)
setAssociatedRetainedObject(nilValue, forKey: &NotificationKey.didInsertObject, inObject: observer)
setAssociatedRetainedObject(nilValue, forKey: &NotificationKey.didDeleteObject, inObject: observer)
setAssociatedRetainedObject(nilValue, forKey: &NotificationKey.didUpdateObject, inObject: observer)
setAssociatedRetainedObject(nilValue, forKey: &NotificationKey.didMoveObject, inObject: observer)
setAssociatedRetainedObject(nilValue, forKey: &NotificationKey.didInsertSection, inObject: observer)
setAssociatedRetainedObject(nilValue, forKey: &NotificationKey.didDeleteSection, inObject: observer)
}
// MARK: Internal
internal init(dataStack: DataStack, from: From<T>, sectionedBy: SectionedBy?, fetchClauses: [FetchClause]) {
let context = dataStack.mainContext
let fetchRequest = NSFetchRequest()
from.applyToFetchRequest(fetchRequest, context: context)
fetchRequest.fetchLimit = 0
fetchRequest.resultType = .ManagedObjectResultType
for clause in fetchClauses {
clause.applyToFetchRequest(fetchRequest)
}
let fetchedResultsController = NSFetchedResultsController(
fetchRequest: fetchRequest,
managedObjectContext: context,
sectionNameKeyPath: sectionedBy?.sectionKeyPath,
cacheName: nil
)
let fetchedResultsControllerDelegate = FetchedResultsControllerDelegate()
self.fetchedResultsController = fetchedResultsController
self.fetchedResultsControllerDelegate = fetchedResultsControllerDelegate
self.parentStack = dataStack
if let sectionIndexTransformer = sectionedBy?.sectionIndexTransformer {
self.sectionIndexTransformer = sectionIndexTransformer
}
else {
self.sectionIndexTransformer = { $0 }
}
fetchedResultsControllerDelegate.handler = self
fetchedResultsControllerDelegate.fetchedResultsController = fetchedResultsController
var error: NSError?
if !fetchedResultsController.performFetch(&error) {
CoreStore.handleError(
error ?? NSError(coreStoreErrorCode: .UnknownError),
"Failed to perform fetch on <\(NSFetchedResultsController.self)>.")
}
}
// MARK: Private
private let fetchedResultsController: NSFetchedResultsController
private let fetchedResultsControllerDelegate: FetchedResultsControllerDelegate
private let sectionIndexTransformer: (sectionName: KeyPath?) -> String?
private weak var parentStack: DataStack?
private func registerChangeNotification(notificationKey: UnsafePointer<Void>, name: String, toObserver observer: AnyObject, callback: (listController: ManagedObjectListController<T>) -> Void) {
setAssociatedRetainedObject(
NotificationObserver(
notificationName: name,
object: self,
closure: { [weak self] (note) -> Void in
if let strongSelf = self {
callback(listController: strongSelf)
}
}
),
forKey: notificationKey,
inObject: observer
)
}
private func registerObjectNotification(notificationKey: UnsafePointer<Void>, name: String, toObserver observer: AnyObject, callback: (listController: ManagedObjectListController<T>, object: T, indexPath: NSIndexPath?, newIndexPath: NSIndexPath?) -> Void) {
setAssociatedRetainedObject(
NotificationObserver(
notificationName: name,
object: self,
closure: { [weak self] (note) -> Void in
if let strongSelf = self,
let userInfo = note.userInfo,
let object = userInfo[UserInfoKeyObject] as? T {
callback(
listController: strongSelf,
object: object,
indexPath: userInfo[UserInfoKeyIndexPath] as? NSIndexPath,
newIndexPath: userInfo[UserInfoKeyNewIndexPath] as? NSIndexPath
)
}
}
),
forKey: notificationKey,
inObject: observer
)
}
private func registerSectionNotification(notificationKey: UnsafePointer<Void>, name: String, toObserver observer: AnyObject, callback: (listController: ManagedObjectListController<T>, sectionInfo: NSFetchedResultsSectionInfo, sectionIndex: Int) -> Void) {
setAssociatedRetainedObject(
NotificationObserver(
notificationName: name,
object: self,
closure: { [weak self] (note) -> Void in
if let strongSelf = self,
let userInfo = note.userInfo,
let sectionInfo = userInfo[UserInfoKeySectionInfo] as? NSFetchedResultsSectionInfo,
let sectionIndex = (userInfo[UserInfoKeySectionIndex] as? NSNumber)?.integerValue {
callback(
listController: strongSelf,
sectionInfo: sectionInfo,
sectionIndex: sectionIndex
)
}
}
),
forKey: notificationKey,
inObject: observer
)
}
}
// MARK: - ManagedObjectListController: FetchedResultsControllerHandler
extension ManagedObjectListController: FetchedResultsControllerHandler {
// MARK: FetchedResultsControllerHandler
private func controller(controller: NSFetchedResultsController, didChangeObject anObject: AnyObject, atIndexPath indexPath: NSIndexPath?, forChangeType type: NSFetchedResultsChangeType, newIndexPath: NSIndexPath?) {
switch type {
case .Insert:
NSNotificationCenter.defaultCenter().postNotificationName(
ManagedObjectListControllerDidInsertObjectNotification,
object: self,
userInfo: [
UserInfoKeyObject: anObject,
UserInfoKeyNewIndexPath: newIndexPath!
]
)
case .Delete:
NSNotificationCenter.defaultCenter().postNotificationName(
ManagedObjectListControllerDidDeleteObjectNotification,
object: self,
userInfo: [
UserInfoKeyObject: anObject,
UserInfoKeyIndexPath: indexPath!
]
)
case .Update:
NSNotificationCenter.defaultCenter().postNotificationName(
ManagedObjectListControllerDidUpdateObjectNotification,
object: self,
userInfo: [
UserInfoKeyObject: anObject,
UserInfoKeyIndexPath: indexPath!
]
)
case .Move:
NSNotificationCenter.defaultCenter().postNotificationName(
ManagedObjectListControllerDidMoveObjectNotification,
object: self,
userInfo: [
UserInfoKeyObject: anObject,
UserInfoKeyIndexPath: indexPath!,
UserInfoKeyNewIndexPath: newIndexPath!
]
)
}
}
private func controller(controller: NSFetchedResultsController, didChangeSection sectionInfo: NSFetchedResultsSectionInfo, atIndex sectionIndex: Int, forChangeType type: NSFetchedResultsChangeType) {
switch type {
case .Insert:
NSNotificationCenter.defaultCenter().postNotificationName(
ManagedObjectListControllerDidInsertSectionNotification,
object: self,
userInfo: [
UserInfoKeySectionInfo: sectionInfo,
UserInfoKeySectionIndex: NSNumber(integer: sectionIndex)
]
)
case .Delete:
NSNotificationCenter.defaultCenter().postNotificationName(
ManagedObjectListControllerDidDeleteSectionNotification,
object: self,
userInfo: [
UserInfoKeySectionInfo: sectionInfo,
UserInfoKeySectionIndex: NSNumber(integer: sectionIndex)
]
)
default:
break
}
}
private func controllerWillChangeContent(controller: NSFetchedResultsController) {
NSNotificationCenter.defaultCenter().postNotificationName(
ManagedObjectListControllerWillChangeListNotification,
object: self
)
}
private func controllerDidChangeContent(controller: NSFetchedResultsController) {
NSNotificationCenter.defaultCenter().postNotificationName(
ManagedObjectListControllerDidChangeListNotification,
object: self
)
}
private func controller(controller: NSFetchedResultsController, sectionIndexTitleForSectionName sectionName: String?) -> String? {
return self.sectionIndexTransformer(sectionName: sectionName)
}
}
// MARK: - FetchedResultsControllerHandler
private protocol FetchedResultsControllerHandler: class {
func controller(controller: NSFetchedResultsController, didChangeObject anObject: AnyObject, atIndexPath indexPath: NSIndexPath?, forChangeType type: NSFetchedResultsChangeType, newIndexPath: NSIndexPath?)
func controller(controller: NSFetchedResultsController, didChangeSection sectionInfo: NSFetchedResultsSectionInfo, atIndex sectionIndex: Int, forChangeType type: NSFetchedResultsChangeType)
func controllerWillChangeContent(controller: NSFetchedResultsController)
func controllerDidChangeContent(controller: NSFetchedResultsController)
func controller(controller: NSFetchedResultsController, sectionIndexTitleForSectionName sectionName: String?) -> String?
}
// MARK: - FetchedResultsControllerDelegate
private final class FetchedResultsControllerDelegate: NSFetchedResultsControllerDelegate {
// MARK: NSFetchedResultsControllerDelegate
@objc func controllerWillChangeContent(controller: NSFetchedResultsController) {
self.handler?.controllerWillChangeContent(controller)
}
@objc func controllerDidChangeContent(controller: NSFetchedResultsController) {
self.handler?.controllerDidChangeContent(controller)
}
@objc func controller(controller: NSFetchedResultsController, didChangeObject anObject: AnyObject, atIndexPath indexPath: NSIndexPath?, forChangeType type: NSFetchedResultsChangeType, newIndexPath: NSIndexPath?) {
self.handler?.controller(controller, didChangeObject: anObject, atIndexPath: indexPath, forChangeType: type, newIndexPath: newIndexPath)
}
@objc func controller(controller: NSFetchedResultsController, didChangeSection sectionInfo: NSFetchedResultsSectionInfo, atIndex sectionIndex: Int, forChangeType type: NSFetchedResultsChangeType) {
self.handler?.controller(controller, didChangeSection: sectionInfo, atIndex: sectionIndex, forChangeType: type)
}
@objc func controller(controller: NSFetchedResultsController, sectionIndexTitleForSectionName sectionName: String?) -> String? {
return self.handler?.controller(controller, sectionIndexTitleForSectionName: sectionName)
}
// MARK: Private
weak var handler: FetchedResultsControllerHandler?
weak var fetchedResultsController: NSFetchedResultsController? {
didSet {
oldValue?.delegate = nil
self.fetchedResultsController?.delegate = self
}
}
deinit {
self.fetchedResultsController?.delegate = nil
}
}
private let ManagedObjectListControllerWillChangeListNotification = "ManagedObjectListControllerWillChangeListNotification"
private let ManagedObjectListControllerDidChangeListNotification = "ManagedObjectListControllerDidChangeListNotification"
private let ManagedObjectListControllerDidInsertObjectNotification = "ManagedObjectListControllerDidInsertObjectNotification"
private let ManagedObjectListControllerDidDeleteObjectNotification = "ManagedObjectListControllerDidDeleteObjectNotification"
private let ManagedObjectListControllerDidUpdateObjectNotification = "ManagedObjectListControllerDidUpdateObjectNotification"
private let ManagedObjectListControllerDidMoveObjectNotification = "ManagedObjectListControllerDidMoveObjectNotification"
private let ManagedObjectListControllerDidInsertSectionNotification = "ManagedObjectListControllerDidInsertSectionNotification"
private let ManagedObjectListControllerDidDeleteSectionNotification = "ManagedObjectListControllerDidDeleteSectionNotification"
private let UserInfoKeyObject = "UserInfoKeyObject"
private let UserInfoKeyIndexPath = "UserInfoKeyIndexPath"
private let UserInfoKeyNewIndexPath = "UserInfoKeyNewIndexPath"
private let UserInfoKeySectionInfo = "UserInfoKeySectionInfo"
private let UserInfoKeySectionIndex = "UserInfoKeySectionIndex"
private struct NotificationKey {
static var willChangeList: Void?
static var didChangeList: Void?
static var didInsertObject: Void?
static var didDeleteObject: Void?
static var didUpdateObject: Void?
static var didMoveObject: Void?
static var didInsertSection: Void?
static var didDeleteSection: Void?
}
@@ -1,147 +0,0 @@
//
// ManagedObjectListObserver.swift
// CoreStore
//
// Copyright (c) 2015 John Rommel Estropia
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in all
// copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
// SOFTWARE.
//
import Foundation
import CoreData
// MARK: - ManagedObjectListChangeObserver
/**
Implement the `ManagedObjectListChangeObserver` protocol to observe changes to a list of `NSManagedObject`'s. `ManagedObjectListChangeObserver`'s may register themselves to a `ManagedObjectListController`'s `addObserver(_:)` method:
let listController = CoreStore.observeObjectList(
From(MyPersonEntity),
OrderBy(.Ascending("lastName"))
)
listController.addObserver(self)
*/
public protocol ManagedObjectListChangeObserver: class {
/**
The `NSManagedObject` type for the observed list
*/
typealias EntityType: NSManagedObject
/**
Handles processing just before a change to the observed list occurs
:param: listController the `ManagedObjectListController` monitoring the list being observed
*/
func managedObjectListWillChange(listController: ManagedObjectListController<EntityType>)
/**
Handles processing right after a change to the observed list occurs
:param: listController the `ManagedObjectListController` monitoring the object being observed
*/
func managedObjectListDidChange(listController: ManagedObjectListController<EntityType>)
}
// MARK: - ManagedObjectListObjectObserver
/**
Implement the `ManagedObjectListObjectObserver` protocol to observe detailed changes to a list's object. `ManagedObjectListObjectObserver`'s may register themselves to a `ManagedObjectListController`'s `addObserver(_:)` method:
let listController = CoreStore.observeObjectList(
From(MyPersonEntity),
OrderBy(.Ascending("lastName"))
)
listController.addObserver(self)
*/
public protocol ManagedObjectListObjectObserver: ManagedObjectListChangeObserver {
/**
Notifies that an object was inserted to the specified `NSIndexPath` in the list
:param: listController the `ManagedObjectListController` monitoring the list being observed
:param: object the entity type for the inserted object
:param: indexPath the new `NSIndexPath` for the inserted object
*/
func managedObjectList(listController: ManagedObjectListController<EntityType>, didInsertObject object: EntityType, toIndexPath indexPath: NSIndexPath)
/**
Notifies that an object was deleted from the specified `NSIndexPath` in the list
:param: listController the `ManagedObjectListController` monitoring the list being observed
:param: object the entity type for the deleted object
:param: indexPath the `NSIndexPath` for the deleted object
*/
func managedObjectList(listController: ManagedObjectListController<EntityType>, didDeleteObject object: EntityType, fromIndexPath indexPath: NSIndexPath)
/**
Notifies that an object at the specified `NSIndexPath` was updated
:param: listController the `ManagedObjectListController` monitoring the list being observed
:param: object the entity type for the updated object
:param: indexPath the `NSIndexPath` for the updated object
*/
func managedObjectList(listController: ManagedObjectListController<EntityType>, didUpdateObject object: EntityType, atIndexPath indexPath: NSIndexPath)
/**
Notifies that an object's index changed
:param: listController the `ManagedObjectListController` monitoring the list being observed
:param: object the entity type for the moved object
:param: fromIndexPath the previous `NSIndexPath` for the moved object
:param: toIndexPath the new `NSIndexPath` for the moved object
*/
func managedObjectList(listController: ManagedObjectListController<EntityType>, didMoveObject object: EntityType, fromIndexPath: NSIndexPath, toIndexPath: NSIndexPath)
}
// MARK: - ManagedObjectListSectionObserver
/**
Implement the `ManagedObjectListSectionObserver` protocol to observe changes to a list's section info. `ManagedObjectListSectionObserver`'s may register themselves to a `ManagedObjectListController`'s `addObserver(_:)` method:
let listController = CoreStore.observeSectionedList(
From(MyPersonEntity),
SectionedBy("age") { "Age \($0)" },
OrderBy(.Ascending("lastName"))
)
listController.addObserver(self)
*/
public protocol ManagedObjectListSectionObserver: ManagedObjectListObjectObserver {
/**
Notifies that a section was inserted at the specified index
:param: listController the `ManagedObjectListController` monitoring the list being observed
:param: sectionInfo the `NSFetchedResultsSectionInfo` for the inserted section
:param: sectionIndex the new section index for the new section
*/
func managedObjectList(listController: ManagedObjectListController<EntityType>, didInsertSection sectionInfo: NSFetchedResultsSectionInfo, toSectionIndex sectionIndex: Int)
/**
Notifies that a section was inserted at the specified index
:param: listController the `ManagedObjectListController` monitoring the list being observed
:param: sectionInfo the `NSFetchedResultsSectionInfo` for the deleted section
:param: sectionIndex the previous section index for the deleted section
*/
func managedObjectList(listController: ManagedObjectListController<EntityType>, didDeleteSection sectionInfo: NSFetchedResultsSectionInfo, fromSectionIndex sectionIndex: Int)
}
@@ -1,69 +0,0 @@
//
// ManagedObjectObserver.swift
// CoreStore
//
// Copyright (c) 2015 John Rommel Estropia
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in all
// copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
// SOFTWARE.
//
import Foundation
import CoreData
// MARK: - ManagedObjectObserver
/**
Implement the `ManagedObjectObserver` protocol to observe changes to a single `NSManagedObject` instance. `ManagedObjectObserver`'s may register themselves to a `ManagedObjectController`'s `addObserver(_:)` method:
let objectController = CoreStore.observeObject(object)
objectController.addObserver(self)
*/
public protocol ManagedObjectObserver: class {
/**
The `NSManagedObject` type for the observed object
*/
typealias EntityType: NSManagedObject
/**
Handles processing just before a change to the observed `object` occurs
:param: objectController the `ManagedObjectController` monitoring the object being observed
:param: object the `NSManagedObject` instance being observed
*/
func managedObjectWillUpdate(objectController: ManagedObjectController<EntityType>, object: EntityType)
/**
Handles processing right after a change to the observed `object` occurs
:param: objectController the `ManagedObjectController` monitoring the object being observed
:param: object the `NSManagedObject` instance being observed
:param: changedPersistentKeys a `Set` of key paths for the attributes that were changed. Note that `changedPersistentKeys` only contains keys for attributes/relationships present in the persistent store, thus transient properties will not be reported.
*/
func managedObjectWasUpdated(objectController: ManagedObjectController<EntityType>, object: EntityType, changedPersistentKeys: Set<KeyPath>)
/**
Handles processing right after `object` is deleted
:param: objectController the `ManagedObjectController` monitoring the object being observed
:param: object the `NSManagedObject` instance being observed
*/
func managedObjectWasDeleted(objectController: ManagedObjectController<EntityType>, object: EntityType)
}
@@ -1,220 +0,0 @@
//
// AsynchronousDataTransaction.swift
// CoreStore
//
// Copyright (c) 2015 John Rommel Estropia
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in all
// copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
// SOFTWARE.
//
import Foundation
import CoreData
import GCDKit
// MARK: - AsynchronousDataTransaction
/**
The `AsynchronousDataTransaction` provides an interface for `NSManagedObject` creates, updates, and deletes. A transaction object should typically be only used from within a transaction block initiated from `DataStack.beginAsynchronous(_:)`, or from `CoreStore.beginAsynchronous(_:)`.
*/
public final class AsynchronousDataTransaction: BaseDataTransaction {
// MARK: Public
/**
Saves the transaction changes asynchronously. This method should not be used after the `commit()` method was already called once.
:param: completion the block executed after the save completes. Success or failure is reported by the `SaveResult` argument of the block.
*/
public func commit(completion: (result: SaveResult) -> Void) {
CoreStore.assert(self.transactionQueue.isCurrentExecutionContext(), "Attempted to commit a \(typeName(self)) outside its designated queue.")
CoreStore.assert(!self.isCommitted, "Attempted to commit a \(typeName(self)) more than once.")
self.isCommitted = true
let semaphore = GCDSemaphore(0)
self.context.saveAsynchronouslyWithCompletion { (result) -> Void in
self.result = result
completion(result: result)
semaphore.signal()
}
semaphore.wait()
}
/**
Saves the transaction changes and waits for completion synchronously. This method should not be used after the `commit()` method was already called once.
*/
public func commit() {
CoreStore.assert(self.transactionQueue.isCurrentExecutionContext(), "Attempted to commit a \(typeName(self)) outside its designated queue.")
CoreStore.assert(!self.isCommitted, "Attempted to commit a \(typeName(self)) more than once.")
self.isCommitted = true
self.result = self.context.saveSynchronously()
}
/**
Begins a child transaction synchronously where NSManagedObject creates, updates, and deletes can be made. This method should not be used after the `commit()` method was already called once.
:param: closure the block where creates, updates, and deletes can be made to the transaction. Transaction blocks are executed serially in a background queue, and all changes are made from a concurrent `NSManagedObjectContext`.
:returns: a `SaveResult` value indicating success or failure, or `nil` if the transaction was not comitted synchronously
*/
public func beginSynchronous(closure: (transaction: SynchronousDataTransaction) -> Void) -> SaveResult? {
CoreStore.assert(self.transactionQueue.isCurrentExecutionContext(), "Attempted to begin a child transaction from a \(typeName(self)) outside its designated queue.")
CoreStore.assert(!self.isCommitted, "Attempted to begin a child transaction from an already committed \(typeName(self)).")
return SynchronousDataTransaction(
mainContext: self.context,
queue: self.childTransactionQueue,
closure: closure).performAndWait()
}
// MARK: BaseDataTransaction
/**
Creates a new `NSManagedObject` with the specified entity type.
:param: into the `Into` clause indicating the destination `NSManagedObject` entity type and the destination configuration
:returns: a new `NSManagedObject` instance of the specified entity type.
*/
public override func create<T: NSManagedObject>(into: Into<T>) -> T {
CoreStore.assert(!self.isCommitted, "Attempted to create an entity of type <\(T.self)> from an already committed \(typeName(self)).")
return super.create(into)
}
/**
Returns an editable proxy of a specified `NSManagedObject`. This method should not be used after the `commit()` method was already called once.
:param: object the `NSManagedObject` type to be edited
:returns: an editable proxy for the specified `NSManagedObject`.
*/
public override func edit<T: NSManagedObject>(object: T?) -> T? {
CoreStore.assert(!self.isCommitted, "Attempted to update an entity of type \(typeName(object)) from an already committed \(typeName(self)).")
return super.edit(object)
}
/**
Returns an editable proxy of the object with the specified `NSManagedObjectID`. This method should not be used after the `commit()` method was already called once.
:param: into an `Into` clause specifying the entity type
:param: objectID the `NSManagedObjectID` for the object to be edited
:returns: an editable proxy for the specified `NSManagedObject`.
*/
public override func edit<T: NSManagedObject>(into: Into<T>, _ objectID: NSManagedObjectID) -> T? {
CoreStore.assert(!self.isCommitted, "Attempted to update an entity of type <\(T.self)> from an already committed \(typeName(self)).")
return super.edit(into, objectID)
}
/**
Deletes a specified `NSManagedObject`. This method should not be used after the `commit()` method was already called once.
:param: object the `NSManagedObject` type to be deleted
*/
public override func delete(object: NSManagedObject?) {
CoreStore.assert(!self.isCommitted, "Attempted to delete an entity of type \(typeName(object)) from an already committed \(typeName(self)).")
super.delete(object)
}
/**
Deletes the specified `NSManagedObject`'s.
:param: object1 the `NSManagedObject` type to be deleted
:param: object2 another `NSManagedObject` type to be deleted
:param: objects other `NSManagedObject`s type to be deleted
*/
public override func delete(object1: NSManagedObject?, _ object2: NSManagedObject?, _ objects: NSManagedObject?...) {
CoreStore.assert(!self.isCommitted, "Attempted to delete an entities from an already committed \(typeName(self)).")
super.delete([object1, object2] + objects)
}
/**
Deletes the specified `NSManagedObject`'s.
:param: objects the `NSManagedObject`'s type to be deleted
*/
public override func delete(objects: [NSManagedObject?]) {
CoreStore.assert(!self.isCommitted, "Attempted to delete an entities from an already committed \(typeName(self)).")
super.delete(objects)
}
/**
Rolls back the transaction by resetting the `NSManagedObjectContext`. After calling this method, all `NSManagedObjects` fetched within the transaction will become invalid. This method should not be used after the `commit()` method was already called once.
*/
public override func rollback() {
CoreStore.assert(!self.isCommitted, "Attempted to rollback an already committed \(typeName(self)).")
super.rollback()
}
// MARK: Internal
internal init(mainContext: NSManagedObjectContext, queue: GCDQueue, closure: (transaction: AsynchronousDataTransaction) -> Void) {
self.closure = closure
super.init(mainContext: mainContext, queue: queue)
}
internal func perform() {
self.transactionQueue.async {
self.closure(transaction: self)
if !self.isCommitted && self.hasChanges {
CoreStore.log(.Warning, message: "The closure for the \(typeName(self)) completed without being committed. All changes made within the transaction were discarded.")
}
}
}
internal func performAndWait() -> SaveResult? {
self.transactionQueue.sync {
self.closure(transaction: self)
if !self.isCommitted && self.hasChanges {
CoreStore.log(.Warning, message: "The closure for the \(typeName(self)) completed without being committed. All changes made within the transaction were discarded.")
}
}
return self.result
}
// MARK: Private
private let closure: (transaction: AsynchronousDataTransaction) -> Void
}
@@ -1,285 +0,0 @@
//
// BaseDataTransaction.swift
// CoreStore
//
// Copyright (c) 2014 John Rommel Estropia
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in all
// copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
// SOFTWARE.
//
import Foundation
import CoreData
import GCDKit
// MARK: - Into
/**
A `Into` clause contains the destination entity and destination persistent store for a `create(...)` method. A common usage is to just indicate the entity:
let person = transaction.create(Into(MyPersonEntity))
For cases where multiple `NSPersistentStore`'s contain the same entity, the destination configuration's name needs to be specified as well:
let person = transaction.create(Into<MyPersonEntity>("Configuration1"))
This helps the `NSManagedObjectContext` to determine which
*/
public struct Into<T: NSManagedObject> {
// MARK: Public
internal static var defaultConfigurationName: String {
return "PF_DEFAULT_CONFIGURATION_NAME"
}
/**
Initializes an `Into` clause.
Sample Usage:
let person = transaction.create(Into<MyPersonEntity>())
*/
public init(){
self.configuration = nil
self.inferStoreIfPossible = true
}
/**
Initializes an `Into` clause with the specified entity type.
Sample Usage:
let person = transaction.create(Into(MyPersonEntity))
:param: entity the `NSManagedObject` type to be created
*/
public init(_ entity: T.Type) {
self.configuration = nil
self.inferStoreIfPossible = true
}
/**
Initializes an `Into` clause with the specified configuration.
Sample Usage:
let person = transaction.create(Into<MyPersonEntity>("Configuration1"))
:param: configuration the `NSPersistentStore` configuration name to associate the object to. This parameter is required if multiple configurations contain the created `NSManagedObject`'s entity type. Set to `nil` to use the default configuration.
*/
public init(_ configuration: String?) {
self.configuration = configuration
self.inferStoreIfPossible = false
}
/**
Initializes an `Into` clause with the specified entity type and configuration.
Sample Usage:
let person = transaction.create(Into(MyPersonEntity.self, "Configuration1"))
:param: entity the `NSManagedObject` type to be created
:param: configuration the `NSPersistentStore` configuration name to associate the object to. This parameter is required if multiple configurations contain the created `NSManagedObject`'s entity type. Set to `nil` to use the default configuration.
*/
public init(_ entity: T.Type, _ configuration: String?) {
self.configuration = configuration
self.inferStoreIfPossible = false
}
// MARK: Internal
internal let configuration: String?
internal let inferStoreIfPossible: Bool
}
// MARK: - BaseDataTransaction
/**
The `BaseDataTransaction` is an abstract interface for `NSManagedObject` creates, updates, and deletes. All `BaseDataTransaction` subclasses manage a private `NSManagedObjectContext` which are direct children of the `NSPersistentStoreCoordinator`'s root `NSManagedObjectContext`. This means that all updates are saved first to the persistent store, and then propagated up to the read-only `NSManagedObjectContext`.
*/
public /*abstract*/ class BaseDataTransaction {
// MARK: Object management
/**
Indicates if the transaction has pending changes
*/
public var hasChanges: Bool {
return self.context.hasChanges
}
/**
Creates a new `NSManagedObject` with the specified entity type.
:param: into the `Into` clause indicating the destination `NSManagedObject` entity type and the destination configuration
:returns: a new `NSManagedObject` instance of the specified entity type.
*/
public func create<T: NSManagedObject>(into: Into<T>) -> T {
CoreStore.assert(self.transactionQueue.isCurrentExecutionContext(), "Attempted to create an entity of type <\(T.self)> outside its designated queue.")
let context = self.context
let object = T.createInContext(context)
if into.inferStoreIfPossible {
switch context.parentStack!.persistentStoreForEntityClass(T.self, configuration: nil, inferStoreIfPossible: true) {
case (.Some(let persistentStore), _):
context.assignObject(object, toPersistentStore: persistentStore)
case (.None, true):
CoreStore.assert(false, "Attempted to create an entity of type \(typeName(object)) with ambiguous destination persistent store, but the configuration name was not specified.")
default:
CoreStore.assert(false, "Attempted to create an entity of type \(typeName(object)), but a destination persistent store containing the entity type could not be found.")
}
}
else {
switch context.parentStack!.persistentStoreForEntityClass(T.self, configuration: into.configuration, inferStoreIfPossible: false) {
case (.Some(let persistentStore), _):
context.assignObject(object, toPersistentStore: persistentStore)
default:
if let configuration = into.configuration {
CoreStore.assert(false, "Attempted to create an entity of type \(typeName(object)) into the configuration \"\(configuration)\", which it doesn't belong to.")
}
else {
CoreStore.assert(false, "Attempted to create an entity of type \(typeName(object)) into the default configuration, which it doesn't belong to.")
}
}
}
return object
}
/**
Returns an editable proxy of a specified `NSManagedObject`.
:param: object the `NSManagedObject` type to be edited
:returns: an editable proxy for the specified `NSManagedObject`.
*/
public func edit<T: NSManagedObject>(object: T?) -> T? {
CoreStore.assert(self.transactionQueue.isCurrentExecutionContext(), "Attempted to update an entity of type \(typeName(object)) outside its designated queue.")
return object?.inContext(self.context)
}
/**
Returns an editable proxy of the object with the specified `NSManagedObjectID`.
:param: into an `Into` clause specifying the entity type
:param: objectID the `NSManagedObjectID` for the object to be edited
:returns: an editable proxy for the specified `NSManagedObject`.
*/
public func edit<T: NSManagedObject>(into: Into<T>, _ objectID: NSManagedObjectID) -> T? {
CoreStore.assert(self.transactionQueue.isCurrentExecutionContext(), "Attempted to update an entity of type <\(T.self)> outside its designated queue.")
CoreStore.assert(into.inferStoreIfPossible || (into.configuration ?? Into.defaultConfigurationName) == objectID.persistentStore?.configurationName, "Attempted to update an entity of type <\(T.self)> but the specified persistent store do not match the `NSManagedObjectID`.")
return T.inContext(self.context, withObjectID: objectID)
}
/**
Deletes a specified `NSManagedObject`.
:param: object the `NSManagedObject` type to be deleted
*/
public func delete(object: NSManagedObject?) {
CoreStore.assert(self.transactionQueue.isCurrentExecutionContext(), "Attempted to delete an entity outside its designated queue.")
object?.inContext(self.context)?.deleteFromContext()
}
/**
Deletes the specified `NSManagedObject`'s.
:param: object1 the `NSManagedObject` type to be deleted
:param: object2 another `NSManagedObject` type to be deleted
:param: objects other `NSManagedObject`s type to be deleted
*/
public func delete(object1: NSManagedObject?, _ object2: NSManagedObject?, _ objects: NSManagedObject?...) {
self.delete([object1, object2] + objects)
}
/**
Deletes the specified `NSManagedObject`'s.
:param: objects the `NSManagedObject`'s type to be deleted
*/
public func delete(objects: [NSManagedObject?]) {
CoreStore.assert(self.transactionQueue.isCurrentExecutionContext(), "Attempted to delete entities outside their designated queue.")
let context = self.context
for object in objects {
object?.inContext(context)?.deleteFromContext()
}
}
// MARK: Saving changes
/**
Rolls back the transaction by resetting the `NSManagedObjectContext`. After calling this method, all `NSManagedObjects` fetched within the transaction will become invalid.
*/
public func rollback() {
CoreStore.assert(self.transactionQueue.isCurrentExecutionContext(), "Attempted to rollback a \(typeName(self)) outside its designated queue.")
self.context.reset()
}
// MARK: Internal
internal let context: NSManagedObjectContext
internal let transactionQueue: GCDQueue
internal let childTransactionQueue: GCDQueue = .createSerial("com.corestore.datastack.childtransactionqueue")
internal var isCommitted = false
internal var result: SaveResult?
internal init(mainContext: NSManagedObjectContext, queue: GCDQueue) {
self.transactionQueue = queue
let context = mainContext.temporaryContextInTransactionWithConcurrencyType(
queue == .Main
? .MainQueueConcurrencyType
: .PrivateQueueConcurrencyType
)
self.context = context
context.parentTransaction = self
}
}
@@ -1,65 +0,0 @@
//
// CoreStore+Transaction.swift
// CoreStore
//
// Copyright (c) 2015 John Rommel Estropia
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in all
// copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
// SOFTWARE.
//
import Foundation
// MARK: - CoreStore
public extension CoreStore {
// MARK: Public
/**
Using the `defaultStack`, begins a transaction asynchronously where `NSManagedObject` creates, updates, and deletes can be made.
:param: closure the block where creates, updates, and deletes can be made to the transaction. Transaction blocks are executed serially in a background queue, and all changes are made from a concurrent `NSManagedObjectContext`.
*/
public static func beginAsynchronous(closure: (transaction: AsynchronousDataTransaction) -> Void) {
self.defaultStack.beginAsynchronous(closure)
}
/**
Using the `defaultStack`, begins a transaction asynchronously where `NSManagedObject` creates, updates, and deletes can be made.
:param: closure the block where creates, updates, and deletes can be made to the transaction. Transaction blocks are executed serially in a background queue, and all changes are made from a concurrent `NSManagedObjectContext`.
:returns: a `SaveResult` value indicating success or failure, or `nil` if the transaction was not comitted synchronously
*/
public static func beginSynchronous(closure: (transaction: SynchronousDataTransaction) -> Void) -> SaveResult? {
return self.defaultStack.beginSynchronous(closure)
}
/**
Using the `defaultStack`, begins a non-contiguous transaction where `NSManagedObject` creates, updates, and deletes can be made. This is useful for making temporary changes, such as partially filled forms. A detached transaction object should typically be only used from the main queue.
:returns: a `DetachedDataTransaction` instance where creates, updates, and deletes can be made.
*/
public static func beginDetached() -> DetachedDataTransaction {
return self.defaultStack.beginDetached()
}
}
@@ -1,75 +0,0 @@
//
// DataStack+Transaction.swift
// CoreStore
//
// Copyright (c) 2015 John Rommel Estropia
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in all
// copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
// SOFTWARE.
//
import Foundation
import CoreData
import GCDKit
// MARK: - DataStack
public extension DataStack {
// MARK: Public
/**
Begins a transaction asynchronously where `NSManagedObject` creates, updates, and deletes can be made.
:param: closure the block where creates, updates, and deletes can be made to the transaction. Transaction blocks are executed serially in a background queue, and all changes are made from a concurrent `NSManagedObjectContext`.
*/
public func beginAsynchronous(closure: (transaction: AsynchronousDataTransaction) -> Void) {
AsynchronousDataTransaction(
mainContext: self.rootSavingContext,
queue: self.childTransactionQueue,
closure: closure).perform()
}
/**
Begins a transaction synchronously where `NSManagedObject` creates, updates, and deletes can be made.
:param: closure the block where creates, updates, and deletes can be made to the transaction. Transaction blocks are executed serially in a background queue, and all changes are made from a concurrent `NSManagedObjectContext`.
:returns: a `SaveResult` value indicating success or failure, or `nil` if the transaction was not comitted synchronously
*/
public func beginSynchronous(closure: (transaction: SynchronousDataTransaction) -> Void) -> SaveResult? {
return SynchronousDataTransaction(
mainContext: self.rootSavingContext,
queue: self.childTransactionQueue,
closure: closure).performAndWait()
}
/**
Begins a non-contiguous transaction where `NSManagedObject` creates, updates, and deletes can be made. This is useful for making temporary changes, such as partially filled forms. A detached transaction object should typically be only used from the main queue.
:returns: a `DetachedDataTransaction` instance where creates, updates, and deletes can be made.
*/
public func beginDetached() -> DetachedDataTransaction {
return DetachedDataTransaction(
mainContext: self.rootSavingContext,
queue: .Main)
}
}
@@ -1,55 +0,0 @@
//
// DetachedDataTransaction.swift
// CoreStore
//
// Copyright (c) 2015 John Rommel Estropia
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in all
// copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
// SOFTWARE.
//
import Foundation
import GCDKit
// MARK: - DetachedDataTransaction
/**
The `DetachedDataTransaction` provides an interface for non-contiguous `NSManagedObject` creates, updates, and deletes. This is useful for making temporary changes, such as partially filled forms. A detached transaction object should typically be only used from the main queue.
*/
public final class DetachedDataTransaction: BaseDataTransaction {
// MARK: Public
/**
Saves the transaction changes asynchronously. For a `DetachedDataTransaction`, multiple commits are allowed, although it is the developer's responsibility to ensure a reasonable leeway to prevent blocking the main thread.
:param: completion the block executed after the save completes. Success or failure is reported by the `SaveResult` argument of the block.
*/
public func commit(completion: (result: SaveResult) -> Void) {
CoreStore.assert(self.transactionQueue.isCurrentExecutionContext(), "Attempted to commit a \(typeName(self)) outside its designated queue.")
self.context.saveAsynchronouslyWithCompletion { (result) -> Void in
self.result = result
completion(result: result)
}
}
}
@@ -1,112 +0,0 @@
//
// SaveResult.swift
// CoreStore
//
// Copyright (c) 2014 John Rommel Estropia
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in all
// copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
// SOFTWARE.
//
import Foundation
// MARK: - SaveResult
/**
The `SaveResult` indicates the result of a `commit(...)` for a transaction.
The `SaveResult` can be treated as a boolean:
CoreStore.beginAsynchronous { transaction in
// ...
let result = transaction.commit()
if result {
// succeeded
}
else {
// failed
}
}
or as an `enum`, where the resulting associated object can also be inspected:
CoreStore.beginAsynchronous { transaction in
// ...
let result = transaction.commit()
switch result {
case .Success(let hasChanges):
// hasChanges indicates if there were changes or not
case .Failure(let error):
// error is the NSError instance for the failure
}
}
```
*/
public enum SaveResult {
// MARK: Public
/**
`SaveResult.Success` indicates that the `commit()` for the transaction succeeded, either because the save succeeded or because there were no changes to save. The associated value `hasChanges` indicates if there were saved changes or not.
*/
case Success(hasChanges: Bool)
/**
`SaveResult.Failure` indicates that the `commit()` for the transaction failed. The associated object for this value is the related `NSError` instance.
*/
case Failure(NSError)
// MARK: Internal
internal init(hasChanges: Bool) {
self = .Success(hasChanges: hasChanges)
}
internal init(_ error: NSError) {
self = .Failure(error)
}
internal init(_ errorCode: CoreStoreErrorCode) {
self.init(errorCode, userInfo: nil)
}
internal init(_ errorCode: CoreStoreErrorCode, userInfo: [NSObject: AnyObject]?) {
self.init(NSError(
coreStoreErrorCode: errorCode,
userInfo: userInfo))
}
}
// MARK: - SaveResult: BooleanType
extension SaveResult: BooleanType {
public var boolValue: Bool {
switch self {
case .Success: return true
case .Failure: return false
}
}
}
@@ -1,187 +0,0 @@
//
// SynchronousDataTransaction.swift
// CoreStore
//
// Copyright (c) 2015 John Rommel Estropia
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in all
// copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
// SOFTWARE.
//
import Foundation
import CoreData
import GCDKit
// MARK: - SynchronousDataTransaction
/**
The `SynchronousDataTransaction` provides an interface for `NSManagedObject` creates, updates, and deletes. A transaction object should typically be only used from within a transaction block initiated from `DataStack.beginSynchronous(_:)`, or from `CoreStore.beginSynchronous(_:)`.
*/
public final class SynchronousDataTransaction: BaseDataTransaction {
// MARK: Public
/**
Saves the transaction changes and waits for completion synchronously. This method should not be used after the `commit()` method was already called once.
*/
public func commit() {
CoreStore.assert(self.transactionQueue.isCurrentExecutionContext(), "Attempted to commit a \(typeName(self)) outside its designated queue.")
CoreStore.assert(!self.isCommitted, "Attempted to commit a \(typeName(self)) more than once.")
self.isCommitted = true
self.result = self.context.saveSynchronously()
}
/**
Begins a child transaction synchronously where `NSManagedObject` creates, updates, and deletes can be made. This method should not be used after the `commit()` method was already called once.
:param: closure the block where creates, updates, and deletes can be made to the transaction. Transaction blocks are executed serially in a background queue, and all changes are made from a concurrent `NSManagedObjectContext`.
:returns: a `SaveResult` value indicating success or failure, or `nil` if the transaction was not comitted synchronously
*/
public func beginSynchronous(closure: (transaction: SynchronousDataTransaction) -> Void) -> SaveResult? {
CoreStore.assert(self.transactionQueue.isCurrentExecutionContext(), "Attempted to begin a child transaction from a \(typeName(self)) outside its designated queue.")
CoreStore.assert(!self.isCommitted, "Attempted to begin a child transaction from an already committed \(typeName(self)).")
return SynchronousDataTransaction(
mainContext: self.context,
queue: self.childTransactionQueue,
closure: closure).performAndWait()
}
// MARK: BaseDataTransaction
/**
Creates a new `NSManagedObject` with the specified entity type.
:param: into the `Into` clause indicating the destination `NSManagedObject` entity type and the destination configuration
:returns: a new `NSManagedObject` instance of the specified entity type.
*/
public override func create<T: NSManagedObject>(into: Into<T>) -> T {
CoreStore.assert(!self.isCommitted, "Attempted to create an entity of type <\(T.self)> from an already committed \(typeName(self)).")
return super.create(into)
}
/**
Returns an editable proxy of a specified `NSManagedObject`. This method should not be used after the `commit()` method was already called once.
:param: object the `NSManagedObject` type to be edited
:returns: an editable proxy for the specified `NSManagedObject`.
*/
public override func edit<T: NSManagedObject>(object: T?) -> T? {
CoreStore.assert(!self.isCommitted, "Attempted to update an entity of type \(typeName(object)) from an already committed \(typeName(self)).")
return super.edit(object)
}
/**
Returns an editable proxy of the object with the specified `NSManagedObjectID`. This method should not be used after the `commit()` method was already called once.
:param: into an `Into` clause specifying the entity type
:param: objectID the `NSManagedObjectID` for the object to be edited
:returns: an editable proxy for the specified `NSManagedObject`.
*/
public override func edit<T: NSManagedObject>(into: Into<T>, _ objectID: NSManagedObjectID) -> T? {
CoreStore.assert(!self.isCommitted, "Attempted to update an entity of type <\(T.self)> from an already committed \(typeName(self)).")
return super.edit(into, objectID)
}
/**
Deletes a specified `NSManagedObject`. This method should not be used after the `commit()` method was already called once.
:param: object the `NSManagedObject` type to be deleted
*/
public override func delete(object: NSManagedObject?) {
CoreStore.assert(!self.isCommitted, "Attempted to delete an entity of type \(typeName(object)) from an already committed \(typeName(self)).")
super.delete(object)
}
/**
Deletes the specified `NSManagedObject`'s.
:param: object1 the `NSManagedObject` type to be deleted
:param: object2 another `NSManagedObject` type to be deleted
:param: objects other `NSManagedObject`s type to be deleted
*/
public override func delete(object1: NSManagedObject?, _ object2: NSManagedObject?, _ objects: NSManagedObject?...) {
CoreStore.assert(!self.isCommitted, "Attempted to delete an entities from an already committed \(typeName(self)).")
super.delete([object1, object2] + objects)
}
/**
Deletes the specified `NSManagedObject`'s.
:param: objects the `NSManagedObject`'s type to be deleted
*/
public override func delete(objects: [NSManagedObject?]) {
CoreStore.assert(!self.isCommitted, "Attempted to delete an entities from an already committed \(typeName(self)).")
super.delete(objects)
}
/**
Rolls back the transaction by resetting the `NSManagedObjectContext`. After calling this method, all `NSManagedObjects` fetched within the transaction will become invalid. This method should not be used after the `commit()` method was already called once.
*/
public override func rollback() {
CoreStore.assert(!self.isCommitted, "Attempted to rollback an already committed \(typeName(self)).")
super.rollback()
}
// MARK: Internal
internal func performAndWait() -> SaveResult? {
self.transactionQueue.sync {
self.closure(transaction: self)
if !self.isCommitted && self.hasChanges {
CoreStore.log(.Warning, message: "The closure for the \(typeName(self)) completed without being committed. All changes made within the transaction were discarded.")
}
}
return self.result
}
internal init(mainContext: NSManagedObjectContext, queue: GCDQueue, closure: (transaction: SynchronousDataTransaction) -> Void) {
self.closure = closure
super.init(mainContext: mainContext, queue: queue)
}
// MARK: Private
private let closure: (transaction: SynchronousDataTransaction) -> Void
}
@@ -1,84 +0,0 @@
//
// CoreStore+Setup.swift
// CoreStore
//
// Copyright (c) 2015 John Rommel Estropia
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in all
// copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
// SOFTWARE.
//
import Foundation
import CoreData
import GCDKit
// MARK: - CoreStore
public extension CoreStore {
/**
Adds an in-memory store to the `defaultStack`.
:param: configuration an optional configuration name from the model file. If not specified, defaults to nil.
:returns: a `PersistentStoreResult` indicating success or failure.
*/
public static func addInMemoryStore(configuration: String? = nil) -> PersistentStoreResult {
return self.defaultStack.addInMemoryStore(configuration: configuration)
}
/**
Adds to the `defaultStack` an SQLite store from the given SQLite file name.
:param: fileName the local filename for the SQLite persistent store in the "Application Support" directory. A new SQLite file will be created if it does not exist.
:param: configuration an optional configuration name from the model file. If not specified, defaults to nil.
:param: automigrating Set to true to configure Core Data auto-migration, or false to disable. If not specified, defaults to true.
:param: resetStoreOnMigrationFailure Set to true to delete the store on migration failure; or set to false to throw exceptions on failure instead. Typically should only be set to true when debugging, or if the persistent store can be recreated easily. If not specified, defaults to false
:returns: a `PersistentStoreResult` indicating success or failure.
*/
public static func addSQLiteStoreAndWait(fileName: String, configuration: String? = nil, automigrating: Bool = true, resetStoreOnMigrationFailure: Bool = false) -> PersistentStoreResult {
return self.defaultStack.addSQLiteStoreAndWait(
fileName,
configuration: configuration,
automigrating: automigrating,
resetStoreOnMigrationFailure: resetStoreOnMigrationFailure
)
}
/**
Adds to the `defaultStack` an SQLite store from the given SQLite file URL.
:param: fileURL the local file URL for the SQLite persistent store. A new SQLite file will be created if it does not exist. If not specified, defaults to a file URL pointing to a "<Application name>.sqlite" file in the "Application Support" directory.
:param: configuration an optional configuration name from the model file. If not specified, defaults to nil.
:param: automigrating Set to true to configure Core Data auto-migration, or false to disable. If not specified, defaults to true.
:param: resetStoreOnMigrationFailure Set to true to delete the store on migration failure; or set to false to throw exceptions on failure instead. Typically should only be set to true when debugging, or if the persistent store can be recreated easily. If not specified, defaults to false.
:returns: a `PersistentStoreResult` indicating success or failure.
*/
public static func addSQLiteStoreAndWait(fileURL: NSURL = defaultSQLiteStoreURL, configuration: String? = nil, automigrating: Bool = true, resetStoreOnMigrationFailure: Bool = false) -> PersistentStoreResult {
return self.defaultStack.addSQLiteStoreAndWait(
fileURL: fileURL,
configuration: configuration,
automigrating: automigrating,
resetStoreOnMigrationFailure: resetStoreOnMigrationFailure
)
}
}
-361
View File
@@ -1,361 +0,0 @@
//
// DataStack.swift
// CoreStore
//
// Copyright (c) 2014 John Rommel Estropia
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in all
// copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
// SOFTWARE.
//
import Foundation
import CoreData
import GCDKit
internal let applicationSupportDirectory = NSFileManager.defaultManager().URLsForDirectory(.ApplicationSupportDirectory, inDomains: .UserDomainMask).first as! NSURL
internal let applicationName = ((NSBundle.mainBundle().objectForInfoDictionaryKey("CFBundleName") as? String) ?? "CoreData")
internal let defaultSQLiteStoreURL = applicationSupportDirectory.URLByAppendingPathComponent(applicationName, isDirectory: false).URLByAppendingPathExtension("sqlite")
// MARK: - DataStack
/**
The `DataStack` encapsulates the data model for the Core Data stack. Each `DataStack` can have multiple data stores, usually specified as a "Configuration" in the model editor. Behind the scenes, the DataStack manages its own `NSPersistentStoreCoordinator`, a root `NSManagedObjectContext` for disk saves, and a shared `NSManagedObjectContext` designed as a read-only model interface for `NSManagedObjects`.
*/
public final class DataStack {
// MARK: Public
/**
Initializes a `DataStack` from a model created by merging all the models found in all bundles.
*/
public convenience init() {
let mergedModel: NSManagedObjectModel! = NSManagedObjectModel.mergedModelFromBundles(NSBundle.allBundles())
CoreStore.assert(mergedModel != nil, "Could not create a merged <\(NSManagedObjectModel.self)> from all bundles.")
self.init(managedObjectModel: mergedModel)
}
/**
Initializes a `DataStack` from the specified model name.
:param: modelName the name of the (.xcdatamodeld) model file.
*/
public convenience init(modelName: String) {
let modelFilePath: String! = NSBundle.mainBundle().pathForResource(modelName, ofType: "momd")
CoreStore.assert(modelFilePath != nil, "Could not find a \"momd\" resource from the main bundle.")
let managedObjectModel: NSManagedObjectModel! = NSManagedObjectModel(contentsOfURL: NSURL(fileURLWithPath: modelFilePath)!)
CoreStore.assert(managedObjectModel != nil, "Could not create an <\(NSManagedObjectModel.self)> from the resource at path \"\(modelFilePath)\".")
self.init(managedObjectModel: managedObjectModel)
}
/**
Initializes a `DataStack` from an `NSManagedObjectModel`.
:param: managedObjectModel the `NSManagedObjectModel` of the (.xcdatamodeld) model file.
*/
public required init(managedObjectModel: NSManagedObjectModel) {
self.coordinator = NSPersistentStoreCoordinator(managedObjectModel: managedObjectModel)
self.rootSavingContext = NSManagedObjectContext.rootSavingContextForCoordinator(self.coordinator)
self.mainContext = NSManagedObjectContext.mainContextForRootContext(self.rootSavingContext)
var entityNameMapping = [EntityClassNameType: EntityNameType]()
var entityConfigurationsMapping = [EntityClassNameType: Set<String>]()
for entityDescription in managedObjectModel.entities as! [NSEntityDescription] {
let managedObjectClassName = entityDescription.managedObjectClassName
entityConfigurationsMapping[managedObjectClassName] = []
if let entityName = entityDescription.name {
entityNameMapping[managedObjectClassName] = entityName
}
}
self.entityNameMapping = entityNameMapping
self.entityConfigurationsMapping = entityConfigurationsMapping
self.rootSavingContext.parentStack = self
}
/**
Adds an in-memory store to the stack.
:param: configuration an optional configuration name from the model file. If not specified, defaults to nil.
:returns: a `PersistentStoreResult` indicating success or failure.
*/
public func addInMemoryStore(configuration: String? = nil) -> PersistentStoreResult {
let coordinator = self.coordinator;
var error: NSError?
var store: NSPersistentStore?
coordinator.performBlockAndWait {
store = coordinator.addPersistentStoreWithType(
NSInMemoryStoreType,
configuration: configuration,
URL: nil,
options: nil,
error: &error)
}
if let store = store {
self.updateMetadataForPersistentStore(store)
return PersistentStoreResult(store)
}
if let error = error {
CoreStore.handleError(
error,
"Failed to add in-memory <\(NSPersistentStore.self)>.")
return PersistentStoreResult(error)
}
else {
CoreStore.handleError(
NSError(coreStoreErrorCode: .UnknownError),
"Failed to add in-memory <\(NSPersistentStore.self)>.")
return PersistentStoreResult(.UnknownError)
}
}
/**
Adds to the stack an SQLite store from the given SQLite file name.
:param: fileName the local filename for the SQLite persistent store in the "Application Support" directory. A new SQLite file will be created if it does not exist. Note that if you have multiple configurations, you will need to specify a different `fileName` explicitly for each of them.
:param: configuration an optional configuration name from the model file. If not specified, defaults to `nil`, the "Default" configuration. Note that if you have multiple configurations, you will need to specify a different `fileName` explicitly for each of them.
:param: automigrating Set to true to configure Core Data auto-migration, or false to disable. If not specified, defaults to true.
:param: resetStoreOnMigrationFailure Set to true to delete the store on migration failure; or set to false to throw exceptions on failure instead. Typically should only be set to true when debugging, or if the persistent store can be recreated easily. If not specified, defaults to false
:returns: a `PersistentStoreResult` indicating success or failure.
*/
public func addSQLiteStoreAndWait(fileName: String, configuration: String? = nil, automigrating: Bool = true, resetStoreOnMigrationFailure: Bool = false) -> PersistentStoreResult {
return self.addSQLiteStoreAndWait(
fileURL: applicationSupportDirectory.URLByAppendingPathComponent(
fileName,
isDirectory: false
),
configuration: configuration,
automigrating: automigrating,
resetStoreOnMigrationFailure: resetStoreOnMigrationFailure
)
}
/**
Adds to the stack an SQLite store from the given SQLite file URL.
:param: fileURL the local file URL for the SQLite persistent store. A new SQLite file will be created if it does not exist. If not specified, defaults to a file URL pointing to a "<Application name>.sqlite" file in the "Application Support" directory. Note that if you have multiple configurations, you will need to specify a different `fileURL` explicitly for each of them.
:param: configuration an optional configuration name from the model file. If not specified, defaults to `nil`, the "Default" configuration. Note that if you have multiple configurations, you will need to specify a different `fileURL` explicitly for each of them.
:param: automigrating Set to true to configure Core Data auto-migration, or false to disable. If not specified, defaults to true.
:param: resetStoreOnMigrationFailure Set to true to delete the store on migration failure; or set to false to throw exceptions on failure instead. Typically should only be set to true when debugging, or if the persistent store can be recreated easily. If not specified, defaults to false.
:returns: a `PersistentStoreResult` indicating success or failure.
*/
public func addSQLiteStoreAndWait(fileURL: NSURL = defaultSQLiteStoreURL, configuration: String? = nil, automigrating: Bool = true, resetStoreOnMigrationFailure: Bool = false) -> PersistentStoreResult {
let coordinator = self.coordinator;
if let store = coordinator.persistentStoreForURL(fileURL) {
let isExistingStoreAutomigrating = ((store.options?[NSMigratePersistentStoresAutomaticallyOption] as? Bool) ?? false)
if store.type == NSSQLiteStoreType
&& isExistingStoreAutomigrating == automigrating
&& store.configurationName == (configuration ?? Into.defaultConfigurationName) {
return PersistentStoreResult(store)
}
CoreStore.handleError(
NSError(coreStoreErrorCode: .DifferentPersistentStoreExistsAtURL),
"Failed to add SQLite <\(NSPersistentStore.self)> at \"\(fileURL)\" because a different <\(NSPersistentStore.self)> at that URL already exists.")
return PersistentStoreResult(.DifferentPersistentStoreExistsAtURL)
}
let fileManager = NSFileManager.defaultManager()
var directoryError: NSError?
if !fileManager.createDirectoryAtURL(
fileURL.URLByDeletingLastPathComponent!,
withIntermediateDirectories: true,
attributes: nil,
error: &directoryError) {
CoreStore.handleError(
directoryError ?? NSError(coreStoreErrorCode: .UnknownError),
"Failed to create directory for SQLite store at \"\(fileURL)\".")
return PersistentStoreResult(directoryError!)
}
var store: NSPersistentStore?
var persistentStoreError: NSError?
coordinator.performBlockAndWait {
store = coordinator.addPersistentStoreWithType(
NSSQLiteStoreType,
configuration: configuration,
URL: fileURL,
options: [NSSQLitePragmasOption: ["WAL": "journal_mode"],
NSInferMappingModelAutomaticallyOption: true,
NSMigratePersistentStoresAutomaticallyOption: automigrating],
error: &persistentStoreError)
}
if let store = store {
self.updateMetadataForPersistentStore(store)
return PersistentStoreResult(store)
}
if let error = persistentStoreError
where (
resetStoreOnMigrationFailure
&& (error.code == NSPersistentStoreIncompatibleVersionHashError
|| error.code == NSMigrationMissingSourceModelError
|| error.code == NSMigrationError)
&& error.domain == NSCocoaErrorDomain
) {
fileManager.removeItemAtURL(fileURL, error: nil)
fileManager.removeItemAtPath(
fileURL.path!.stringByAppendingString("-shm"),
error: nil)
fileManager.removeItemAtPath(
fileURL.path!.stringByAppendingString("-wal"),
error: nil)
var store: NSPersistentStore?
coordinator.performBlockAndWait {
store = coordinator.addPersistentStoreWithType(
NSSQLiteStoreType,
configuration: configuration,
URL: fileURL,
options: [NSSQLitePragmasOption: ["WAL": "journal_mode"],
NSInferMappingModelAutomaticallyOption: true,
NSMigratePersistentStoresAutomaticallyOption: automigrating],
error: &persistentStoreError)
}
if let store = store {
self.updateMetadataForPersistentStore(store)
return PersistentStoreResult(store)
}
}
CoreStore.handleError(
persistentStoreError ?? NSError(coreStoreErrorCode: .UnknownError),
"Failed to add SQLite <\(NSPersistentStore.self)> at \"\(fileURL)\".")
return PersistentStoreResult(.UnknownError)
}
// MARK: Internal
internal let coordinator: NSPersistentStoreCoordinator
internal let rootSavingContext: NSManagedObjectContext
internal let mainContext: NSManagedObjectContext
internal let childTransactionQueue: GCDQueue = .createSerial("com.corestore.datastack.childtransactionqueue")
internal func entityNameForEntityClass(entityClass: NSManagedObject.Type) -> String? {
return self.entityNameMapping[NSStringFromClass(entityClass)]
}
internal func persistentStoresForEntityClass(entityClass: NSManagedObject.Type) -> [NSPersistentStore]? {
var returnValue: [NSPersistentStore]? = nil
self.storeMetadataUpdateQueue.barrierSync {
let configurationsForEntity = self.entityConfigurationsMapping[NSStringFromClass(entityClass)] ?? []
returnValue = map(configurationsForEntity) {
return self.configurationStoreMapping[$0]!
}
}
return returnValue
}
internal func persistentStoreForEntityClass(entityClass: NSManagedObject.Type, configuration: String?, inferStoreIfPossible: Bool) -> (store: NSPersistentStore?, isAmbiguous: Bool) {
var returnValue: (store: NSPersistentStore?, isAmbiguous: Bool) = (store: nil, isAmbiguous: false)
self.storeMetadataUpdateQueue.barrierSync {
let configurationsForEntity = self.entityConfigurationsMapping[NSStringFromClass(entityClass)] ?? []
if let configuration = configuration {
if configurationsForEntity.contains(configuration) {
returnValue = (store: self.configurationStoreMapping[configuration], isAmbiguous: false)
return
}
else if !inferStoreIfPossible {
return
}
}
switch configurationsForEntity.count {
case 0:
return
case 1 where inferStoreIfPossible:
returnValue = (store: self.configurationStoreMapping[configurationsForEntity.first!], isAmbiguous: false)
default:
returnValue = (store: nil, isAmbiguous: true)
}
}
return returnValue
}
internal func updateMetadataForPersistentStore(persistentStore: NSPersistentStore) {
self.storeMetadataUpdateQueue.barrierAsync {
let configurationName = persistentStore.configurationName
self.configurationStoreMapping[configurationName] = persistentStore
for entityDescription in (self.coordinator.managedObjectModel.entitiesForConfiguration(configurationName) as? [NSEntityDescription] ?? []) {
self.entityConfigurationsMapping[entityDescription.managedObjectClassName]?.insert(configurationName)
}
}
}
// MARK: Private
private typealias EntityClassNameType = String
private typealias EntityNameType = String
private typealias ConfigurationNameType = String
private let entityNameMapping: [EntityClassNameType: EntityNameType]
private let storeMetadataUpdateQueue = GCDQueue.createConcurrent("com.coreStore.persistentStoreBarrierQueue")
private var configurationStoreMapping = [ConfigurationNameType: NSPersistentStore]()
private var entityConfigurationsMapping = [EntityClassNameType: Set<String>]()
}
@@ -1,110 +0,0 @@
//
// PersistentStoreResult.swift
// CoreStore
//
// Copyright (c) 2014 John Rommel Estropia
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in all
// copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
// SOFTWARE.
//
import Foundation
import CoreData
// MARK: - PersistentStoreResult
/**
The `PersistentStoreResult` indicates the result of initializing the persistent store.
The `PersistentStoreResult` can be treated as a boolean:
let result = CoreStore.addSQLiteStoreAndWait()
if result {
// succeeded
}
else {
// failed
}
or as an `enum`, where the resulting associated object can also be inspected:
let result = CoreStore.addSQLiteStoreAndWait()
switch result {
case .Success(let persistentStore):
// persistentStore is the related NSPersistentStore instance
case .Failure(let error):
// error is the NSError instance for the failure
}
```
*/
public enum PersistentStoreResult {
// MARK: Public
/**
`PersistentStoreResult.Success` indicates that the persistent store process succeeded. The associated object for this `enum` value is the related `NSPersistentStore` instance.
*/
case Success(NSPersistentStore)
/**
`PersistentStoreResult.Failure` indicates that the persistent store process failed. The associated object for this value is the related `NSError` instance.
*/
case Failure(NSError)
// MARK: Internal
internal init(_ store: NSPersistentStore) {
self = .Success(store)
}
internal init(_ error: NSError) {
self = .Failure(error)
}
internal init(_ errorCode: CoreStoreErrorCode) {
self.init(errorCode, userInfo: nil)
}
internal init(_ errorCode: CoreStoreErrorCode, userInfo: [NSObject: AnyObject]?) {
self.init(NSError(
coreStoreErrorCode: errorCode,
userInfo: userInfo))
}
}
// MARK: - PersistentStoreResult: BooleanType
extension PersistentStoreResult: BooleanType {
// MARK: Public
public var boolValue: Bool {
switch self {
case .Success: return true
case .Failure: return false
}
}
}
@@ -7,10 +7,11 @@
objects = {
/* Begin PBXBuildFile section */
B503FADF1AFDC71700F90881 /* ObjectListObserverDemoViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = B503FADB1AFDC71700F90881 /* ObjectListObserverDemoViewController.swift */; };
B503FADF1AFDC71700F90881 /* ListObserverDemoViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = B503FADB1AFDC71700F90881 /* ListObserverDemoViewController.swift */; };
B503FAE01AFDC71700F90881 /* ObjectObserverDemoViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = B503FADC1AFDC71700F90881 /* ObjectObserverDemoViewController.swift */; };
B503FAE11AFDC71700F90881 /* Palette.swift in Sources */ = {isa = PBXBuildFile; fileRef = B503FADD1AFDC71700F90881 /* Palette.swift */; };
B503FAE21AFDC71700F90881 /* PaletteTableViewCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = B503FADE1AFDC71700F90881 /* PaletteTableViewCell.swift */; };
B5125C121B521B78003A42C7 /* OrganismV2ToV3.xcmappingmodel in Sources */ = {isa = PBXBuildFile; fileRef = B5125C111B521B78003A42C7 /* OrganismV2ToV3.xcmappingmodel */; };
B52977D91B120B80003D50A5 /* ObserversViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = B52977D81B120B80003D50A5 /* ObserversViewController.swift */; };
B52977DD1B120F3B003D50A5 /* TransactionsDemoViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = B52977DC1B120F3B003D50A5 /* TransactionsDemoViewController.swift */; };
B52977DF1B120F83003D50A5 /* MapKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = B52977DE1B120F83003D50A5 /* MapKit.framework */; };
@@ -21,63 +22,36 @@
B54AAD591AF4D26E00848AE0 /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = B54AAD571AF4D26E00848AE0 /* Main.storyboard */; };
B54AAD5B1AF4D26E00848AE0 /* Images.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = B54AAD5A1AF4D26E00848AE0 /* Images.xcassets */; };
B54AAD5E1AF4D26E00848AE0 /* LaunchScreen.xib in Resources */ = {isa = PBXBuildFile; fileRef = B54AAD5C1AF4D26E00848AE0 /* LaunchScreen.xib */; };
B560070F1B3EC90F00A9A8F9 /* OrganismV2ToV3MigrationPolicy.swift in Sources */ = {isa = PBXBuildFile; fileRef = B560070E1B3EC90F00A9A8F9 /* OrganismV2ToV3MigrationPolicy.swift */; };
B566E32A1B117B1F00F4F0C6 /* StackSetupDemoViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = B566E3291B117B1F00F4F0C6 /* StackSetupDemoViewController.swift */; };
B566E3321B11DF3200F4F0C6 /* UserAccount.swift in Sources */ = {isa = PBXBuildFile; fileRef = B566E3311B11DF3200F4F0C6 /* UserAccount.swift */; };
B56964C91B20AC780075EE4A /* CustomLoggerViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = B56964C81B20AC780075EE4A /* CustomLoggerViewController.swift */; };
B56964D71B231AE90075EE4A /* StackSetupDemo.xcdatamodeld in Sources */ = {isa = PBXBuildFile; fileRef = B56964D51B231AE90075EE4A /* StackSetupDemo.xcdatamodeld */; };
B56964DA1B231BCA0075EE4A /* MaleAccount.swift in Sources */ = {isa = PBXBuildFile; fileRef = B56964D91B231BCA0075EE4A /* MaleAccount.swift */; };
B56964DC1B231BCB0075EE4A /* FemaleAccount.swift in Sources */ = {isa = PBXBuildFile; fileRef = B56964DB1B231BCB0075EE4A /* FemaleAccount.swift */; };
B56964DF1B2321E30075EE4A /* MigrationDemo.xcdatamodeld in Sources */ = {isa = PBXBuildFile; fileRef = B56964DD1B2321E30075EE4A /* MigrationDemo.xcdatamodeld */; };
B569650C1B2B36E10075EE4A /* FetchingAndQueryingDemoViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = B569650B1B2B36E10075EE4A /* FetchingAndQueryingDemoViewController.swift */; };
B56965181B2E20CC0075EE4A /* TimeZone.swift in Sources */ = {isa = PBXBuildFile; fileRef = B56965171B2E20CC0075EE4A /* TimeZone.swift */; };
B569651A1B30888A0075EE4A /* FetchingResultsViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = B56965191B30888A0075EE4A /* FetchingResultsViewController.swift */; };
B569651C1B30889A0075EE4A /* QueryingResultsViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = B569651B1B30889A0075EE4A /* QueryingResultsViewController.swift */; };
B583A9201AF5F542001F76AF /* CoreStore.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = B583A91B1AF5F4F4001F76AF /* CoreStore.framework */; };
B583A9211AF5F542001F76AF /* CoreStore.framework in Embed Frameworks */ = {isa = PBXBuildFile; fileRef = B583A91B1AF5F4F4001F76AF /* CoreStore.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; };
B5D9C9191B20AB1900E64F0E /* GCDKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = B5D9C9181B20AB1900E64F0E /* GCDKit.framework */; };
B5D9C91A1B20AB1900E64F0E /* GCDKit.framework in Embed Frameworks */ = {isa = PBXBuildFile; fileRef = B5D9C9181B20AB1900E64F0E /* GCDKit.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; };
B56965291B3582D30075EE4A /* MigrationDemo.xcdatamodeld in Sources */ = {isa = PBXBuildFile; fileRef = B56965271B3582D30075EE4A /* MigrationDemo.xcdatamodeld */; };
B5E599321B5240F50084BD5F /* OrganismTableViewCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = B5E599311B5240F50084BD5F /* OrganismTableViewCell.swift */; };
B5E89AD01C5292A2003B04A9 /* CoreStore.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = B5BDC9211C202429008147CD /* CoreStore.framework */; };
B5E89AD11C5292A2003B04A9 /* CoreStore.framework in Embed Frameworks */ = {isa = PBXBuildFile; fileRef = B5BDC9211C202429008147CD /* CoreStore.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; };
B5EE25851B36E23C0000406B /* OrganismV1.swift in Sources */ = {isa = PBXBuildFile; fileRef = B5EE25841B36E23C0000406B /* OrganismV1.swift */; };
B5EE25871B36E2520000406B /* OrganismV2.swift in Sources */ = {isa = PBXBuildFile; fileRef = B5EE25861B36E2520000406B /* OrganismV2.swift */; };
B5EE258C1B36E40D0000406B /* MigrationsDemoViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = B5EE258B1B36E40D0000406B /* MigrationsDemoViewController.swift */; };
B5EE259B1B3EA4890000406B /* OrganismV3.swift in Sources */ = {isa = PBXBuildFile; fileRef = B5EE259A1B3EA4890000406B /* OrganismV3.swift */; };
B5EE259E1B3EC1B20000406B /* OrganismProtocol.swift in Sources */ = {isa = PBXBuildFile; fileRef = B5EE259D1B3EC1B20000406B /* OrganismProtocol.swift */; };
/* End PBXBuildFile section */
/* Begin PBXContainerItemProxy section */
B583A91A1AF5F4F4001F76AF /* PBXContainerItemProxy */ = {
isa = PBXContainerItemProxy;
containerPortal = B583A9141AF5F4F3001F76AF /* CoreStore.xcodeproj */;
proxyType = 2;
remoteGlobalIDString = 2F03A53019C5C6DA005002A5;
remoteInfo = CoreStore;
};
B583A91C1AF5F4F4001F76AF /* PBXContainerItemProxy */ = {
isa = PBXContainerItemProxy;
containerPortal = B583A9141AF5F4F3001F76AF /* CoreStore.xcodeproj */;
proxyType = 2;
remoteGlobalIDString = 2F03A53B19C5C6DA005002A5;
remoteInfo = CoreStoreTests;
};
B583A91E1AF5F512001F76AF /* PBXContainerItemProxy */ = {
isa = PBXContainerItemProxy;
containerPortal = B583A9141AF5F4F3001F76AF /* CoreStore.xcodeproj */;
proxyType = 1;
remoteGlobalIDString = 2F03A52F19C5C6DA005002A5;
remoteInfo = CoreStore;
};
B583A9221AF5F542001F76AF /* PBXContainerItemProxy */ = {
isa = PBXContainerItemProxy;
containerPortal = B583A9141AF5F4F3001F76AF /* CoreStore.xcodeproj */;
proxyType = 1;
remoteGlobalIDString = 2F03A52F19C5C6DA005002A5;
remoteInfo = CoreStore;
};
/* End PBXContainerItemProxy section */
/* Begin PBXCopyFilesBuildPhase section */
B583A9241AF5F542001F76AF /* Embed Frameworks */ = {
B5E89ACF1C52929C003B04A9 /* Embed Frameworks */ = {
isa = PBXCopyFilesBuildPhase;
buildActionMask = 2147483647;
dstPath = "";
dstSubfolderSpec = 10;
files = (
B5D9C91A1B20AB1900E64F0E /* GCDKit.framework in Embed Frameworks */,
B583A9211AF5F542001F76AF /* CoreStore.framework in Embed Frameworks */,
B5E89AD11C5292A2003B04A9 /* CoreStore.framework in Embed Frameworks */,
);
name = "Embed Frameworks";
runOnlyForDeploymentPostprocessing = 0;
@@ -85,10 +59,12 @@
/* End PBXCopyFilesBuildPhase section */
/* Begin PBXFileReference section */
B503FADB1AFDC71700F90881 /* ObjectListObserverDemoViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ObjectListObserverDemoViewController.swift; sourceTree = "<group>"; };
B503FADB1AFDC71700F90881 /* ListObserverDemoViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ListObserverDemoViewController.swift; sourceTree = "<group>"; };
B503FADC1AFDC71700F90881 /* ObjectObserverDemoViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ObjectObserverDemoViewController.swift; sourceTree = "<group>"; };
B503FADD1AFDC71700F90881 /* Palette.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Palette.swift; sourceTree = "<group>"; };
B503FADE1AFDC71700F90881 /* PaletteTableViewCell.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = PaletteTableViewCell.swift; sourceTree = "<group>"; };
B5125C111B521B78003A42C7 /* OrganismV2ToV3.xcmappingmodel */ = {isa = PBXFileReference; lastKnownFileType = wrapper.xcmappingmodel; path = OrganismV2ToV3.xcmappingmodel; sourceTree = "<group>"; };
B5125C131B521BA7003A42C7 /* OrganismV3ToV2.xcmappingmodel */ = {isa = PBXFileReference; lastKnownFileType = wrapper.xcmappingmodel; path = OrganismV3ToV2.xcmappingmodel; sourceTree = "<group>"; };
B52977D81B120B80003D50A5 /* ObserversViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ObserversViewController.swift; sourceTree = "<group>"; };
B52977DC1B120F3B003D50A5 /* TransactionsDemoViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = TransactionsDemoViewController.swift; sourceTree = "<group>"; };
B52977DE1B120F83003D50A5 /* MapKit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = MapKit.framework; path = System/Library/Frameworks/MapKit.framework; sourceTree = SDKROOT; };
@@ -101,20 +77,27 @@
B54AAD581AF4D26E00848AE0 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/Main.storyboard; sourceTree = "<group>"; };
B54AAD5A1AF4D26E00848AE0 /* Images.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Images.xcassets; sourceTree = "<group>"; };
B54AAD5D1AF4D26E00848AE0 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.xib; name = Base; path = Base.lproj/LaunchScreen.xib; sourceTree = "<group>"; };
B560070E1B3EC90F00A9A8F9 /* OrganismV2ToV3MigrationPolicy.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = OrganismV2ToV3MigrationPolicy.swift; sourceTree = "<group>"; };
B566E3291B117B1F00F4F0C6 /* StackSetupDemoViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = StackSetupDemoViewController.swift; sourceTree = "<group>"; };
B566E3311B11DF3200F4F0C6 /* UserAccount.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = UserAccount.swift; sourceTree = "<group>"; };
B56964C81B20AC780075EE4A /* CustomLoggerViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = CustomLoggerViewController.swift; sourceTree = "<group>"; };
B56964D61B231AE90075EE4A /* StackSetupDemo.xcdatamodel */ = {isa = PBXFileReference; lastKnownFileType = wrapper.xcdatamodel; path = StackSetupDemo.xcdatamodel; sourceTree = "<group>"; };
B56964D91B231BCA0075EE4A /* MaleAccount.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = MaleAccount.swift; sourceTree = "<group>"; };
B56964DB1B231BCB0075EE4A /* FemaleAccount.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = FemaleAccount.swift; sourceTree = "<group>"; };
B56964DE1B2321E30075EE4A /* MigrationDemo.xcdatamodel */ = {isa = PBXFileReference; lastKnownFileType = wrapper.xcdatamodel; path = MigrationDemo.xcdatamodel; sourceTree = "<group>"; };
B56964E01B2326F30075EE4A /* MigrationDemoV2.xcdatamodel */ = {isa = PBXFileReference; lastKnownFileType = wrapper.xcdatamodel; path = MigrationDemoV2.xcdatamodel; sourceTree = "<group>"; };
B569650B1B2B36E10075EE4A /* FetchingAndQueryingDemoViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = FetchingAndQueryingDemoViewController.swift; sourceTree = "<group>"; };
B56965171B2E20CC0075EE4A /* TimeZone.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = TimeZone.swift; sourceTree = "<group>"; };
B56965191B30888A0075EE4A /* FetchingResultsViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = FetchingResultsViewController.swift; sourceTree = "<group>"; };
B569651B1B30889A0075EE4A /* QueryingResultsViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = QueryingResultsViewController.swift; sourceTree = "<group>"; };
B583A9141AF5F4F3001F76AF /* CoreStore.xcodeproj */ = {isa = PBXFileReference; lastKnownFileType = "wrapper.pb-project"; name = CoreStore.xcodeproj; path = ../CoreStore.xcodeproj; sourceTree = "<group>"; };
B5D9C9181B20AB1900E64F0E /* GCDKit.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; path = GCDKit.framework; sourceTree = BUILT_PRODUCTS_DIR; };
B56965281B3582D30075EE4A /* MigrationDemo.xcdatamodel */ = {isa = PBXFileReference; lastKnownFileType = wrapper.xcdatamodel; path = MigrationDemo.xcdatamodel; sourceTree = "<group>"; };
B5BDC9211C202429008147CD /* CoreStore.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; path = CoreStore.framework; sourceTree = BUILT_PRODUCTS_DIR; };
B5E599311B5240F50084BD5F /* OrganismTableViewCell.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = OrganismTableViewCell.swift; path = "CoreStoreDemo/MIgrations Demo/OrganismTableViewCell.swift"; sourceTree = SOURCE_ROOT; };
B5EE25801B36E1B00000406B /* MigrationDemoV2.xcdatamodel */ = {isa = PBXFileReference; lastKnownFileType = wrapper.xcdatamodel; path = MigrationDemoV2.xcdatamodel; sourceTree = "<group>"; };
B5EE25841B36E23C0000406B /* OrganismV1.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = OrganismV1.swift; sourceTree = "<group>"; };
B5EE25861B36E2520000406B /* OrganismV2.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = OrganismV2.swift; sourceTree = "<group>"; };
B5EE25881B36E2750000406B /* MigrationDemoV3.xcdatamodel */ = {isa = PBXFileReference; lastKnownFileType = wrapper.xcdatamodel; path = MigrationDemoV3.xcdatamodel; sourceTree = "<group>"; };
B5EE258B1B36E40D0000406B /* MigrationsDemoViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = MigrationsDemoViewController.swift; sourceTree = "<group>"; };
B5EE259A1B3EA4890000406B /* OrganismV3.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = OrganismV3.swift; sourceTree = "<group>"; };
B5EE259D1B3EC1B20000406B /* OrganismProtocol.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = OrganismProtocol.swift; sourceTree = "<group>"; };
/* End PBXFileReference section */
/* Begin PBXFrameworksBuildPhase section */
@@ -122,10 +105,9 @@
isa = PBXFrameworksBuildPhase;
buildActionMask = 2147483647;
files = (
B5E89AD01C5292A2003B04A9 /* CoreStore.framework in Frameworks */,
B52977E11B120F8A003D50A5 /* CoreLocation.framework in Frameworks */,
B52977DF1B120F83003D50A5 /* MapKit.framework in Frameworks */,
B5D9C9191B20AB1900E64F0E /* GCDKit.framework in Frameworks */,
B583A9201AF5F542001F76AF /* CoreStore.framework in Frameworks */,
);
runOnlyForDeploymentPostprocessing = 0;
};
@@ -136,7 +118,7 @@
isa = PBXGroup;
children = (
B52977D81B120B80003D50A5 /* ObserversViewController.swift */,
B503FADB1AFDC71700F90881 /* ObjectListObserverDemoViewController.swift */,
B503FADB1AFDC71700F90881 /* ListObserverDemoViewController.swift */,
B503FADC1AFDC71700F90881 /* ObjectObserverDemoViewController.swift */,
B503FADD1AFDC71700F90881 /* Palette.swift */,
B503FADE1AFDC71700F90881 /* PaletteTableViewCell.swift */,
@@ -156,9 +138,8 @@
B52977E21B120F90003D50A5 /* Frameworks */ = {
isa = PBXGroup;
children = (
B583A9141AF5F4F3001F76AF /* CoreStore.xcodeproj */,
B5D9C9181B20AB1900E64F0E /* GCDKit.framework */,
B52977E01B120F8A003D50A5 /* CoreLocation.framework */,
B5BDC9211C202429008147CD /* CoreStore.framework */,
B52977DE1B120F83003D50A5 /* MapKit.framework */,
);
name = Frameworks;
@@ -189,13 +170,14 @@
B503FADA1AFDC71700F90881 /* List and Object Observers Demo */,
B52977DB1B120F2C003D50A5 /* Transactions Demo */,
B56965091B2B35370075EE4A /* Fetching and Querying Demo */,
B569652F1B3591460075EE4A /* Migrations Demo */,
B56964C61B20AC200075EE4A /* Loggers Demo */,
B54AAD571AF4D26E00848AE0 /* Main.storyboard */,
B54AAD5A1AF4D26E00848AE0 /* Images.xcassets */,
B54AAD5C1AF4D26E00848AE0 /* LaunchScreen.xib */,
B54AAD501AF4D26E00848AE0 /* CoreStoreDemo.xcdatamodeld */,
B56964D51B231AE90075EE4A /* StackSetupDemo.xcdatamodeld */,
B56964DD1B2321E30075EE4A /* MigrationDemo.xcdatamodeld */,
B56965271B3582D30075EE4A /* MigrationDemo.xcdatamodeld */,
B54AAD4C1AF4D26E00848AE0 /* Supporting Files */,
);
path = CoreStoreDemo;
@@ -239,13 +221,20 @@
path = "Fetching and Querying Demo";
sourceTree = "<group>";
};
B583A9151AF5F4F3001F76AF /* Products */ = {
B569652F1B3591460075EE4A /* Migrations Demo */ = {
isa = PBXGroup;
children = (
B583A91B1AF5F4F4001F76AF /* CoreStore.framework */,
B583A91D1AF5F4F4001F76AF /* CoreStoreTests.xctest */,
B5EE259D1B3EC1B20000406B /* OrganismProtocol.swift */,
B5EE259A1B3EA4890000406B /* OrganismV3.swift */,
B5EE25861B36E2520000406B /* OrganismV2.swift */,
B5EE25841B36E23C0000406B /* OrganismV1.swift */,
B5EE258B1B36E40D0000406B /* MigrationsDemoViewController.swift */,
B5E599311B5240F50084BD5F /* OrganismTableViewCell.swift */,
B5125C111B521B78003A42C7 /* OrganismV2ToV3.xcmappingmodel */,
B560070E1B3EC90F00A9A8F9 /* OrganismV2ToV3MigrationPolicy.swift */,
B5125C131B521BA7003A42C7 /* OrganismV3ToV2.xcmappingmodel */,
);
name = Products;
path = "Migrations Demo";
sourceTree = "<group>";
};
/* End PBXGroup section */
@@ -258,13 +247,11 @@
B54AAD451AF4D26E00848AE0 /* Sources */,
B54AAD461AF4D26E00848AE0 /* Frameworks */,
B54AAD471AF4D26E00848AE0 /* Resources */,
B583A9241AF5F542001F76AF /* Embed Frameworks */,
B5E89ACF1C52929C003B04A9 /* Embed Frameworks */,
);
buildRules = (
);
dependencies = (
B583A91F1AF5F512001F76AF /* PBXTargetDependency */,
B583A9231AF5F542001F76AF /* PBXTargetDependency */,
);
name = CoreStoreDemo;
productName = CoreStoreDemo;
@@ -277,11 +264,13 @@
B54AAD411AF4D26E00848AE0 /* Project object */ = {
isa = PBXProject;
attributes = {
LastUpgradeCheck = 0630;
LastSwiftUpdateCheck = 0700;
LastUpgradeCheck = 0800;
ORGANIZATIONNAME = "John Rommel Estropia";
TargetAttributes = {
B54AAD481AF4D26E00848AE0 = {
CreatedOnToolsVersion = 6.3;
LastSwiftMigration = 0800;
};
};
};
@@ -296,12 +285,6 @@
mainGroup = B54AAD401AF4D26E00848AE0;
productRefGroup = B54AAD4A1AF4D26E00848AE0 /* Products */;
projectDirPath = "";
projectReferences = (
{
ProductGroup = B583A9151AF5F4F3001F76AF /* Products */;
ProjectRef = B583A9141AF5F4F3001F76AF /* CoreStore.xcodeproj */;
},
);
projectRoot = "";
targets = (
B54AAD481AF4D26E00848AE0 /* CoreStoreDemo */,
@@ -309,23 +292,6 @@
};
/* End PBXProject section */
/* Begin PBXReferenceProxy section */
B583A91B1AF5F4F4001F76AF /* CoreStore.framework */ = {
isa = PBXReferenceProxy;
fileType = wrapper.framework;
path = CoreStore.framework;
remoteRef = B583A91A1AF5F4F4001F76AF /* PBXContainerItemProxy */;
sourceTree = BUILT_PRODUCTS_DIR;
};
B583A91D1AF5F4F4001F76AF /* CoreStoreTests.xctest */ = {
isa = PBXReferenceProxy;
fileType = wrapper.cfbundle;
path = CoreStoreTests.xctest;
remoteRef = B583A91C1AF5F4F4001F76AF /* PBXContainerItemProxy */;
sourceTree = BUILT_PRODUCTS_DIR;
};
/* End PBXReferenceProxy section */
/* Begin PBXResourcesBuildPhase section */
B54AAD471AF4D26E00848AE0 /* Resources */ = {
isa = PBXResourcesBuildPhase;
@@ -345,11 +311,14 @@
buildActionMask = 2147483647;
files = (
B56965181B2E20CC0075EE4A /* TimeZone.swift in Sources */,
B56965291B3582D30075EE4A /* MigrationDemo.xcdatamodeld in Sources */,
B5E599321B5240F50084BD5F /* OrganismTableViewCell.swift in Sources */,
B5EE25851B36E23C0000406B /* OrganismV1.swift in Sources */,
B52977DD1B120F3B003D50A5 /* TransactionsDemoViewController.swift in Sources */,
B56964DF1B2321E30075EE4A /* MigrationDemo.xcdatamodeld in Sources */,
B52977E41B121635003D50A5 /* Place.swift in Sources */,
B569650C1B2B36E10075EE4A /* FetchingAndQueryingDemoViewController.swift in Sources */,
B569651A1B30888A0075EE4A /* FetchingResultsViewController.swift in Sources */,
B5EE25871B36E2520000406B /* OrganismV2.swift in Sources */,
B503FAE01AFDC71700F90881 /* ObjectObserverDemoViewController.swift in Sources */,
B52977D91B120B80003D50A5 /* ObserversViewController.swift in Sources */,
B56964C91B20AC780075EE4A /* CustomLoggerViewController.swift in Sources */,
@@ -357,31 +326,23 @@
B56964DA1B231BCA0075EE4A /* MaleAccount.swift in Sources */,
B566E3321B11DF3200F4F0C6 /* UserAccount.swift in Sources */,
B54AAD521AF4D26E00848AE0 /* CoreStoreDemo.xcdatamodeld in Sources */,
B5EE259B1B3EA4890000406B /* OrganismV3.swift in Sources */,
B503FAE11AFDC71700F90881 /* Palette.swift in Sources */,
B503FAE21AFDC71700F90881 /* PaletteTableViewCell.swift in Sources */,
B503FADF1AFDC71700F90881 /* ObjectListObserverDemoViewController.swift in Sources */,
B560070F1B3EC90F00A9A8F9 /* OrganismV2ToV3MigrationPolicy.swift in Sources */,
B503FADF1AFDC71700F90881 /* ListObserverDemoViewController.swift in Sources */,
B54AAD4F1AF4D26E00848AE0 /* AppDelegate.swift in Sources */,
B56964D71B231AE90075EE4A /* StackSetupDemo.xcdatamodeld in Sources */,
B56964DC1B231BCB0075EE4A /* FemaleAccount.swift in Sources */,
B5EE259E1B3EC1B20000406B /* OrganismProtocol.swift in Sources */,
B5EE258C1B36E40D0000406B /* MigrationsDemoViewController.swift in Sources */,
B569651C1B30889A0075EE4A /* QueryingResultsViewController.swift in Sources */,
B5125C121B521B78003A42C7 /* OrganismV2ToV3.xcmappingmodel in Sources */,
);
runOnlyForDeploymentPostprocessing = 0;
};
/* End PBXSourcesBuildPhase section */
/* Begin PBXTargetDependency section */
B583A91F1AF5F512001F76AF /* PBXTargetDependency */ = {
isa = PBXTargetDependency;
name = CoreStore;
targetProxy = B583A91E1AF5F512001F76AF /* PBXContainerItemProxy */;
};
B583A9231AF5F542001F76AF /* PBXTargetDependency */ = {
isa = PBXTargetDependency;
name = CoreStore;
targetProxy = B583A9221AF5F542001F76AF /* PBXContainerItemProxy */;
};
/* End PBXTargetDependency section */
/* Begin PBXVariantGroup section */
B54AAD571AF4D26E00848AE0 /* Main.storyboard */ = {
isa = PBXVariantGroup;
@@ -415,14 +376,17 @@
CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
CLANG_WARN_EMPTY_BODY = YES;
CLANG_WARN_ENUM_CONVERSION = YES;
CLANG_WARN_INFINITE_RECURSION = YES;
CLANG_WARN_INT_CONVERSION = YES;
CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
CLANG_WARN_SUSPICIOUS_MOVE = YES;
CLANG_WARN_UNREACHABLE_CODE = YES;
CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
"CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer";
COPY_PHASE_STRIP = NO;
DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
ENABLE_STRICT_OBJC_MSGSEND = YES;
ENABLE_TESTABILITY = YES;
GCC_C_LANGUAGE_STANDARD = gnu99;
GCC_DYNAMIC_NO_PIC = NO;
GCC_NO_COMMON_BLOCKS = YES;
@@ -438,7 +402,7 @@
GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
GCC_WARN_UNUSED_FUNCTION = YES;
GCC_WARN_UNUSED_VARIABLE = YES;
IPHONEOS_DEPLOYMENT_TARGET = 8.3;
IPHONEOS_DEPLOYMENT_TARGET = 8.0;
MTL_ENABLE_DEBUG_INFO = YES;
ONLY_ACTIVE_ARCH = YES;
SDKROOT = iphoneos;
@@ -459,8 +423,10 @@
CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
CLANG_WARN_EMPTY_BODY = YES;
CLANG_WARN_ENUM_CONVERSION = YES;
CLANG_WARN_INFINITE_RECURSION = YES;
CLANG_WARN_INT_CONVERSION = YES;
CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
CLANG_WARN_SUSPICIOUS_MOVE = YES;
CLANG_WARN_UNREACHABLE_CODE = YES;
CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
"CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer";
@@ -476,7 +442,7 @@
GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
GCC_WARN_UNUSED_FUNCTION = YES;
GCC_WARN_UNUSED_VARIABLE = YES;
IPHONEOS_DEPLOYMENT_TARGET = 8.3;
IPHONEOS_DEPLOYMENT_TARGET = 8.0;
MTL_ENABLE_DEBUG_INFO = NO;
SDKROOT = iphoneos;
VALIDATE_PRODUCT = YES;
@@ -487,15 +453,12 @@
isa = XCBuildConfiguration;
buildSettings = {
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
FRAMEWORK_SEARCH_PATHS = (
"$(inherited)",
"$(USER_LIBRARY_DIR)/Developer/Xcode/DerivedData/CoreStoreDemo-ftknhsqfpsthfogvisxisgpbbhsj/Build/Products/Debug-iphoneos",
"$(USER_LIBRARY_DIR)/Developer/Xcode/DerivedData/CoreStoreDemo-bnajhooxbfnxepepdtkvkfplrqyq/Build/Products/Debug-iphoneos",
);
INFOPLIST_FILE = CoreStoreDemo/Info.plist;
IPHONEOS_DEPLOYMENT_TARGET = 8.0;
LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks";
PRODUCT_BUNDLE_IDENTIFIER = com.johnestropia.corestore.demo;
PRODUCT_NAME = "$(TARGET_NAME)";
SWIFT_VERSION = 3.0;
};
name = Debug;
};
@@ -503,15 +466,13 @@
isa = XCBuildConfiguration;
buildSettings = {
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
FRAMEWORK_SEARCH_PATHS = (
"$(inherited)",
"$(USER_LIBRARY_DIR)/Developer/Xcode/DerivedData/CoreStoreDemo-ftknhsqfpsthfogvisxisgpbbhsj/Build/Products/Debug-iphoneos",
"$(USER_LIBRARY_DIR)/Developer/Xcode/DerivedData/CoreStoreDemo-bnajhooxbfnxepepdtkvkfplrqyq/Build/Products/Debug-iphoneos",
);
INFOPLIST_FILE = CoreStoreDemo/Info.plist;
IPHONEOS_DEPLOYMENT_TARGET = 8.0;
LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks";
PRODUCT_BUNDLE_IDENTIFIER = com.johnestropia.corestore.demo;
PRODUCT_NAME = "$(TARGET_NAME)";
SWIFT_OPTIMIZATION_LEVEL = "-Owholemodule";
SWIFT_VERSION = 3.0;
};
name = Release;
};
@@ -559,13 +520,14 @@
sourceTree = "<group>";
versionGroupType = wrapper.xcdatamodel;
};
B56964DD1B2321E30075EE4A /* MigrationDemo.xcdatamodeld */ = {
B56965271B3582D30075EE4A /* MigrationDemo.xcdatamodeld */ = {
isa = XCVersionGroup;
children = (
B56964E01B2326F30075EE4A /* MigrationDemoV2.xcdatamodel */,
B56964DE1B2321E30075EE4A /* MigrationDemo.xcdatamodel */,
B5EE25881B36E2750000406B /* MigrationDemoV3.xcdatamodel */,
B5EE25801B36E1B00000406B /* MigrationDemoV2.xcdatamodel */,
B56965281B3582D30075EE4A /* MigrationDemo.xcdatamodel */,
);
currentVersion = B56964E01B2326F30075EE4A /* MigrationDemoV2.xcdatamodel */;
currentVersion = B5EE25881B36E2750000406B /* MigrationDemoV3.xcdatamodel */;
path = MigrationDemo.xcdatamodeld;
sourceTree = "<group>";
versionGroupType = wrapper.xcdatamodel;
@@ -0,0 +1,10 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>HasAskedToTakeAutomaticSnapshotBeforeSignificantChanges</key>
<true/>
<key>SnapshotAutomaticallyBeforeSignificantChanges</key>
<true/>
</dict>
</plist>
@@ -1,7 +1,7 @@
<?xml version="1.0" encoding="UTF-8"?>
<Scheme
LastUpgradeVersion = "0630"
version = "1.8">
LastUpgradeVersion = "0800"
version = "1.3">
<BuildAction
parallelizeBuildables = "YES"
buildImplicitDependencies = "YES">
@@ -23,10 +23,10 @@
</BuildActionEntries>
</BuildAction>
<TestAction
buildConfiguration = "Debug"
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
shouldUseLaunchSchemeArgsEnv = "YES"
buildConfiguration = "Debug">
shouldUseLaunchSchemeArgsEnv = "YES">
<Testables>
</Testables>
<MacroExpansion>
@@ -42,11 +42,11 @@
</AdditionalOptions>
</TestAction>
<LaunchAction
buildConfiguration = "Debug"
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
launchStyle = "0"
useCustomWorkingDirectory = "NO"
buildConfiguration = "Debug"
ignoresPersistentStateOnLaunch = "NO"
debugDocumentVersioning = "YES"
debugServiceExtension = "internal"
@@ -65,10 +65,10 @@
</AdditionalOptions>
</LaunchAction>
<ProfileAction
buildConfiguration = "Release"
shouldUseLaunchSchemeArgsEnv = "YES"
savedToolIdentifier = ""
useCustomWorkingDirectory = "NO"
buildConfiguration = "Release"
debugDocumentVersioning = "YES">
<BuildableProductRunnable
runnableDebuggingMode = "0">
@@ -1,39 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<Bucket
type = "1"
version = "2.0">
<Breakpoints>
<BreakpointProxy
BreakpointExtensionID = "Xcode.Breakpoint.FileBreakpoint">
<BreakpointContent
shouldBeEnabled = "Yes"
ignoreCount = "0"
continueAfterRunningActions = "No"
filePath = "../CoreStore/Migrating/DataStack+Migration.swift"
timestampString = "457102815.005196"
startingColumnNumber = "9223372036854775807"
endingColumnNumber = "9223372036854775807"
startingLineNumber = "80"
endingLineNumber = "80"
landmarkName = "needsMigrationForSQLiteStore(fileURL:configuration:)"
landmarkType = "5">
</BreakpointContent>
</BreakpointProxy>
<BreakpointProxy
BreakpointExtensionID = "Xcode.Breakpoint.FileBreakpoint">
<BreakpointContent
shouldBeEnabled = "Yes"
ignoreCount = "0"
continueAfterRunningActions = "No"
filePath = "../CoreStore/Migrating/DataStack+Migration.swift"
timestampString = "457102823.242858"
startingColumnNumber = "9223372036854775807"
endingColumnNumber = "9223372036854775807"
startingLineNumber = "165"
endingLineNumber = "165"
landmarkName = "upgradeSQLiteStoreIfNeeded(fileURL:configuration:completion:)"
landmarkType = "5">
</BreakpointContent>
</BreakpointProxy>
</Breakpoints>
</Bucket>
@@ -3,11 +3,12 @@
// CoreStoreDemo
//
// Created by John Rommel Estropia on 2015/05/02.
// Copyright (c) 2015 John Rommel Estropia. All rights reserved.
// Copyright © 2015 John Rommel Estropia. All rights reserved.
//
import UIKit
import CoreStore
// MARK: - AppDelegate
@@ -18,9 +19,9 @@ class AppDelegate: UIResponder, UIApplicationDelegate {
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
}
}
@@ -1,7 +1,8 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<document type="com.apple.InterfaceBuilder3.CocoaTouch.XIB" version="3.0" toolsVersion="7706" systemVersion="14D136" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" launchScreen="YES" useTraitCollections="YES">
<document type="com.apple.InterfaceBuilder3.CocoaTouch.XIB" version="3.0" toolsVersion="10112" systemVersion="15D21" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" launchScreen="YES" useTraitCollections="YES">
<dependencies>
<plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="7703"/>
<deployment identifier="iOS"/>
<plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="10083"/>
<capability name="Constraints with non-1.0 multipliers" minToolsVersion="5.1"/>
</dependencies>
<objects>
@@ -11,14 +12,17 @@
<rect key="frame" x="0.0" y="0.0" width="480" height="480"/>
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
<subviews>
<label opaque="NO" clipsSubviews="YES" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text=" Copyright (c) 2015 John Rommel Estropia. All rights reserved." textAlignment="center" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" minimumFontSize="9" translatesAutoresizingMaskIntoConstraints="NO" id="8ie-xW-0ye">
<label opaque="NO" clipsSubviews="YES" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text=" Copyright © 2015 John Rommel Estropia. All rights reserved." textAlignment="center" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" minimumFontSize="9" translatesAutoresizingMaskIntoConstraints="NO" id="8ie-xW-0ye">
<rect key="frame" x="20" y="439" width="441" height="21"/>
<fontDescription key="fontDescription" type="system" pointSize="17"/>
<color key="textColor" red="0.92549019607843142" green="0.94117647058823528" blue="0.94509803921568625" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
<nil key="highlightedColor"/>
</label>
<label opaque="NO" clipsSubviews="YES" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" misplaced="YES" text="CoreStore" textAlignment="center" lineBreakMode="middleTruncation" baselineAdjustment="alignBaselines" minimumFontSize="18" translatesAutoresizingMaskIntoConstraints="NO" id="kId-c2-rCX">
<rect key="frame" x="20" y="140" width="441" height="43"/>
<imageView userInteractionEnabled="NO" contentMode="center" horizontalHuggingPriority="251" verticalHuggingPriority="251" image="CoreStoreIcon" translatesAutoresizingMaskIntoConstraints="NO" id="q8C-V6-gXH">
<rect key="frame" x="155" y="83" width="170" height="170"/>
</imageView>
<label opaque="NO" clipsSubviews="YES" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="CoreStore" textAlignment="center" lineBreakMode="middleTruncation" baselineAdjustment="alignBaselines" minimumFontSize="18" translatesAutoresizingMaskIntoConstraints="NO" id="kId-c2-rCX">
<rect key="frame" x="20" y="273" width="440" height="57.5"/>
<fontDescription key="fontDescription" name="HelveticaNeue-UltraLight" family="Helvetica Neue" pointSize="50"/>
<color key="textColor" red="0.92549019607843142" green="0.94117647058823528" blue="0.94509803921568625" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
<nil key="highlightedColor"/>
@@ -26,16 +30,21 @@
</subviews>
<color key="backgroundColor" red="0.20392156862745098" green="0.28627450980392155" blue="0.36862745098039218" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
<constraints>
<constraint firstItem="kId-c2-rCX" firstAttribute="centerY" secondItem="iN0-l3-epB" secondAttribute="bottom" multiplier="1/3" constant="1" id="5cJ-9S-tgC"/>
<constraint firstAttribute="centerX" secondItem="kId-c2-rCX" secondAttribute="centerX" id="Koa-jz-hwk"/>
<constraint firstAttribute="bottom" secondItem="8ie-xW-0ye" secondAttribute="bottom" constant="20" id="Kzo-t9-V3l"/>
<constraint firstItem="8ie-xW-0ye" firstAttribute="leading" secondItem="iN0-l3-epB" secondAttribute="leading" constant="20" symbolic="YES" id="MfP-vx-nX0"/>
<constraint firstItem="q8C-V6-gXH" firstAttribute="centerY" secondItem="iN0-l3-epB" secondAttribute="centerY" multiplier="0.7" id="QW6-8Y-w15"/>
<constraint firstAttribute="centerX" secondItem="8ie-xW-0ye" secondAttribute="centerX" id="ZEH-qu-HZ9"/>
<constraint firstItem="q8C-V6-gXH" firstAttribute="centerX" secondItem="iN0-l3-epB" secondAttribute="centerX" id="fRb-1V-9iD"/>
<constraint firstItem="kId-c2-rCX" firstAttribute="leading" secondItem="iN0-l3-epB" secondAttribute="leading" constant="20" symbolic="YES" id="fvb-Df-36g"/>
<constraint firstItem="kId-c2-rCX" firstAttribute="top" secondItem="q8C-V6-gXH" secondAttribute="bottom" constant="20" id="s63-MP-ush"/>
</constraints>
<nil key="simulatedStatusBarMetrics"/>
<freeformSimulatedSizeMetrics key="simulatedDestinationMetrics"/>
<point key="canvasLocation" x="548" y="455"/>
</view>
</objects>
<resources>
<image name="CoreStoreIcon" width="170" height="170"/>
</resources>
</document>
@@ -0,0 +1,53 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<<<<<<< Updated upstream
<document type="com.apple.InterfaceBuilder3.CocoaTouch.XIB" version="3.0" toolsVersion="9531" systemVersion="15C50" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" launchScreen="YES" useTraitCollections="YES">
<dependencies>
<plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="9529"/>
=======
<document type="com.apple.InterfaceBuilder3.CocoaTouch.XIB" version="3.0" toolsVersion="9532" systemVersion="15D21" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" launchScreen="YES" useTraitCollections="YES">
<dependencies>
<deployment identifier="iOS"/>
<plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="9530"/>
>>>>>>> Stashed changes
<capability name="Constraints with non-1.0 multipliers" minToolsVersion="5.1"/>
</dependencies>
<objects>
<placeholder placeholderIdentifier="IBFilesOwner" id="-1" userLabel="File's Owner"/>
<placeholder placeholderIdentifier="IBFirstResponder" id="-2" customClass="UIResponder"/>
<view contentMode="scaleToFill" id="iN0-l3-epB">
<rect key="frame" x="0.0" y="0.0" width="480" height="480"/>
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
<subviews>
<<<<<<< Updated upstream
<label opaque="NO" clipsSubviews="YES" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text=" Copyright © 2015 John Rommel Estropia. All rights reserved." textAlignment="center" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" minimumFontSize="9" translatesAutoresizingMaskIntoConstraints="NO" id="8ie-xW-0ye">
<rect key="frame" x="20" y="439" width="441" height="21"/>
=======
<label opaque="NO" clipsSubviews="YES" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text=" Copyright (c) 2015 John Rommel Estropia. All rights reserved." textAlignment="center" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" minimumFontSize="9" translatesAutoresizingMaskIntoConstraints="NO" id="8ie-xW-0ye">
<rect key="frame" x="20" y="439.5" width="441" height="20.5"/>
>>>>>>> Stashed changes
<fontDescription key="fontDescription" type="system" pointSize="17"/>
<color key="textColor" red="0.92549019607843142" green="0.94117647058823528" blue="0.94509803921568625" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
<nil key="highlightedColor"/>
</label>
<label opaque="NO" clipsSubviews="YES" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="CoreStore" textAlignment="center" lineBreakMode="middleTruncation" baselineAdjustment="alignBaselines" minimumFontSize="18" translatesAutoresizingMaskIntoConstraints="NO" id="kId-c2-rCX">
<rect key="frame" x="20" y="133" width="441" height="57.5"/>
<fontDescription key="fontDescription" name="HelveticaNeue-UltraLight" family="Helvetica Neue" pointSize="50"/>
<color key="textColor" red="0.92549019607843142" green="0.94117647058823528" blue="0.94509803921568625" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
<nil key="highlightedColor"/>
</label>
</subviews>
<color key="backgroundColor" red="0.20392156862745098" green="0.28627450980392155" blue="0.36862745098039218" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
<constraints>
<constraint firstItem="kId-c2-rCX" firstAttribute="centerY" secondItem="iN0-l3-epB" secondAttribute="bottom" multiplier="1/3" constant="1" id="5cJ-9S-tgC"/>
<constraint firstAttribute="centerX" secondItem="kId-c2-rCX" secondAttribute="centerX" id="Koa-jz-hwk"/>
<constraint firstAttribute="bottom" secondItem="8ie-xW-0ye" secondAttribute="bottom" constant="20" id="Kzo-t9-V3l"/>
<constraint firstItem="8ie-xW-0ye" firstAttribute="leading" secondItem="iN0-l3-epB" secondAttribute="leading" constant="20" symbolic="YES" id="MfP-vx-nX0"/>
<constraint firstAttribute="centerX" secondItem="8ie-xW-0ye" secondAttribute="centerX" id="ZEH-qu-HZ9"/>
<constraint firstItem="kId-c2-rCX" firstAttribute="leading" secondItem="iN0-l3-epB" secondAttribute="leading" constant="20" symbolic="YES" id="fvb-Df-36g"/>
</constraints>
<nil key="simulatedStatusBarMetrics"/>
<freeformSimulatedSizeMetrics key="simulatedDestinationMetrics"/>
<point key="canvasLocation" x="548" y="455"/>
</view>
</objects>
</document>
@@ -1,44 +1,63 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<document type="com.apple.InterfaceBuilder3.CocoaTouch.Storyboard.XIB" version="3.0" toolsVersion="7706" systemVersion="14D136" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" useTraitCollections="YES" initialViewController="Ni8-QF-XHB">
<?xml version="1.0" encoding="UTF-8"?>
<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>
<plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="7703"/>
<deployment identifier="iOS"/>
<plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="12078"/>
<capability name="Aspect ratio constraints" minToolsVersion="5.1"/>
<capability name="Constraints to layout margins" minToolsVersion="6.0"/>
<capability name="Constraints with non-1.0 multipliers" minToolsVersion="5.1"/>
<capability name="documents saved in the Xcode 8 format" minToolsVersion="8.0"/>
</dependencies>
<customFonts key="customFonts">
<array key="AppleSDGothicNeo.ttc">
<string>AppleSDGothicNeo-Regular</string>
</array>
<array key="HelveticaNeue.ttc">
<string>HelveticaNeue</string>
<string>HelveticaNeue-Bold</string>
</array>
<array key="HelveticaNeueLights.ttc">
<string>HelveticaNeue-Light</string>
<string>HelveticaNeue-Thin</string>
</array>
</customFonts>
<scenes>
<!--SNS Accounts-->
<scene sceneID="3If-81-mNf">
<objects>
<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">
<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"/>
<color key="backgroundColor" white="1" alpha="1" colorSpace="calibratedWhite"/>
<color key="backgroundColor" red="0.15542715787887573" green="0.2203737199306488" blue="0.2959403395652771" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
<color key="separatorColor" red="0.15542715787887573" green="0.2203737199306488" blue="0.2959403395652771" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
<view key="tableHeaderView" contentMode="scaleToFill" id="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"/>
<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">
<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"/>
<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"/>
</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">
<rect key="frame" x="20" y="70" width="41" height="20.5"/>
<fontDescription key="fontDescription" name="HelveticaNeue-Light" family="Helvetica Neue" pointSize="17"/>
<color key="textColor" red="0.92549019610000005" green="0.94117647059999998" blue="0.94509803920000002" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
<color key="textColor" red="0.90744441747665405" green="0.9265514612197876" blue="0.93116652965545654" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
<nil key="highlightedColor"/>
</label>
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="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"/>
<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"/>
</label>
</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>
<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"/>
@@ -52,20 +71,24 @@
</view>
<prototypes>
<tableViewCell contentMode="scaleToFill" selectionStyle="default" indentationWidth="10" reuseIdentifier="UITableViewCell" textLabel="8b8-lM-Krq" detailTextLabel="hR1-Zb-BOk" style="IBUITableViewCellStyleValue1" id="dMt-nx-EO5">
<rect key="frame" x="0.0" y="172" width="375" height="44"/>
<autoresizingMask key="autoresizingMask"/>
<tableViewCellContentView key="contentView" opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center" tableViewCell="dMt-nx-EO5" id="gdK-VV-zNb">
<rect key="frame" x="0.0" y="0.0" width="375" height="43.5"/>
<autoresizingMask key="autoresizingMask"/>
<subviews>
<label opaque="NO" multipleTouchEnabled="YES" contentMode="left" text="Title" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" id="8b8-lM-Krq">
<rect key="frame" x="15" y="13" width="28.5" height="19"/>
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMaxY="YES"/>
<fontDescription key="fontDescription" name="HelveticaNeue-Light" family="Helvetica Neue" pointSize="16"/>
<color key="textColor" red="0.17254901959999999" green="0.24313725489999999" blue="0.31372549020000001" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
<color key="textColor" red="0.13079629838466644" green="0.184075728058815" blue="0.24594299495220184" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
<nil key="highlightedColor"/>
</label>
<label opaque="NO" multipleTouchEnabled="YES" contentMode="left" text="Subtitle" textAlignment="right" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" id="hR1-Zb-BOk">
<rect key="frame" x="308" y="13" width="52" height="19"/>
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMaxY="YES"/>
<fontDescription key="fontDescription" name="HelveticaNeue-Light" family="Helvetica Neue" pointSize="16"/>
<color key="textColor" red="0.55686274509803924" green="0.55686274509803924" blue="0.57647058823529407" alpha="1" colorSpace="calibratedRGB"/>
<color key="textColor" red="0.55686274509803924" green="0.55686274509803924" blue="0.57647058823529407" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
<nil key="highlightedColor"/>
</label>
</subviews>
@@ -88,32 +111,185 @@
</objects>
<point key="canvasLocation" x="3694" y="650"/>
</scene>
<!--Evolution-->
<scene sceneID="iwU-Hv-zNr">
<objects>
<viewController automaticallyAdjustsScrollViewInsets="NO" id="iVv-Vc-nCL" customClass="MigrationsDemoViewController" customModule="CoreStoreDemo" customModuleProvider="target" sceneMemberID="viewController">
<layoutGuides>
<viewControllerLayoutGuide type="top" id="Un6-jI-efh"/>
<viewControllerLayoutGuide type="bottom" id="t9A-zf-Iew"/>
</layoutGuides>
<view key="view" contentMode="scaleToFill" id="75P-2m-6cr">
<rect key="frame" x="0.0" y="0.0" width="375" height="667"/>
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
<subviews>
<tableView clipsSubviews="YES" contentMode="scaleToFill" alwaysBounceVertical="YES" dataMode="prototypes" style="plain" separatorStyle="default" rowHeight="44" sectionHeaderHeight="22" sectionFooterHeight="22" translatesAutoresizingMaskIntoConstraints="NO" id="WUc-3Y-Quw">
<rect key="frame" x="0.0" y="324" width="375" height="343"/>
<color key="backgroundColor" red="0.93725490196078431" green="0.93725490196078431" blue="0.95686274509803926" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
<color key="separatorColor" red="0.15542715787887573" green="0.2203737199306488" blue="0.2959403395652771" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
<prototypes>
<tableViewCell contentMode="scaleToFill" selectionStyle="default" indentationWidth="10" reuseIdentifier="OrganismTableViewCell" id="WVb-th-o8c" customClass="OrganismTableViewCell" customModule="CoreStoreDemo" customModuleProvider="target">
<rect key="frame" x="0.0" y="22" width="375" height="44"/>
<autoresizingMask key="autoresizingMask"/>
<tableViewCellContentView key="contentView" opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center" tableViewCell="WVb-th-o8c" id="JBq-Ml-a9p">
<rect key="frame" x="0.0" y="0.0" width="375" height="43.5"/>
<autoresizingMask key="autoresizingMask"/>
<subviews>
<button opaque="NO" contentMode="scaleToFill" horizontalHuggingPriority="750" contentHorizontalAlignment="center" contentVerticalAlignment="center" buttonType="roundedRect" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="OQf-Bd-Zze">
<rect key="frame" x="295" y="8" width="72" height="27.5"/>
<fontDescription key="fontDescription" type="boldSystem" pointSize="15"/>
<inset key="contentEdgeInsets" minX="7" minY="0.0" maxX="7" maxY="0.0"/>
<state key="normal" title="mutate!"/>
<connections>
<action selector="mutateButtonTouchUpInside:" destination="WVb-th-o8c" eventType="touchUpInside" id="REw-UX-rJ0"/>
</connections>
</button>
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="Label" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="VZk-6K-4ut">
<rect key="frame" x="15" y="8" width="270" height="27.5"/>
<fontDescription key="fontDescription" name="HelveticaNeue-Thin" family="Helvetica Neue" pointSize="17"/>
<color key="textColor" red="0.15542715787887573" green="0.2203737199306488" blue="0.2959403395652771" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
<nil key="highlightedColor"/>
</label>
</subviews>
<constraints>
<constraint firstItem="OQf-Bd-Zze" firstAttribute="top" secondItem="JBq-Ml-a9p" secondAttribute="topMargin" id="39z-i5-EeS"/>
<constraint firstItem="VZk-6K-4ut" firstAttribute="top" secondItem="JBq-Ml-a9p" secondAttribute="topMargin" id="WO1-gf-MIu"/>
<constraint firstItem="VZk-6K-4ut" firstAttribute="leading" secondItem="JBq-Ml-a9p" secondAttribute="leadingMargin" constant="7" id="X0N-Il-F26"/>
<constraint firstAttribute="bottomMargin" secondItem="OQf-Bd-Zze" secondAttribute="bottom" id="YwC-dw-rGI"/>
<constraint firstItem="OQf-Bd-Zze" firstAttribute="leading" secondItem="VZk-6K-4ut" secondAttribute="trailing" constant="10" id="mo1-NZ-iPa"/>
<constraint firstAttribute="bottomMargin" secondItem="VZk-6K-4ut" secondAttribute="bottom" id="ucK-FJ-7v4"/>
<constraint firstItem="OQf-Bd-Zze" firstAttribute="trailing" secondItem="JBq-Ml-a9p" secondAttribute="trailingMargin" id="v3e-PY-3wW"/>
</constraints>
</tableViewCellContentView>
<connections>
<outlet property="dnaLabel" destination="VZk-6K-4ut" id="CSU-Ig-qMu"/>
<outlet property="mutateButton" destination="OQf-Bd-Zze" id="5gd-Jx-tMT"/>
</connections>
</tableViewCell>
</prototypes>
<connections>
<outlet property="dataSource" destination="iVv-Vc-nCL" id="yp2-X4-fhE"/>
<outlet property="delegate" destination="iVv-Vc-nCL" id="V5b-s8-XOl"/>
</connections>
</tableView>
<view contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="XKA-Ub-c2X">
<rect key="frame" x="0.0" y="64" width="375" height="260"/>
<subviews>
<view contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="i7U-bW-juB" customClass="UIButton">
<rect key="frame" x="0.0" y="0.0" width="375" height="260"/>
<subviews>
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="Organism" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="zxy-nY-P44">
<rect key="frame" x="20" y="90.5" width="335" height="26.5"/>
<fontDescription key="fontDescription" name="HelveticaNeue-Bold" family="Helvetica Neue" pointSize="22"/>
<color key="textColor" red="0.90744441747665405" green="0.9265514612197876" blue="0.93116652965545654" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
<nil key="highlightedColor"/>
</label>
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="attributes" lineBreakMode="wordWrap" numberOfLines="0" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="6Ac-xl-ldZ">
<rect key="frame" x="20" y="131.5" width="335" height="20.5"/>
<fontDescription key="fontDescription" name="HelveticaNeue-Light" family="Helvetica Neue" pointSize="17"/>
<color key="textColor" red="0.90744441747665405" green="0.9265514612197876" blue="0.93116652965545654" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
<nil key="highlightedColor"/>
</label>
<segmentedControl opaque="NO" contentMode="scaleToFill" contentHorizontalAlignment="left" contentVerticalAlignment="top" segmentControlStyle="plain" selectedSegmentIndex="0" translatesAutoresizingMaskIntoConstraints="NO" id="rAZ-eJ-sxy">
<rect key="frame" x="20" y="20" width="335" height="29"/>
<segments>
<segment title="First"/>
<segment title="Second"/>
<segment title=""/>
</segments>
<color key="tintColor" red="1" green="1" blue="1" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
<connections>
<action selector="segmentedControlValueChanged:" destination="iVv-Vc-nCL" eventType="valueChanged" id="RwG-kW-RPg"/>
</connections>
</segmentedControl>
<progressView opaque="NO" clipsSubviews="YES" contentMode="scaleToFill" verticalHuggingPriority="750" progress="0.5" translatesAutoresizingMaskIntoConstraints="NO" id="869-wx-Odb">
<rect key="frame" x="20" y="68" width="335" height="2"/>
<color key="progressTintColor" red="1" green="1" blue="1" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
<color key="trackTintColor" red="1" green="1" blue="1" alpha="0.20000000000000001" colorSpace="custom" customColorSpace="sRGB"/>
</progressView>
</subviews>
<color key="backgroundColor" red="0.15542715787887573" green="0.2203737199306488" blue="0.2959403395652771" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
<constraints>
<constraint firstItem="zxy-nY-P44" firstAttribute="leading" secondItem="i7U-bW-juB" secondAttribute="leading" constant="20" id="1u1-Tq-hRn"/>
<constraint firstItem="6Ac-xl-ldZ" firstAttribute="top" secondItem="zxy-nY-P44" secondAttribute="bottom" constant="14.5" id="39B-9l-O3g"/>
<constraint firstAttribute="trailing" secondItem="zxy-nY-P44" secondAttribute="trailing" constant="20" id="3d5-Zk-rB1"/>
<constraint firstAttribute="trailing" secondItem="6Ac-xl-ldZ" secondAttribute="trailing" constant="20" id="EJq-uA-8dQ"/>
<constraint firstItem="rAZ-eJ-sxy" firstAttribute="top" secondItem="i7U-bW-juB" secondAttribute="top" constant="20" id="Ey7-mP-RNA"/>
<constraint firstItem="zxy-nY-P44" firstAttribute="top" secondItem="869-wx-Odb" secondAttribute="bottom" constant="20.5" id="GU3-JM-b99"/>
<constraint firstItem="rAZ-eJ-sxy" firstAttribute="leading" secondItem="i7U-bW-juB" secondAttribute="leading" constant="20" id="KKJ-gG-pFL"/>
<constraint firstAttribute="trailing" secondItem="869-wx-Odb" secondAttribute="trailing" constant="20" id="Lni-gD-7h0"/>
<constraint firstItem="869-wx-Odb" firstAttribute="top" secondItem="rAZ-eJ-sxy" secondAttribute="bottom" constant="20" id="QBz-cP-SVZ"/>
<constraint firstAttribute="trailing" secondItem="rAZ-eJ-sxy" secondAttribute="trailing" constant="20" id="WoD-cr-aj9"/>
<constraint firstAttribute="height" constant="260" id="XTa-ql-yEW"/>
<constraint firstItem="6Ac-xl-ldZ" firstAttribute="leading" secondItem="i7U-bW-juB" secondAttribute="leading" constant="20" id="jkv-ow-f0q"/>
<constraint firstItem="869-wx-Odb" firstAttribute="leading" secondItem="i7U-bW-juB" secondAttribute="leading" constant="20" id="qgE-y5-uh8"/>
</constraints>
</view>
</subviews>
<color key="backgroundColor" red="1" green="1" blue="1" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
<constraints>
<constraint firstAttribute="height" constant="260" id="90R-Mf-iAB"/>
<constraint firstItem="i7U-bW-juB" firstAttribute="leading" secondItem="XKA-Ub-c2X" secondAttribute="leading" id="e9h-f4-c37"/>
<constraint firstItem="i7U-bW-juB" firstAttribute="top" secondItem="XKA-Ub-c2X" secondAttribute="top" id="vJV-dl-RLx"/>
<constraint firstAttribute="trailing" secondItem="i7U-bW-juB" secondAttribute="trailing" id="wYt-hg-yKM"/>
</constraints>
</view>
</subviews>
<color key="backgroundColor" red="1" green="1" blue="1" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
<constraints>
<constraint firstAttribute="trailing" secondItem="XKA-Ub-c2X" secondAttribute="trailing" id="U0P-51-KT9"/>
<constraint firstAttribute="trailing" secondItem="WUc-3Y-Quw" secondAttribute="trailing" id="i7I-7B-97K"/>
<constraint firstItem="WUc-3Y-Quw" firstAttribute="leading" secondItem="75P-2m-6cr" secondAttribute="leading" id="i8b-GU-yFg"/>
<constraint firstItem="XKA-Ub-c2X" firstAttribute="top" secondItem="Un6-jI-efh" secondAttribute="bottom" id="lU2-wP-RQb"/>
<constraint firstItem="XKA-Ub-c2X" firstAttribute="leading" secondItem="75P-2m-6cr" secondAttribute="leading" id="oa7-qv-9am"/>
<constraint firstItem="t9A-zf-Iew" firstAttribute="top" secondItem="WUc-3Y-Quw" secondAttribute="bottom" id="tts-uy-w5J"/>
<constraint firstItem="WUc-3Y-Quw" firstAttribute="top" secondItem="XKA-Ub-c2X" secondAttribute="bottom" id="vjy-iN-Xi7"/>
</constraints>
</view>
<navigationItem key="navigationItem" title="Evolution" id="uc7-DN-PYG"/>
<connections>
<outlet property="headerContainer" destination="i7U-bW-juB" id="hpf-7a-yBd"/>
<outlet property="organismLabel" destination="6Ac-xl-ldZ" id="pgF-ej-ovy"/>
<outlet property="progressView" destination="869-wx-Odb" id="um3-UM-uOP"/>
<outlet property="segmentedControl" destination="rAZ-eJ-sxy" id="K3Q-X2-Jrm"/>
<outlet property="tableView" destination="WUc-3Y-Quw" id="3Ki-v0-lTb"/>
<outlet property="titleLabel" destination="zxy-nY-P44" id="9JO-hP-yVp"/>
</connections>
</viewController>
<placeholder placeholderIdentifier="IBFirstResponder" id="LzB-gZ-6fG" userLabel="First Responder" sceneMemberID="firstResponder"/>
</objects>
<point key="canvasLocation" x="3694" y="4113"/>
</scene>
<!--CoreStore Demos-->
<scene sceneID="0Be-vc-h1W">
<objects>
<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">
<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"/>
<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>
<tableViewSection id="wIP-Hn-YfF">
<cells>
<tableViewCell contentMode="scaleToFill" selectionStyle="default" accessoryType="disclosureIndicator" indentationWidth="10" textLabel="Q3n-Df-v1t" detailTextLabel="Hbn-cf-Y7m" style="IBUITableViewCellStyleSubtitle" id="AXm-KE-45G">
<rect key="frame" x="0.0" y="35" width="375" height="50"/>
<autoresizingMask key="autoresizingMask"/>
<tableViewCellContentView key="contentView" opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center" tableViewCell="AXm-KE-45G" id="9te-Wx-hkf">
<rect key="frame" x="0.0" y="0.0" width="342" height="49.5"/>
<autoresizingMask key="autoresizingMask"/>
<subviews>
<label opaque="NO" multipleTouchEnabled="YES" contentMode="left" text="Accounts" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" id="Q3n-Df-v1t">
<rect key="frame" x="15" y="6" width="82" height="24"/>
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMaxY="YES"/>
<fontDescription key="fontDescription" name="HelveticaNeue-Light" family="Helvetica Neue" pointSize="20"/>
<color key="textColor" red="0.17254901960784313" green="0.24313725490196078" blue="0.31372549019607843" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
<color key="textColor" red="0.13079629838466644" green="0.184075728058815" blue="0.24594299495220184" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
<nil key="highlightedColor"/>
</label>
<label opaque="NO" multipleTouchEnabled="YES" contentMode="left" text="Setting up multiple persistent store configurations" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" id="Hbn-cf-Y7m">
<rect key="frame" x="15" y="30" width="263.5" height="13.5"/>
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMaxY="YES"/>
<fontDescription key="fontDescription" type="system" pointSize="11"/>
<color key="textColor" red="0.17254901959999999" green="0.24313725489999999" blue="0.31372549020000001" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
<color key="textColor" red="0.13079629838466644" green="0.184075728058815" blue="0.24594299495220184" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
<nil key="highlightedColor"/>
</label>
</subviews>
@@ -123,20 +299,24 @@
</connections>
</tableViewCell>
<tableViewCell contentMode="scaleToFill" selectionStyle="default" accessoryType="disclosureIndicator" indentationWidth="10" textLabel="vpt-cT-gMo" detailTextLabel="ou9-TZ-8bf" style="IBUITableViewCellStyleSubtitle" id="fsb-zw-8Ii">
<rect key="frame" x="0.0" y="85" width="375" height="50"/>
<autoresizingMask key="autoresizingMask"/>
<tableViewCellContentView key="contentView" opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center" tableViewCell="fsb-zw-8Ii" id="Upm-AO-Fw3">
<rect key="frame" x="0.0" y="0.0" width="342" height="49.5"/>
<autoresizingMask key="autoresizingMask"/>
<subviews>
<label opaque="NO" multipleTouchEnabled="YES" contentMode="left" text="Colors" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" id="vpt-cT-gMo">
<rect key="frame" x="15" y="6" width="56" height="24"/>
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMaxY="YES"/>
<fontDescription key="fontDescription" name="HelveticaNeue-Light" family="Helvetica Neue" pointSize="20"/>
<color key="textColor" red="0.17254901959999999" green="0.24313725489999999" blue="0.31372549020000001" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
<color key="textColor" red="0.13079629838466644" green="0.184075728058815" blue="0.24594299495220184" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
<nil key="highlightedColor"/>
</label>
<label opaque="NO" multipleTouchEnabled="YES" contentMode="left" text="Observing list changes and single object changes" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" id="ou9-TZ-8bf">
<rect key="frame" x="15" y="30" width="260.5" height="13.5"/>
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMaxY="YES"/>
<fontDescription key="fontDescription" type="system" pointSize="11"/>
<color key="textColor" red="0.17254901959999999" green="0.24313725489999999" blue="0.31372549020000001" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
<color key="textColor" red="0.13079629838466644" green="0.184075728058815" blue="0.24594299495220184" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
<nil key="highlightedColor"/>
</label>
</subviews>
@@ -146,20 +326,24 @@
</connections>
</tableViewCell>
<tableViewCell contentMode="scaleToFill" selectionStyle="default" accessoryType="disclosureIndicator" indentationWidth="10" textLabel="UbU-Kd-yrY" detailTextLabel="uP1-Jc-o9v" style="IBUITableViewCellStyleSubtitle" id="ekW-PJ-mbo">
<rect key="frame" x="0.0" y="135" width="375" height="50"/>
<autoresizingMask key="autoresizingMask"/>
<tableViewCellContentView key="contentView" opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center" tableViewCell="ekW-PJ-mbo" id="CYq-mg-PVS">
<rect key="frame" x="0.0" y="0.0" width="342" height="49.5"/>
<autoresizingMask key="autoresizingMask"/>
<subviews>
<label opaque="NO" multipleTouchEnabled="YES" contentMode="left" text="Placemarks" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" id="UbU-Kd-yrY">
<rect key="frame" x="15" y="6" width="100.5" height="24"/>
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMaxY="YES"/>
<fontDescription key="fontDescription" name="HelveticaNeue-Light" family="Helvetica Neue" pointSize="20"/>
<color key="textColor" red="0.17254901959999999" green="0.24313725489999999" blue="0.31372549020000001" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
<color key="textColor" red="0.13079629838466644" green="0.184075728058815" blue="0.24594299495220184" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
<nil key="highlightedColor"/>
</label>
<label opaque="NO" multipleTouchEnabled="YES" contentMode="left" text="Making changes with transactions" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" id="uP1-Jc-o9v">
<rect key="frame" x="15" y="30" width="179" height="13.5"/>
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMaxY="YES"/>
<fontDescription key="fontDescription" type="system" pointSize="11"/>
<color key="textColor" red="0.17254901959999999" green="0.24313725489999999" blue="0.31372549020000001" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
<color key="textColor" red="0.13079629838466644" green="0.184075728058815" blue="0.24594299495220184" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
<nil key="highlightedColor"/>
</label>
</subviews>
@@ -169,20 +353,24 @@
</connections>
</tableViewCell>
<tableViewCell contentMode="scaleToFill" selectionStyle="default" accessoryType="disclosureIndicator" indentationWidth="10" textLabel="C8Y-0y-lEG" detailTextLabel="jZw-qE-0ws" style="IBUITableViewCellStyleSubtitle" id="ph1-8z-C1m">
<rect key="frame" x="0.0" y="185" width="375" height="50"/>
<autoresizingMask key="autoresizingMask"/>
<tableViewCellContentView key="contentView" opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center" tableViewCell="ph1-8z-C1m" id="nNz-rd-ksg">
<rect key="frame" x="0.0" y="0.0" width="342" height="49.5"/>
<autoresizingMask key="autoresizingMask"/>
<subviews>
<label opaque="NO" multipleTouchEnabled="YES" contentMode="left" text="Time Zones" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" id="C8Y-0y-lEG">
<rect key="frame" x="15" y="6" width="101.5" height="24"/>
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMaxY="YES"/>
<fontDescription key="fontDescription" name="HelveticaNeue-Light" family="Helvetica Neue" pointSize="20"/>
<color key="textColor" red="0.17254901959999999" green="0.24313725489999999" blue="0.31372549020000001" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
<color key="textColor" red="0.13079629838466644" green="0.184075728058815" blue="0.24594299495220184" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
<nil key="highlightedColor"/>
</label>
<label opaque="NO" multipleTouchEnabled="YES" contentMode="left" text="Fetching objects and raw values" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" id="jZw-qE-0ws">
<rect key="frame" x="15" y="30" width="168.5" height="13.5"/>
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMaxY="YES"/>
<fontDescription key="fontDescription" type="system" pointSize="11"/>
<color key="textColor" red="0.17254901959999999" green="0.24313725489999999" blue="0.31372549020000001" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
<color key="textColor" red="0.13079629838466644" green="0.184075728058815" blue="0.24594299495220184" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
<nil key="highlightedColor"/>
</label>
</subviews>
@@ -192,20 +380,24 @@
</connections>
</tableViewCell>
<tableViewCell contentMode="scaleToFill" selectionStyle="default" accessoryType="disclosureIndicator" indentationWidth="10" textLabel="ZfY-Aq-Ykq" detailTextLabel="QzD-9b-k1j" style="IBUITableViewCellStyleSubtitle" id="wyK-rk-3tI">
<rect key="frame" x="0.0" y="235" width="375" height="50"/>
<autoresizingMask key="autoresizingMask"/>
<tableViewCellContentView key="contentView" opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center" tableViewCell="wyK-rk-3tI" id="fLd-KK-QcW">
<rect key="frame" x="0.0" y="0.0" width="342" height="49.5"/>
<autoresizingMask key="autoresizingMask"/>
<subviews>
<label opaque="NO" multipleTouchEnabled="YES" contentMode="left" text="Logger" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" id="ZfY-Aq-Ykq">
<rect key="frame" x="15" y="6" width="61" height="24"/>
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMaxY="YES"/>
<fontDescription key="fontDescription" name="HelveticaNeue-Light" family="Helvetica Neue" pointSize="20"/>
<color key="textColor" red="0.17254901959999999" green="0.24313725489999999" blue="0.31372549020000001" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
<color key="textColor" red="0.13079629838466644" green="0.184075728058815" blue="0.24594299495220184" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
<nil key="highlightedColor"/>
</label>
<label opaque="NO" multipleTouchEnabled="YES" contentMode="left" text="Implementing a custom logger" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" id="QzD-9b-k1j">
<rect key="frame" x="15" y="30" width="159" height="13.5"/>
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMaxY="YES"/>
<fontDescription key="fontDescription" type="system" pointSize="11"/>
<color key="textColor" red="0.17254901959999999" green="0.24313725489999999" blue="0.31372549020000001" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
<color key="textColor" red="0.13079629838466644" green="0.184075728058815" blue="0.24594299495220184" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
<nil key="highlightedColor"/>
</label>
</subviews>
@@ -214,6 +406,33 @@
<segue destination="5yy-0N-QDU" kind="show" id="5D7-Xp-1HT"/>
</connections>
</tableViewCell>
<tableViewCell contentMode="scaleToFill" selectionStyle="default" accessoryType="disclosureIndicator" indentationWidth="10" textLabel="hSG-mG-YBw" detailTextLabel="X9P-TQ-LYh" style="IBUITableViewCellStyleSubtitle" id="xTM-Cf-0if">
<rect key="frame" x="0.0" y="285" width="375" height="50"/>
<autoresizingMask key="autoresizingMask"/>
<tableViewCellContentView key="contentView" opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center" tableViewCell="xTM-Cf-0if" id="DfO-BW-krd">
<rect key="frame" x="0.0" y="0.0" width="342" height="49.5"/>
<autoresizingMask key="autoresizingMask"/>
<subviews>
<label opaque="NO" multipleTouchEnabled="YES" contentMode="left" text="Evolution" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" id="hSG-mG-YBw">
<rect key="frame" x="15" y="6" width="78.5" height="24"/>
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMaxY="YES"/>
<fontDescription key="fontDescription" name="HelveticaNeue-Light" family="Helvetica Neue" pointSize="20"/>
<color key="textColor" red="0.13079629838466644" green="0.184075728058815" blue="0.24594299495220184" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
<nil key="highlightedColor"/>
</label>
<label opaque="NO" multipleTouchEnabled="YES" contentMode="left" text="Migrating and de-migrating stores" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" id="X9P-TQ-LYh">
<rect key="frame" x="15" y="30" width="179.5" height="13.5"/>
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMaxY="YES"/>
<fontDescription key="fontDescription" type="system" pointSize="11"/>
<color key="textColor" red="0.13079629838466644" green="0.184075728058815" blue="0.24594299495220184" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
<nil key="highlightedColor"/>
</label>
</subviews>
</tableViewCellContentView>
<connections>
<segue destination="iVv-Vc-nCL" kind="show" id="HbO-rU-Qfj"/>
</connections>
</tableViewCell>
</cells>
</tableViewSection>
</sections>
@@ -237,69 +456,69 @@
<viewControllerLayoutGuide type="bottom" id="aI4-O3-OCi"/>
</layoutGuides>
<view key="view" contentMode="scaleToFill" id="w8K-eN-RvU">
<rect key="frame" x="0.0" y="0.0" width="600" height="268"/>
<rect key="frame" x="0.0" y="0.0" width="375" height="301.5"/>
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
<subviews>
<view contentMode="scaleToFill" verticalCompressionResistancePriority="250" translatesAutoresizingMaskIntoConstraints="NO" id="NhC-oM-bkd">
<rect key="frame" x="16" y="70" width="568" height="36"/>
<color key="backgroundColor" white="1" alpha="1" colorSpace="calibratedWhite"/>
<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"/>
<color key="backgroundColor" red="1" green="1" blue="1" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
<constraints>
<constraint firstAttribute="height" relation="greaterThanOrEqual" id="TIX-qi-B34"/>
</constraints>
</view>
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" verticalCompressionResistancePriority="250" text="Label" textAlignment="center" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" minimumScaleFactor="0.5" adjustsLetterSpacingToFitWidth="YES" translatesAutoresizingMaskIntoConstraints="NO" id="Vfe-Yq-3Xa">
<rect key="frame" x="16" y="116" width="568" height="18"/>
<rect key="frame" x="16" y="149.5" width="343" height="18"/>
<constraints>
<constraint firstAttribute="height" relation="greaterThanOrEqual" id="4h9-ha-EzR"/>
</constraints>
<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"/>
</label>
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="Hue" textAlignment="right" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="sgg-Md-Nf3">
<rect key="frame" x="16" y="154" width="74" height="18"/>
<rect key="frame" x="16" y="187.5" width="74" height="18"/>
<fontDescription key="fontDescription" type="system" pointSize="15"/>
<color key="textColor" red="0.0" green="0.0" blue="0.0" alpha="1" colorSpace="calibratedRGB"/>
<color key="textColor" red="0.0" green="0.0" blue="0.0" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
<nil key="highlightedColor"/>
</label>
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="Saturation" textAlignment="right" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="rry-vh-bRK">
<rect key="frame" x="16" y="192" width="74" height="18"/>
<rect key="frame" x="16" y="225.5" width="74" height="18"/>
<fontDescription key="fontDescription" type="system" pointSize="15"/>
<color key="textColor" red="0.0" green="0.0" blue="0.0" alpha="1" colorSpace="calibratedRGB"/>
<color key="textColor" red="0.0" green="0.0" blue="0.0" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
<nil key="highlightedColor"/>
</label>
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="Brightness" textAlignment="right" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="vTa-ly-eyO">
<rect key="frame" x="16" y="230" width="74" height="18"/>
<rect key="frame" x="16" y="263.5" width="74" height="18"/>
<fontDescription key="fontDescription" type="system" pointSize="15"/>
<color key="textColor" red="0.0" green="0.0" blue="0.0" alpha="1" colorSpace="calibratedRGB"/>
<color key="textColor" red="0.0" green="0.0" blue="0.0" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
<nil key="highlightedColor"/>
</label>
<slider opaque="NO" contentMode="scaleToFill" contentHorizontalAlignment="center" contentVerticalAlignment="center" minValue="0.0" maxValue="359" translatesAutoresizingMaskIntoConstraints="NO" id="YQ6-fq-3Wb">
<rect key="frame" x="98" y="148" width="488" height="31"/>
<rect key="frame" x="98" y="181.5" width="263" height="31"/>
<connections>
<action selector="hueSliderValueDidChange:" destination="dX3-kR-CYC" eventType="valueChanged" id="9Hy-3h-llE"/>
</connections>
</slider>
<slider opaque="NO" contentMode="scaleToFill" contentHorizontalAlignment="center" contentVerticalAlignment="center" value="1" minValue="0.0" maxValue="1" translatesAutoresizingMaskIntoConstraints="NO" id="xXz-78-tAd">
<rect key="frame" x="98" y="186" width="488" height="31"/>
<rect key="frame" x="98" y="219.5" width="263" height="31"/>
<connections>
<action selector="saturationSliderValueDidChange:" destination="dX3-kR-CYC" eventType="valueChanged" id="qtU-ua-ZTc"/>
</connections>
</slider>
<slider opaque="NO" contentMode="scaleToFill" contentHorizontalAlignment="center" contentVerticalAlignment="center" value="0.5" minValue="0.0" maxValue="1" translatesAutoresizingMaskIntoConstraints="NO" id="hpy-2d-eOP">
<rect key="frame" x="98" y="224" width="488" height="31"/>
<rect key="frame" x="98" y="257.5" width="263" height="31"/>
<connections>
<action selector="brightnessSliderValueDidChange:" destination="dX3-kR-CYC" eventType="valueChanged" id="F09-EP-2iD"/>
</connections>
</slider>
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="Label" textAlignment="center" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="p4O-tf-dgt">
<rect key="frame" x="16" y="49" width="568" height="21"/>
<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"/>
<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"/>
</label>
</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>
<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"/>
@@ -361,23 +580,23 @@
<viewControllerLayoutGuide type="bottom" id="LNL-mj-D7l"/>
</layoutGuides>
<view key="view" contentMode="scaleToFill" id="6x3-vn-Egt">
<rect key="frame" x="0.0" y="64" width="600" height="600"/>
<rect key="frame" x="0.0" y="0.0" width="375" height="667"/>
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
<subviews>
<containerView opaque="NO" contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="L5f-tW-lXf">
<rect key="frame" x="0.0" y="64" width="600" height="268"/>
<rect key="frame" x="0.0" y="64" width="375" height="301.5"/>
<connections>
<segue destination="5Fw-je-9gI" kind="embed" id="YcI-2Z-ijV"/>
</connections>
</containerView>
<containerView opaque="NO" contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="6So-f3-4Gp">
<rect key="frame" x="0.0" y="332" width="600" height="268"/>
<rect key="frame" x="0.0" y="365.5" width="375" height="301.5"/>
<connections>
<segue destination="sll-yo-mBc" kind="embed" id="AAl-HS-dq2"/>
</connections>
</containerView>
</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>
<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"/>
@@ -406,11 +625,11 @@
<navigationBar key="navigationBar" contentMode="scaleToFill" id="00L-5k-Eno">
<rect key="frame" x="0.0" y="0.0" width="320" height="44"/>
<autoresizingMask key="autoresizingMask"/>
<color key="tintColor" red="0.92549019610000005" green="0.94117647059999998" blue="0.94509803920000002" 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="tintColor" red="0.90744441747665405" green="0.9265514612197876" blue="0.93116652965545654" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
<color key="barTintColor" red="0.15542715787887573" green="0.2203737199306488" blue="0.2959403395652771" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
<textAttributes key="titleTextAttributes">
<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>
</navigationBar>
<nil name="viewControllers"/>
@@ -425,19 +644,21 @@
<!--List Observer-->
<scene sceneID="gkX-bd-Rel">
<objects>
<tableViewController id="3AE-ED-0oj" customClass="ObjectListObserverDemoViewController" customModule="CoreStoreDemo" customModuleProvider="target" sceneMemberID="viewController">
<tableViewController id="3AE-ED-0oj" customClass="ListObserverDemoViewController" customModule="CoreStoreDemo" customModuleProvider="target" sceneMemberID="viewController">
<tableView key="view" clipsSubviews="YES" contentMode="scaleToFill" alwaysBounceVertical="YES" dataMode="prototypes" style="plain" separatorStyle="default" rowHeight="44" sectionHeaderHeight="22" sectionFooterHeight="22" id="DAz-BE-6Ca">
<rect key="frame" x="0.0" y="0.0" width="600" height="268"/>
<rect key="frame" x="0.0" y="0.0" width="375" height="301.5"/>
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
<prototypes>
<tableViewCell contentMode="scaleToFill" selectionStyle="default" accessoryType="disclosureIndicator" indentationWidth="10" reuseIdentifier="PaletteTableViewCell" id="G3X-70-BCD" customClass="PaletteTableViewCell" customModule="CoreStoreDemo" customModuleProvider="target">
<rect key="frame" x="0.0" y="22" width="375" height="44"/>
<autoresizingMask key="autoresizingMask"/>
<tableViewCellContentView key="contentView" opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center" tableViewCell="G3X-70-BCD" id="aT8-nz-i5l">
<rect key="frame" x="0.0" y="0.0" width="342" height="43.5"/>
<autoresizingMask key="autoresizingMask"/>
<subviews>
<view contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="uQX-PI-UWF">
<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>
<constraint firstAttribute="width" secondItem="uQX-PI-UWF" secondAttribute="height" multiplier="1:1" id="9qA-iN-Neb"/>
</constraints>
@@ -445,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">
<rect key="frame" x="45" y="8" width="34.5" height="27"/>
<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"/>
</label>
</subviews>
@@ -482,20 +703,22 @@
<!--List Observer-->
<scene sceneID="iDB-TD-It9">
<objects>
<tableViewController id="lCE-i6-UCT" customClass="ObjectListObserverDemoViewController" customModule="CoreStoreDemo" customModuleProvider="target" sceneMemberID="viewController">
<tableViewController id="lCE-i6-UCT" customClass="ListObserverDemoViewController" customModule="CoreStoreDemo" customModuleProvider="target" sceneMemberID="viewController">
<tableView key="view" clipsSubviews="YES" contentMode="scaleToFill" alwaysBounceVertical="YES" dataMode="prototypes" style="plain" separatorStyle="default" rowHeight="44" sectionHeaderHeight="22" sectionFooterHeight="22" id="Zba-8M-Zd7">
<rect key="frame" x="0.0" y="0.0" width="600" height="268"/>
<rect key="frame" x="0.0" y="0.0" width="375" height="301.5"/>
<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>
<tableViewCell contentMode="scaleToFill" selectionStyle="default" accessoryType="disclosureIndicator" indentationWidth="10" reuseIdentifier="PaletteTableViewCell" id="zSO-3e-OVq" customClass="PaletteTableViewCell" customModule="CoreStoreDemo" customModuleProvider="target">
<rect key="frame" x="0.0" y="22" width="375" height="44"/>
<autoresizingMask key="autoresizingMask"/>
<tableViewCellContentView key="contentView" opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center" tableViewCell="zSO-3e-OVq" id="cHA-by-n4b">
<rect key="frame" x="0.0" y="0.0" width="342" height="43.5"/>
<autoresizingMask key="autoresizingMask"/>
<subviews>
<view contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="5uq-Yi-XwH">
<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>
<constraint firstAttribute="width" secondItem="5uq-Yi-XwH" secondAttribute="height" multiplier="1:1" id="oOe-HC-VyN"/>
</constraints>
@@ -503,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">
<rect key="frame" x="45" y="8" width="34.5" height="27"/>
<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"/>
</label>
</subviews>
@@ -546,11 +769,11 @@
<navigationBar key="navigationBar" contentMode="scaleToFill" id="6XA-6M-yvZ">
<rect key="frame" x="0.0" y="0.0" width="320" height="44"/>
<autoresizingMask key="autoresizingMask"/>
<color key="tintColor" red="0.74117647060000003" green="0.76470588240000004" blue="0.78039215689999997" 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="tintColor" red="0.68773996829986572" green="0.71417498588562012" blue="0.73246318101882935" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
<color key="barTintColor" red="0.13079629838466644" green="0.184075728058815" blue="0.24594299495220184" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
<textAttributes key="titleTextAttributes">
<fontDescription key="fontDescription" name="HelveticaNeue-Thin" family="Helvetica Neue" pointSize="20"/>
<color key="textColor" red="0.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>
</navigationBar>
<nil name="viewControllers"/>
@@ -571,17 +794,17 @@
<viewControllerLayoutGuide type="bottom" id="RZg-hi-T8O"/>
</layoutGuides>
<view key="view" contentMode="scaleToFill" id="k4s-iL-Krh">
<rect key="frame" x="0.0" y="0.0" width="600" height="536"/>
<rect key="frame" x="0.0" y="64" width="375" height="603"/>
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
<subviews>
<mapView clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="scaleToFill" mapType="standard" translatesAutoresizingMaskIntoConstraints="NO" id="V2U-0R-Ts0">
<rect key="frame" x="0.0" y="0.0" width="600" height="536"/>
<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="375" height="536"/>
<connections>
<outlet property="delegate" destination="jPl-fH-NlD" id="Sjn-YC-haS"/>
</connections>
</mapView>
</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>
<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"/>
@@ -608,30 +831,30 @@
<viewControllerLayoutGuide type="bottom" id="Cwn-Jd-4Lr"/>
</layoutGuides>
<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"/>
<subviews>
<textView clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="scaleToFill" directionalLockEnabled="YES" alwaysBounceVertical="YES" indicatorStyle="white" editable="NO" translatesAutoresizingMaskIntoConstraints="NO" id="TpK-gX-CTN">
<rect key="frame" x="0.0" y="142" width="600" height="458"/>
<color key="backgroundColor" red="0.20392156862745098" green="0.28627450980392155" blue="0.36862745098039218" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
<color key="textColor" red="0.94509803921568625" green="0.7686274509803922" blue="0.058823529411764705" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
<rect key="frame" x="0.0" y="142" width="375" height="525"/>
<color key="backgroundColor" red="0.15542715787887573" green="0.2203737199306488" blue="0.2959403395652771" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
<color key="textColor" red="0.92706394195556641" green="0.72759377956390381" blue="0.064024783670902252" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
<fontDescription key="fontDescription" name="AppleSDGothicNeo-Regular" family="Apple SD Gothic Neo" pointSize="15"/>
<textInputTraits key="textInputTraits" autocapitalizationType="sentences"/>
</textView>
<segmentedControl opaque="NO" contentMode="scaleToFill" contentHorizontalAlignment="left" contentVerticalAlignment="top" segmentControlStyle="bordered" momentary="YES" translatesAutoresizingMaskIntoConstraints="NO" id="4iq-B4-k0p">
<rect key="frame" x="20" y="94" width="560" height="29"/>
<rect key="frame" x="20" y="94" width="335" height="29"/>
<segments>
<segment title="Log"/>
<segment title="Error"/>
<segment title="Assert"/>
</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>
<action selector="segmentedControlValueChanged:" destination="5yy-0N-QDU" eventType="valueChanged" id="2pp-Vt-2Os"/>
</connections>
</segmentedControl>
</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>
<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"/>
@@ -667,11 +890,11 @@
<navigationBar key="navigationBar" contentMode="scaleToFill" id="wJo-mp-1pS">
<rect key="frame" x="0.0" y="0.0" width="320" height="44"/>
<autoresizingMask key="autoresizingMask"/>
<color key="tintColor" red="0.74117647058823533" green="0.76470588235294112" blue="0.7803921568627451" 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="tintColor" red="0.68773996829986572" green="0.71417498588562012" blue="0.73246318101882935" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
<color key="barTintColor" red="0.13079629838466644" green="0.184075728058815" blue="0.24594299495220184" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
<textAttributes key="titleTextAttributes">
<fontDescription key="fontDescription" name="HelveticaNeue-Thin" family="Helvetica Neue" pointSize="20"/>
<color key="textColor" red="0.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>
</navigationBar>
<nil name="viewControllers"/>
@@ -692,15 +915,15 @@
<viewControllerLayoutGuide type="bottom" id="DlN-cN-JXd"/>
</layoutGuides>
<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"/>
<subviews>
<tableView clipsSubviews="YES" contentMode="scaleToFill" alwaysBounceVertical="YES" dataMode="prototypes" style="plain" separatorStyle="default" rowHeight="44" sectionHeaderHeight="22" sectionFooterHeight="22" translatesAutoresizingMaskIntoConstraints="NO" id="WGY-kX-mAx">
<rect key="frame" x="0.0" y="64" width="600" height="536"/>
<color key="backgroundColor" red="0.20392156859999999" green="0.28627450980000002" blue="0.36862745099999999" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
<color key="separatorColor" red="0.20392156859999999" green="0.28627450980000002" blue="0.36862745099999999" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
<rect key="frame" x="0.0" y="64" width="375" height="603"/>
<color key="backgroundColor" red="0.15542715787887573" green="0.2203737199306488" blue="0.2959403395652771" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
<color key="separatorColor" red="0.15542715787887573" green="0.2203737199306488" blue="0.2959403395652771" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
<view key="tableHeaderView" contentMode="scaleToFill" id="iaH-1W-Sbo">
<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"/>
<subviews>
<segmentedControl opaque="NO" contentMode="scaleToFill" contentHorizontalAlignment="left" contentVerticalAlignment="top" segmentControlStyle="bordered" selectedSegmentIndex="0" translatesAutoresizingMaskIntoConstraints="NO" id="YVj-dA-fyV">
@@ -709,13 +932,13 @@
<segment title="Fetch"/>
<segment title="Query"/>
</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>
<action selector="segmentedControlValueChanged:" destination="qbj-MK-nIY" eventType="valueChanged" id="Wok-dl-uq7"/>
</connections>
</segmentedControl>
</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>
<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"/>
@@ -724,15 +947,17 @@
</view>
<prototypes>
<tableViewCell contentMode="scaleToFill" selectionStyle="default" accessoryType="disclosureIndicator" indentationWidth="10" reuseIdentifier="UITableViewCell" textLabel="6db-P0-6Ms" style="IBUITableViewCellStyleDefault" id="vUr-WV-qur">
<rect key="frame" x="0.0" y="0.0" width="600" height="44"/>
<rect key="frame" x="0.0" y="102" width="375" height="44"/>
<autoresizingMask key="autoresizingMask"/>
<tableViewCellContentView key="contentView" opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center" tableViewCell="vUr-WV-qur" id="Vr0-hE-cn9">
<rect key="frame" x="0.0" y="0.0" width="342" height="43.5"/>
<autoresizingMask key="autoresizingMask"/>
<subviews>
<label opaque="NO" multipleTouchEnabled="YES" contentMode="left" text="Title" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" id="6db-P0-6Ms">
<rect key="frame" x="15" y="0.0" width="325" height="43.5"/>
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMaxY="YES"/>
<fontDescription key="fontDescription" name="HelveticaNeue-Light" family="Helvetica Neue" pointSize="18"/>
<color key="textColor" red="0.17254901959999999" green="0.24313725489999999" blue="0.31372549020000001" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
<color key="textColor" red="0.13079629838466644" green="0.184075728058815" blue="0.24594299495220184" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
<nil key="highlightedColor"/>
</label>
</subviews>
@@ -745,7 +970,7 @@
</connections>
</tableView>
</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>
<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"/>
@@ -770,26 +995,30 @@
<objects>
<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">
<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"/>
<color key="backgroundColor" red="0.20392156859999999" green="0.28627450980000002" blue="0.36862745099999999" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
<color key="separatorColor" red="0.20392156859999999" green="0.28627450980000002" blue="0.36862745099999999" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
<color key="backgroundColor" red="0.15542715787887573" green="0.2203737199306488" blue="0.2959403395652771" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
<color key="separatorColor" red="0.15542715787887573" green="0.2203737199306488" blue="0.2959403395652771" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
<prototypes>
<tableViewCell contentMode="scaleToFill" selectionStyle="none" indentationWidth="10" reuseIdentifier="UITableViewCell" textLabel="RgX-yK-1L2" detailTextLabel="QZ4-A2-x4h" style="IBUITableViewCellStyleSubtitle" id="uBt-Iy-nWP">
<rect key="frame" x="0.0" y="36" width="375" height="60"/>
<autoresizingMask key="autoresizingMask"/>
<tableViewCellContentView key="contentView" opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center" tableViewCell="uBt-Iy-nWP" id="6SD-ur-9zp">
<rect key="frame" x="0.0" y="0.0" width="375" height="59.5"/>
<autoresizingMask key="autoresizingMask"/>
<subviews>
<label opaque="NO" multipleTouchEnabled="YES" contentMode="left" text="name" lineBreakMode="wordWrap" numberOfLines="0" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" id="RgX-yK-1L2">
<rect key="frame" x="15" y="11" width="48.5" height="24"/>
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMaxY="YES"/>
<fontDescription key="fontDescription" name="HelveticaNeue-Light" family="Helvetica Neue" pointSize="20"/>
<color key="textColor" red="0.17254901959999999" green="0.24313725489999999" blue="0.31372549020000001" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
<color key="textColor" red="0.13079629838466644" green="0.184075728058815" blue="0.24594299495220184" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
<nil key="highlightedColor"/>
</label>
<label opaque="NO" multipleTouchEnabled="YES" contentMode="left" text="offset" lineBreakMode="wordWrap" numberOfLines="0" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" id="QZ4-A2-x4h">
<rect key="frame" x="15" y="35" width="31" height="13.5"/>
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMaxY="YES"/>
<fontDescription key="fontDescription" type="system" pointSize="11"/>
<color key="textColor" red="0.17254901959999999" green="0.24313725489999999" blue="0.31372549020000001" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
<color key="textColor" red="0.13079629838466644" green="0.184075728058815" blue="0.24594299495220184" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
<nil key="highlightedColor"/>
</label>
</subviews>
@@ -812,26 +1041,30 @@
<objects>
<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">
<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"/>
<color key="backgroundColor" red="0.20392156859999999" green="0.28627450980000002" blue="0.36862745099999999" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
<color key="separatorColor" red="0.20392156859999999" green="0.28627450980000002" blue="0.36862745099999999" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
<color key="backgroundColor" red="0.15542715787887573" green="0.2203737199306488" blue="0.2959403395652771" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
<color key="separatorColor" red="0.15542715787887573" green="0.2203737199306488" blue="0.2959403395652771" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
<prototypes>
<tableViewCell contentMode="scaleToFill" selectionStyle="none" indentationWidth="10" reuseIdentifier="UITableViewCell" textLabel="Syt-QJ-KXg" detailTextLabel="yHS-dP-IKS" style="IBUITableViewCellStyleSubtitle" id="q7Q-aF-Ftl">
<rect key="frame" x="0.0" y="36" width="375" height="60"/>
<autoresizingMask key="autoresizingMask"/>
<tableViewCellContentView key="contentView" opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center" tableViewCell="q7Q-aF-Ftl" id="fc3-eg-yes">
<rect key="frame" x="0.0" y="0.0" width="375" height="59.5"/>
<autoresizingMask key="autoresizingMask"/>
<subviews>
<label opaque="NO" multipleTouchEnabled="YES" contentMode="left" text="name" lineBreakMode="wordWrap" numberOfLines="0" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" id="Syt-QJ-KXg">
<rect key="frame" x="15" y="11" width="48.5" height="24"/>
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMaxY="YES"/>
<fontDescription key="fontDescription" name="HelveticaNeue-Light" family="Helvetica Neue" pointSize="20"/>
<color key="textColor" red="0.17254901959999999" green="0.24313725489999999" blue="0.31372549020000001" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
<color key="textColor" red="0.13079629838466644" green="0.184075728058815" blue="0.24594299495220184" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
<nil key="highlightedColor"/>
</label>
<label opaque="NO" multipleTouchEnabled="YES" contentMode="left" text="offset" lineBreakMode="wordWrap" numberOfLines="0" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" id="yHS-dP-IKS">
<rect key="frame" x="15" y="35" width="31" height="13.5"/>
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMaxY="YES"/>
<fontDescription key="fontDescription" type="system" pointSize="11"/>
<color key="textColor" red="0.17254901959999999" green="0.24313725489999999" blue="0.31372549020000001" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
<color key="textColor" red="0.13079629838466644" green="0.184075728058815" blue="0.24594299495220184" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
<nil key="highlightedColor"/>
</label>
</subviews>
@@ -854,6 +1087,6 @@
<image name="second" width="30" height="30"/>
</resources>
<inferredMetricsTieBreakers>
<segue reference="hyN-De-zte"/>
<segue reference="fIB-GS-Ppk"/>
</inferredMetricsTieBreakers>
</document>
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<model userDefinedModelVersionIdentifier="" type="com.apple.IDECoreDataModeler.DataModel" documentVersion="1.0" lastSavedToolsVersion="7701" systemVersion="14D136" minimumToolsVersion="Automatic" macOSVersion="Automatic" iOSVersion="Automatic">
<model userDefinedModelVersionIdentifier="" type="com.apple.IDECoreDataModeler.DataModel" documentVersion="1.0" lastSavedToolsVersion="10169.1" systemVersion="15D21" minimumToolsVersion="Automatic">
<entity name="Palette" representedClassName="CoreStoreDemo.Palette">
<attribute name="brightness" optional="YES" attributeType="Float" defaultValueString="0.0" syncable="YES"/>
<attribute name="colorName" optional="YES" transient="YES" attributeType="String" syncable="YES"/>
@@ -3,7 +3,7 @@
// CoreStoreDemo
//
// Created by John Rommel Estropia on 2015/06/12.
// Copyright (c) 2015 John Rommel Estropia. All rights reserved.
// Copyright © 2015 John Rommel Estropia. All rights reserved.
//
import UIKit
@@ -15,31 +15,31 @@ private struct Static {
static let timeZonesStack: DataStack = {
let dataStack = DataStack()
dataStack.addSQLiteStoreAndWait(
"TimeZoneDemo.sqlite",
try! dataStack.addStorageAndWait(
SQLiteStore(
fileName: "TimeZoneDemo.sqlite",
configuration: "FetchingAndQueryingDemo",
resetStoreOnMigrationFailure: true
localStorageOptions: .recreateStoreOnModelMismatch
)
)
_ = try? dataStack.perform(
synchronous: { (transaction) in
dataStack.beginSynchronous { (transaction) -> Void in
transaction.deleteAll(From<TimeZone>())
transaction.deleteAll(From(TimeZone))
for name in NSTimeZone.knownTimeZoneNames() as! [String] {
for name in NSTimeZone.knownTimeZoneNames {
let rawTimeZone = NSTimeZone(name: name)!
let cachedTimeZone = transaction.create(Into(TimeZone))
let cachedTimeZone = transaction.create(Into<TimeZone>())
cachedTimeZone.name = rawTimeZone.name
cachedTimeZone.abbreviation = rawTimeZone.abbreviation ?? ""
cachedTimeZone.secondsFromGMT = Int32(rawTimeZone.secondsFromGMT)
cachedTimeZone.hasDaylightSavingTime = rawTimeZone.daylightSavingTime
cachedTimeZone.hasDaylightSavingTime = rawTimeZone.isDaylightSavingTime
cachedTimeZone.daylightSavingTimeOffset = rawTimeZone.daylightSavingTimeOffset
}
transaction.commit()
}
)
return dataStack
}()
}
@@ -51,7 +51,7 @@ class FetchingAndQueryingDemoViewController: UIViewController, UITableViewDataSo
// MARK: UIViewController
override func viewDidAppear(animated: Bool) {
override func viewDidAppear(_ animated: Bool) {
super.viewDidAppear(animated)
@@ -65,27 +65,27 @@ class FetchingAndQueryingDemoViewController: UIViewController, UITableViewDataSo
let alert = UIAlertController(
title: "Fetch and Query Demo",
message: "This demo shows how to execute fetches and queries.\n\nEach menu item executes and displays a preconfigured fetch/query.",
preferredStyle: .Alert
preferredStyle: .alert
)
alert.addAction(UIAlertAction(title: "OK", style: .Cancel, handler: nil))
self.presentViewController(alert, animated: true, completion: nil)
alert.addAction(UIAlertAction(title: "OK", style: .cancel, handler: 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:
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:
let item = self.queryingItems[indexPath.row]
controller.setValue(item.query(), title: item.title)
controller.set(value: item.query(), title: item.title)
default:
break
@@ -96,13 +96,14 @@ class FetchingAndQueryingDemoViewController: UIViewController, UITableViewDataSo
// MARK: UITableViewDataSource
func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
switch self.segmentedControl?.selectedSegmentIndex {
case .Some(Section.Fetching.rawValue):
case Section.fetching.rawValue?:
return self.fetchingItems.count
case .Some(Section.Querying.rawValue):
case Section.querying.rawValue?:
return self.queryingItems.count
default:
@@ -110,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") as! UITableViewCell
let cell = tableView.dequeueReusableCell(withIdentifier: "UITableViewCell")!
switch self.segmentedControl?.selectedSegmentIndex {
case .Some(Section.Fetching.rawValue):
case Section.fetching.rawValue?:
cell.textLabel?.text = self.fetchingItems[indexPath.row].title
case .Some(Section.Querying.rawValue):
case Section.querying.rawValue?:
cell.textLabel?.text = self.queryingItems[indexPath.row].title
default:
@@ -132,17 +133,17 @@ class FetchingAndQueryingDemoViewController: UIViewController, UITableViewDataSo
// 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 {
case .Some(Section.Fetching.rawValue):
self.performSegueWithIdentifier("FetchingResultsViewController", sender: indexPath)
case Section.fetching.rawValue?:
self.performSegue(withIdentifier: "FetchingResultsViewController", sender: indexPath)
case .Some(Section.Querying.rawValue):
self.performSegueWithIdentifier("QueryingResultsViewController", sender: indexPath)
case Section.querying.rawValue?:
self.performSegue(withIdentifier: "QueryingResultsViewController", sender: indexPath)
default:
break
@@ -154,8 +155,8 @@ class FetchingAndQueryingDemoViewController: UIViewController, UITableViewDataSo
private enum Section: Int {
case Fetching
case Querying
case fetching
case querying
}
private let fetchingItems = [
@@ -164,8 +165,8 @@ class FetchingAndQueryingDemoViewController: UIViewController, UITableViewDataSo
fetch: { () -> [TimeZone] in
return Static.timeZonesStack.fetchAll(
From(TimeZone),
OrderBy(.Ascending("name"))
From<TimeZone>(),
OrderBy(.ascending(#keyPath(TimeZone.name)))
)!
}
),
@@ -174,9 +175,9 @@ class FetchingAndQueryingDemoViewController: UIViewController, UITableViewDataSo
fetch: { () -> [TimeZone] in
return Static.timeZonesStack.fetchAll(
From(TimeZone),
Where("%K BEGINSWITH[c] %@", "name", "Asia"),
OrderBy(.Ascending("secondsFromGMT"))
From<TimeZone>(),
Where("%K BEGINSWITH[c] %@", #keyPath(TimeZone.name), "Asia"),
OrderBy(.ascending(#keyPath(TimeZone.secondsFromGMT)))
)!
}
),
@@ -185,10 +186,10 @@ class FetchingAndQueryingDemoViewController: UIViewController, UITableViewDataSo
fetch: { () -> [TimeZone] in
return Static.timeZonesStack.fetchAll(
From(TimeZone),
Where("%K BEGINSWITH[c] %@", "name", "America")
|| Where("%K BEGINSWITH[c] %@", "name", "Europe"),
OrderBy(.Ascending("secondsFromGMT"))
From<TimeZone>(),
Where("%K BEGINSWITH[c] %@", #keyPath(TimeZone.name), "America")
|| Where("%K BEGINSWITH[c] %@", #keyPath(TimeZone.name), "Europe"),
OrderBy(.ascending(#keyPath(TimeZone.secondsFromGMT)))
)!
}
),
@@ -197,9 +198,9 @@ class FetchingAndQueryingDemoViewController: UIViewController, UITableViewDataSo
fetch: { () -> [TimeZone] in
return Static.timeZonesStack.fetchAll(
From(TimeZone),
!Where("%K BEGINSWITH[c] %@", "name", "America"),
OrderBy(.Ascending("secondsFromGMT"))
From<TimeZone>(),
!Where("%K BEGINSWITH[c] %@", #keyPath(TimeZone.name), "America"),
OrderBy(.ascending(#keyPath(TimeZone.secondsFromGMT)))
)!
}
),
@@ -208,9 +209,9 @@ class FetchingAndQueryingDemoViewController: UIViewController, UITableViewDataSo
fetch: { () -> [TimeZone] in
return Static.timeZonesStack.fetchAll(
From(TimeZone),
From<TimeZone>(),
Where("hasDaylightSavingTime", isEqualTo: true),
OrderBy(.Ascending("name"))
OrderBy(.ascending(#keyPath(TimeZone.name)))
)!
}
)
@@ -219,60 +220,60 @@ class FetchingAndQueryingDemoViewController: UIViewController, UITableViewDataSo
private let queryingItems = [
(
title: "Number of Time Zones",
query: { () -> AnyObject in
query: { () -> Any in
return Static.timeZonesStack.queryValue(
From(TimeZone),
Select<NSNumber>(.Count("name"))
From<TimeZone>(),
Select<NSNumber>(.count(#keyPath(TimeZone.name)))
)!
}
),
(
title: "Abbreviation For Tokyo's Time Zone",
query: { () -> AnyObject in
query: { () -> Any in
return Static.timeZonesStack.queryValue(
From(TimeZone),
Select<String>("abbreviation"),
Where("%K ENDSWITH[c] %@", "name", "Tokyo")
From<TimeZone>(),
Select<String>(#keyPath(TimeZone.abbreviation)),
Where("%K ENDSWITH[c] %@", #keyPath(TimeZone.name), "Tokyo")
)!
}
),
(
title: "All Abbreviations",
query: { () -> AnyObject in
query: { () -> Any in
return Static.timeZonesStack.queryAttributes(
From(TimeZone),
Select<NSDictionary>("name", "abbreviation"),
OrderBy(.Ascending("name"))
From<TimeZone>(),
Select<NSDictionary>(#keyPath(TimeZone.name), #keyPath(TimeZone.abbreviation)),
OrderBy(.ascending(#keyPath(TimeZone.name)))
)!
}
),
(
title: "Number of Countries per Time Zone",
query: { () -> AnyObject in
query: { () -> Any in
return Static.timeZonesStack.queryAttributes(
From(TimeZone),
Select<NSDictionary>(.Count("abbreviation"), "abbreviation"),
GroupBy("abbreviation"),
OrderBy(.Ascending("secondsFromGMT"), .Ascending("name"))
From<TimeZone>(),
Select<NSDictionary>(.count(#keyPath(TimeZone.abbreviation)), #keyPath(TimeZone.abbreviation)),
GroupBy(#keyPath(TimeZone.abbreviation)),
OrderBy(.ascending(#keyPath(TimeZone.secondsFromGMT)), .ascending(#keyPath(TimeZone.name)))
)!
}
),
(
title: "Number of Countries with Summer Time",
query: { () -> AnyObject in
query: { () -> Any in
return Static.timeZonesStack.queryAttributes(
From(TimeZone),
From<TimeZone>(),
Select<NSDictionary>(
.Count("hasDaylightSavingTime", As: "numberOfCountries"),
"hasDaylightSavingTime"
.count(#keyPath(TimeZone.hasDaylightSavingTime), as: "numberOfCountries"),
#keyPath(TimeZone.hasDaylightSavingTime)
),
GroupBy("hasDaylightSavingTime"),
OrderBy(.Descending("hasDaylightSavingTime"))
GroupBy(#keyPath(TimeZone.hasDaylightSavingTime)),
OrderBy(.descending(#keyPath(TimeZone.hasDaylightSavingTime)))
)!
}
)
@@ -283,7 +284,7 @@ class FetchingAndQueryingDemoViewController: UIViewController, UITableViewDataSo
@IBOutlet dynamic weak var segmentedControl: UISegmentedControl?
@IBOutlet dynamic weak var tableView: UITableView?
@IBAction dynamic func segmentedControlValueChanged(sender: AnyObject?) {
@IBAction dynamic func segmentedControlValueChanged(_ sender: AnyObject?) {
self.tableView?.reloadData()
}
@@ -3,7 +3,7 @@
// CoreStoreDemo
//
// Created by John Rommel Estropia on 2015/06/17.
// Copyright (c) 2015 John Rommel Estropia. All rights reserved.
// Copyright © 2015 John Rommel Estropia. All rights reserved.
//
import UIKit
@@ -14,7 +14,7 @@ class FetchingResultsViewController: UITableViewController {
// MARK: Public
func setTimeZones(timeZones: [TimeZone]?, title: String) {
func set(timeZones: [TimeZone]?, title: String) {
self.timeZones += timeZones ?? []
self.sectionTitle = title
@@ -36,14 +36,14 @@ class FetchingResultsViewController: UITableViewController {
// MARK: UITableViewDataSource
override func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
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) as! UITableViewCell
let cell = tableView.dequeueReusableCell(withIdentifier: "UITableViewCell", for: indexPath)
let timeZone = self.timeZones[indexPath.row]
cell.textLabel?.text = timeZone.name
@@ -55,7 +55,7 @@ class FetchingResultsViewController: UITableViewController {
// MARK: UITableViewDelegate
override func tableView(tableView: UITableView, titleForHeaderInSection section: Int) -> String? {
override func tableView(_ tableView: UITableView, titleForHeaderInSection section: Int) -> String? {
return self.sectionTitle
}
@@ -3,7 +3,7 @@
// CoreStoreDemo
//
// Created by John Rommel Estropia on 2015/06/17.
// Copyright (c) 2015 John Rommel Estropia. All rights reserved.
// Copyright © 2015 John Rommel Estropia. All rights reserved.
//
import UIKit
@@ -12,23 +12,23 @@ class QueryingResultsViewController: UITableViewController {
// MARK: Public
func setValue(value: AnyObject?, title: String) {
func set(value: Any?, title: String) {
switch value {
case .Some(let array as [AnyObject]):
self.values = array.map { (item: AnyObject) -> (title: String, detail: String) in
case (let array as [Any])?:
self.values = array.map { (item: Any) -> (title: String, detail: String) in
(
title: item.description,
detail: _stdlib_getDemangledTypeName(item)
title: String(describing: item),
detail: String(reflecting: type(of: item))
)
}
case .Some(let item):
case let item?:
self.values = [
(
title: item.description,
detail: _stdlib_getDemangledTypeName(item)
title: String(describing: item),
detail: String(reflecting: type(of: item))
)
]
@@ -55,14 +55,14 @@ class QueryingResultsViewController: UITableViewController {
// MARK: UITableViewDataSource
override func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
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) as! UITableViewCell
let cell = tableView.dequeueReusableCell(withIdentifier: "UITableViewCell", for: indexPath)
let value = self.values[indexPath.row]
@@ -75,7 +75,7 @@ class QueryingResultsViewController: UITableViewController {
// MARK: UITableViewDelegate
override func tableView(tableView: UITableView, titleForHeaderInSection section: Int) -> String? {
override func tableView(_ tableView: UITableView, titleForHeaderInSection section: Int) -> String? {
return self.sectionTitle
}
@@ -3,7 +3,7 @@
// CoreStoreDemo
//
// Created by John Rommel Estropia on 2015/06/15.
// Copyright (c) 2015 John Rommel Estropia. All rights reserved.
// Copyright © 2015 John Rommel Estropia. All rights reserved.
//
import Foundation
@@ -21,13 +21,33 @@
"scale" : "3x"
},
{
"idiom" : "iphone",
"size" : "60x60",
"idiom" : "iphone",
"filename" : "Icon-60@2x.png",
"scale" : "2x"
},
{
"idiom" : "iphone",
"size" : "60x60",
"idiom" : "iphone",
"filename" : "Icon-60@3x-1.png",
"scale" : "3x"
},
{
"size" : "76x76",
"idiom" : "ipad",
"filename" : "Icon-76.png",
"scale" : "1x"
},
{
"size" : "76x76",
"idiom" : "ipad",
"filename" : "Icon-76@2x.png",
"scale" : "2x"
},
{
"size" : "60x60",
"idiom" : "car",
"filename" : "Icon-60@3x.png",
"scale" : "3x"
}
],
Binary file not shown.

After

Width:  |  Height:  |  Size: 7.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 11 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 11 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 9.3 KiB

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

After

Width:  |  Height:  |  Size: 28 KiB

+4 -2
View File
@@ -4,10 +4,12 @@
<dict>
<key>CFBundleDevelopmentRegion</key>
<string>en</string>
<key>CFBundleDisplayName</key>
<string>CoreStore</string>
<key>CFBundleExecutable</key>
<string>$(EXECUTABLE_NAME)</string>
<key>CFBundleIdentifier</key>
<string>com.johnestropia.CoreStoreDemo</string>
<string>$(PRODUCT_BUNDLE_IDENTIFIER)</string>
<key>CFBundleInfoDictionaryVersion</key>
<string>6.0</string>
<key>CFBundleName</key>
@@ -15,7 +17,7 @@
<key>CFBundlePackageType</key>
<string>APPL</string>
<key>CFBundleShortVersionString</key>
<string>1.0</string>
<string>1.0.1</string>
<key>CFBundleSignature</key>
<string>????</string>
<key>CFBundleVersion</key>
@@ -0,0 +1,315 @@
//
// ListObserverDemoViewController.swift
// CoreStoreDemo
//
// Created by John Rommel Estropia on 2015/05/02.
// Copyright © 2015 John Rommel Estropia. All rights reserved.
//
import UIKit
import CoreStore
private struct Static {
enum Filter: String {
case all = "All Colors"
case light = "Light Colors"
case dark = "Dark Colors"
func next() -> Filter {
switch self {
case .all: return .light
case .light: return .dark
case .dark: return .all
}
}
func whereClause() -> Where {
switch self {
case .all: return Where(true)
case .light: return Where("%K >= %@", #keyPath(Palette.brightness), 0.9)
case .dark: return Where("%K <= %@", #keyPath(Palette.brightness), 0.4)
}
}
}
static var filter = Filter.all {
didSet {
self.palettes.refetch(
self.filter.whereClause(),
OrderBy(.ascending(#keyPath(Palette.hue)))
)
}
}
static let palettes: ListMonitor<Palette> = {
try! CoreStore.addStorageAndWait(
SQLiteStore(
fileName: "ColorsDemo.sqlite",
configuration: "ObservingDemo",
localStorageOptions: .recreateStoreOnModelMismatch
)
)
return CoreStore.monitorSectionedList(
From<Palette>(),
SectionBy(#keyPath(Palette.colorName)),
OrderBy(.ascending(#keyPath(Palette.hue)))
)
}()
}
// MARK: - ListObserverDemoViewController
class ListObserverDemoViewController: UITableViewController, ListSectionObserver {
// MARK: NSObject
deinit {
Static.palettes.removeObserver(self)
}
// MARK: UIViewController
override func viewDidLoad() {
super.viewDidLoad()
let navigationItem = self.navigationItem
navigationItem.leftBarButtonItems = [
self.editButtonItem,
UIBarButtonItem(
barButtonSystemItem: .trash,
target: self,
action: #selector(self.resetBarButtonItemTouched(_:))
)
]
let filterBarButton = UIBarButtonItem(
title: Static.filter.rawValue,
style: .plain,
target: self,
action: #selector(self.filterBarButtonItemTouched(_:))
)
navigationItem.rightBarButtonItems = [
UIBarButtonItem(
barButtonSystemItem: .add,
target: self,
action: #selector(self.addBarButtonItemTouched(_:))
),
filterBarButton
]
self.filterBarButton = filterBarButton
Static.palettes.addObserver(self)
self.setTable(enabled: !Static.palettes.isPendingRefetch)
}
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
super.prepare(for: segue, sender: sender)
switch (segue.identifier, segue.destination, sender) {
case ("ObjectObserverDemoViewController"?, let destinationViewController as ObjectObserverDemoViewController, let palette as Palette):
destinationViewController.palette = palette
default:
break
}
}
// MARK: UITableViewDataSource
override func numberOfSections(in tableView: UITableView) -> Int {
return Static.palettes.numberOfSections()
}
override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return Static.palettes.numberOfObjectsInSection(section)
}
override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "PaletteTableViewCell") as! PaletteTableViewCell
let palette = Static.palettes[indexPath]
cell.colorView?.backgroundColor = palette.color
cell.label?.text = palette.colorText
return cell
}
// MARK: UITableViewDelegate
override func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
tableView.deselectRow(at: indexPath, animated: true)
self.performSegue(
withIdentifier: "ObjectObserverDemoViewController",
sender: Static.palettes[indexPath]
)
}
override func tableView(_ tableView: UITableView, commit editingStyle: UITableViewCellEditingStyle, forRowAt indexPath: IndexPath) {
switch editingStyle {
case .delete:
let palette = Static.palettes[indexPath]
CoreStore.perform(
asynchronous: { (transaction) in
transaction.delete(palette)
},
completion: { _ in }
)
default:
break
}
}
override func tableView(_ tableView: UITableView, titleForHeaderInSection section: Int) -> String? {
return Static.palettes.sectionInfoAtIndex(section).name
}
// MARK: ListObserver
func listMonitorWillChange(_ monitor: ListMonitor<Palette>) {
self.tableView.beginUpdates()
}
func listMonitorDidChange(_ monitor: ListMonitor<Palette>) {
self.tableView.endUpdates()
}
func listMonitorWillRefetch(_ monitor: ListMonitor<Palette>) {
self.setTable(enabled: false)
}
func listMonitorDidRefetch(_ monitor: ListMonitor<Palette>) {
self.filterBarButton?.title = Static.filter.rawValue
self.tableView.reloadData()
self.setTable(enabled: true)
}
// MARK: ListObjectObserver
func listMonitor(_ monitor: ListMonitor<Palette>, didInsertObject object: Palette, toIndexPath indexPath: IndexPath) {
self.tableView.insertRows(at: [indexPath], with: .automatic)
}
func listMonitor(_ monitor: ListMonitor<Palette>, didDeleteObject object: Palette, fromIndexPath indexPath: IndexPath) {
self.tableView.deleteRows(at: [indexPath], with: .automatic)
}
func listMonitor(_ monitor: ListMonitor<Palette>, didUpdateObject object: Palette, atIndexPath indexPath: IndexPath) {
if let cell = self.tableView.cellForRow(at: indexPath) as? PaletteTableViewCell {
let palette = Static.palettes[indexPath]
cell.colorView?.backgroundColor = palette.color
cell.label?.text = palette.colorText
}
}
func listMonitor(_ monitor: ListMonitor<Palette>, didMoveObject object: Palette, fromIndexPath: IndexPath, toIndexPath: IndexPath) {
self.tableView.deleteRows(at: [fromIndexPath], with: .automatic)
self.tableView.insertRows(at: [toIndexPath], with: .automatic)
}
// MARK: ListSectionObserver
func listMonitor(_ monitor: ListMonitor<Palette>, didInsertSection sectionInfo: NSFetchedResultsSectionInfo, toSectionIndex sectionIndex: Int) {
self.tableView.insertSections(IndexSet(integer: sectionIndex), with: .automatic)
}
func listMonitor(_ monitor: ListMonitor<Palette>, didDeleteSection sectionInfo: NSFetchedResultsSectionInfo, fromSectionIndex sectionIndex: Int) {
self.tableView.deleteSections(IndexSet(integer: sectionIndex), with: .automatic)
}
// MARK: Private
private var filterBarButton: UIBarButtonItem?
@IBAction private dynamic func resetBarButtonItemTouched(_ sender: AnyObject?) {
CoreStore.perform(
asynchronous: { (transaction) in
transaction.deleteAll(From<Palette>())
},
completion: { _ in }
)
}
@IBAction private dynamic func filterBarButtonItemTouched(_ sender: AnyObject?) {
Static.filter = Static.filter.next()
}
@IBAction private dynamic func addBarButtonItemTouched(_ sender: AnyObject?) {
CoreStore.perform(
asynchronous: { (transaction) in
let palette = transaction.create(Into<Palette>())
palette.setInitialValues()
},
completion: { _ in }
)
}
private func setTable(enabled: Bool) {
UIView.animate(
withDuration: 0.2,
delay: 0,
options: .beginFromCurrentState,
animations: { () -> Void in
if let tableView = self.tableView {
tableView.alpha = enabled ? 1.0 : 0.5
tableView.isUserInteractionEnabled = enabled
}
},
completion: nil
)
}
}
@@ -1,218 +0,0 @@
//
// ObjectListObserverDemoViewController.swift
// CoreStoreDemo
//
// Created by John Rommel Estropia on 2015/05/02.
// Copyright (c) 2015 John Rommel Estropia. All rights reserved.
//
import UIKit
import CoreStore
private struct Static {
static let palettes: ManagedObjectListController<Palette> = {
CoreStore.addSQLiteStoreAndWait(
"ColorsDemo.sqlite",
configuration: "ObservingDemo",
resetStoreOnMigrationFailure: true
)
return CoreStore.observeSectionedList(
From(Palette),
SectionedBy("colorName"),
OrderBy(.Ascending("hue"))
)
}()
}
// MARK: - ObjectListObserverDemoViewController
class ObjectListObserverDemoViewController: UITableViewController, ManagedObjectListSectionObserver {
// MARK: NSObject
deinit {
Static.palettes.removeObserver(self)
}
// MARK: UIViewController
override func viewDidLoad() {
super.viewDidLoad()
self.navigationItem.leftBarButtonItems = [
self.editButtonItem(),
UIBarButtonItem(
barButtonSystemItem: .Trash,
target: self,
action: "resetBarButtonItemTouched:"
)
]
self.navigationItem.rightBarButtonItem = UIBarButtonItem(
barButtonSystemItem: .Add,
target: self,
action: "addBarButtonItemTouched:"
)
Static.palettes.addObserver(self)
}
override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) {
super.prepareForSegue(segue, sender: sender)
switch (segue.identifier, segue.destinationViewController, sender) {
case (.Some("ObjectObserverDemoViewController"), let destinationViewController as ObjectObserverDemoViewController, let palette as Palette):
destinationViewController.palette = palette
default:
break
}
}
// MARK: UITableViewDataSource
override func numberOfSectionsInTableView(tableView: UITableView) -> Int {
return Static.palettes.numberOfSections()
}
override func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return Static.palettes.numberOfObjectsInSection(section)
}
override func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCellWithIdentifier("PaletteTableViewCell") as! PaletteTableViewCell
let palette = Static.palettes[indexPath]
cell.colorView?.backgroundColor = palette.color
cell.label?.text = palette.colorText
return cell
}
// MARK: UITableViewDelegate
override func tableView(tableView: UITableView, didSelectRowAtIndexPath indexPath: NSIndexPath) {
tableView.deselectRowAtIndexPath(indexPath, animated: true)
self.performSegueWithIdentifier(
"ObjectObserverDemoViewController",
sender: Static.palettes[indexPath]
)
}
override func tableView(tableView: UITableView, commitEditingStyle editingStyle: UITableViewCellEditingStyle, forRowAtIndexPath indexPath: NSIndexPath) {
switch editingStyle {
case .Delete:
let palette = Static.palettes[indexPath]
CoreStore.beginAsynchronous{ (transaction) -> Void in
transaction.delete(palette)
transaction.commit { (result) -> Void in }
}
default:
break
}
}
override func tableView(tableView: UITableView, titleForHeaderInSection section: Int) -> String? {
return Static.palettes.sectionInfoAtIndex(section).name
}
// MARK: ManagedObjectListChangeObserver
func managedObjectListWillChange(listController: ManagedObjectListController<Palette>) {
self.tableView.beginUpdates()
}
func managedObjectListDidChange(listController: ManagedObjectListController<Palette>) {
self.tableView.endUpdates()
}
// MARK: ManagedObjectListObjectObserver
func managedObjectList(listController: ManagedObjectListController<Palette>, didInsertObject object: Palette, toIndexPath indexPath: NSIndexPath) {
self.tableView.insertRowsAtIndexPaths([indexPath], withRowAnimation: .Automatic)
}
func managedObjectList(listController: ManagedObjectListController<Palette>, didDeleteObject object: Palette, fromIndexPath indexPath: NSIndexPath) {
self.tableView.deleteRowsAtIndexPaths([indexPath], withRowAnimation: .Automatic)
}
func managedObjectList(listController: ManagedObjectListController<Palette>, didUpdateObject object: Palette, atIndexPath indexPath: NSIndexPath) {
if let cell = self.tableView.cellForRowAtIndexPath(indexPath) as? PaletteTableViewCell {
let palette = Static.palettes[indexPath]
cell.colorView?.backgroundColor = palette.color
cell.label?.text = palette.colorText
}
}
func managedObjectList(listController: ManagedObjectListController<Palette>, didMoveObject object: Palette, fromIndexPath: NSIndexPath, toIndexPath: NSIndexPath) {
self.tableView.deleteRowsAtIndexPaths([fromIndexPath], withRowAnimation: .Automatic)
self.tableView.insertRowsAtIndexPaths([toIndexPath], withRowAnimation: .Automatic)
}
// MARK: ManagedObjectListSectionObserver
func managedObjectList(listController: ManagedObjectListController<Palette>, didInsertSection sectionInfo: NSFetchedResultsSectionInfo, toSectionIndex sectionIndex: Int) {
self.tableView.insertSections(NSIndexSet(index: sectionIndex), withRowAnimation: .Automatic)
}
func managedObjectList(listController: ManagedObjectListController<Palette>, didDeleteSection sectionInfo: NSFetchedResultsSectionInfo, fromSectionIndex sectionIndex: Int) {
self.tableView.deleteSections(NSIndexSet(index: sectionIndex), withRowAnimation: .Automatic)
}
// MARK: Private
@IBAction dynamic func resetBarButtonItemTouched(sender: AnyObject?) {
CoreStore.beginAsynchronous { (transaction) -> Void in
transaction.deleteAll(From(Palette))
transaction.commit()
}
}
@IBAction dynamic func addBarButtonItemTouched(sender: AnyObject?) {
CoreStore.beginAsynchronous { (transaction) -> Void in
let palette = transaction.create(Into(Palette))
palette.setInitialValues()
transaction.commit()
}
}
}
@@ -3,7 +3,7 @@
// CoreStoreDemo
//
// Created by John Rommel Estropia on 2015/05/06.
// Copyright (c) 2015 John Rommel Estropia. All rights reserved.
// Copyright © 2015 John Rommel Estropia. All rights reserved.
//
import UIKit
@@ -12,23 +12,28 @@ import CoreStore
// MARK: - ObjectObserverDemoViewController
class ObjectObserverDemoViewController: UIViewController, ManagedObjectObserver {
class ObjectObserverDemoViewController: UIViewController, ObjectObserver {
var palette: Palette? {
get {
return self.objectController?.object
return self.monitor?.object
}
set {
guard self.monitor?.object != newValue else {
return
}
if let palette = newValue {
self.objectController = CoreStore.observeObject(palette)
self.monitor = CoreStore.monitorObject(palette)
}
else {
self.objectController = nil
self.monitor = nil
}
}
}
@@ -37,30 +42,30 @@ class ObjectObserverDemoViewController: UIViewController, ManagedObjectObserver
deinit {
self.objectController?.removeObserver(self)
self.monitor?.removeObserver(self)
}
// MARK: UIViewController
required init(coder aDecoder: NSCoder) {
required init?(coder aDecoder: NSCoder) {
if let palette = CoreStore.fetchOne(From(Palette), OrderBy(.Ascending("hue"))) {
if let palette = CoreStore.fetchOne(From<Palette>(), OrderBy(.ascending(#keyPath(Palette.hue)))) {
self.objectController = CoreStore.observeObject(palette)
self.monitor = CoreStore.monitorObject(palette)
}
else {
CoreStore.beginSynchronous { (transaction) -> Void in
_ = try? CoreStore.perform(
synchronous: { (transaction) in
let palette = transaction.create(Into(Palette))
let palette = transaction.create(Into(Palette.self))
palette.setInitialValues()
transaction.commit()
}
)
let palette = CoreStore.fetchOne(From(Palette), OrderBy(.Ascending("hue")))!
self.objectController = CoreStore.observeObject(palette)
let palette = CoreStore.fetchOne(From<Palette>(), OrderBy(.ascending(#keyPath(Palette.hue))))!
self.monitor = CoreStore.monitorObject(palette)
}
super.init(coder: aDecoder)
@@ -69,46 +74,41 @@ class ObjectObserverDemoViewController: UIViewController, ManagedObjectObserver
override func viewDidLoad() {
super.viewDidLoad()
self.objectController?.addObserver(self)
self.monitor?.addObserver(self)
if let palette = self.objectController?.object {
if let palette = self.monitor?.object {
self.reloadPaletteInfo(palette, changedKeys: nil)
}
}
// MARK: ManagedObjectObserver
// MARK: ObjectObserver
func managedObjectWillUpdate(objectController: ManagedObjectController<Palette>, object: Palette) {
// none
}
func managedObjectWasUpdated(objectController: ManagedObjectController<Palette>, object: Palette, changedPersistentKeys: Set<KeyPath>) {
func objectMonitor(_ monitor: ObjectMonitor<Palette>, didUpdateObject object: Palette, changedPersistentKeys: Set<KeyPath>) {
self.reloadPaletteInfo(object, changedKeys: changedPersistentKeys)
}
func managedObjectWasDeleted(objectController: ManagedObjectController<Palette>, object: Palette) {
func objectMonitor(_ monitor: ObjectMonitor<Palette>, didDeleteObject object: Palette) {
self.navigationItem.rightBarButtonItem?.enabled = false
self.navigationItem.rightBarButtonItem?.isEnabled = false
self.colorNameLabel?.alpha = 0.3
self.colorView?.alpha = 0.3
self.hsbLabel?.text = "Deleted"
self.hsbLabel?.textColor = UIColor.redColor()
self.hsbLabel?.textColor = UIColor.red
self.hueSlider?.enabled = false
self.saturationSlider?.enabled = false
self.brightnessSlider?.enabled = false
self.hueSlider?.isEnabled = false
self.saturationSlider?.isEnabled = false
self.brightnessSlider?.isEnabled = false
}
// MARK: Private
var objectController: ManagedObjectController<Palette>?
var monitor: ObjectMonitor<Palette>?
@IBOutlet weak var colorNameLabel: UILabel?
@IBOutlet weak var colorView: UIView?
@@ -118,55 +118,63 @@ class ObjectObserverDemoViewController: UIViewController, ManagedObjectObserver
@IBOutlet weak var saturationSlider: UISlider?
@IBOutlet weak var brightnessSlider: UISlider?
@IBAction dynamic func hueSliderValueDidChange(sender: AnyObject?) {
@IBAction dynamic func hueSliderValueDidChange(_ sender: AnyObject?) {
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?.objectController?.object) {
if let palette = transaction.edit(self?.monitor?.object) {
palette.hue = Int32(hue)
transaction.commit()
}
}
},
completion: { _ in }
)
}
@IBAction dynamic func saturationSliderValueDidChange(sender: AnyObject?) {
@IBAction dynamic func saturationSliderValueDidChange(_ sender: AnyObject?) {
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?.objectController?.object) {
if let palette = transaction.edit(self?.monitor?.object) {
palette.saturation = saturation
transaction.commit()
}
}
},
completion: { _ in }
)
}
@IBAction dynamic func brightnessSliderValueDidChange(sender: AnyObject?) {
@IBAction dynamic func brightnessSliderValueDidChange(_ sender: AnyObject?) {
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?.objectController?.object) {
if let palette = transaction.edit(self?.monitor?.object) {
palette.brightness = brightness
transaction.commit()
}
}
},
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?.objectController?.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
@@ -176,19 +184,15 @@ class ObjectObserverDemoViewController: UIViewController, ManagedObjectObserver
self.hsbLabel?.text = palette.colorText
let hue = palette.hue
let saturation = palette.saturation
let brightness = palette.brightness
if changedKeys == nil || changedKeys?.contains("hue") == true {
if changedKeys == nil || changedKeys?.contains(#keyPath(Palette.hue)) == true {
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
}
if changedKeys == nil || changedKeys?.contains("brightness") == true {
if changedKeys == nil || changedKeys?.contains(#keyPath(Palette.brightness)) == true {
self.brightnessSlider?.value = palette.brightness
}
@@ -3,7 +3,7 @@
// CoreStoreDemo
//
// Created by John Rommel Estropia on 2015/05/24.
// Copyright (c) 2015 John Rommel Estropia. All rights reserved.
// Copyright © 2015 John Rommel Estropia. All rights reserved.
//
import UIKit
@@ -15,16 +15,16 @@ class ObserversViewController: UIViewController {
// MARK: UIViewController
override func viewDidAppear(animated: Bool) {
override func viewDidAppear(_ animated: Bool) {
super.viewDidAppear(animated)
let alert = UIAlertController(
title: "Observers Demo",
message: "This demo shows how to observe changes to a list of objects. The top and bottom view controllers both observe a single shared \"ManagedObjectListController\" instance.\n\nTap on a row to see how to observe changes made to a single object using a \"ManagedObjectController\".",
preferredStyle: .Alert
message: "This demo shows how to observe changes to a list of objects. The top and bottom view controllers both observe a single shared \"ListMonitor\" instance.\n\nTap on a row to see how to observe changes made to a single object using a \"ObjectMonitor\".",
preferredStyle: .alert
)
alert.addAction(UIAlertAction(title: "OK", style: .Cancel, handler: nil))
self.presentViewController(alert, animated: true, completion: nil)
alert.addAction(UIAlertAction(title: "OK", style: .cancel, handler: nil))
self.present(alert, animated: true, completion: nil)
}
}
@@ -3,7 +3,7 @@
// CoreStoreDemo
//
// Created by John Rommel Estropia on 2015/05/05.
// Copyright (c) 2015 John Rommel Estropia. All rights reserved.
// Copyright © 2015 John Rommel Estropia. All rights reserved.
//
import Foundation
@@ -24,8 +24,8 @@ class Palette: NSManagedObject {
get {
let KVCKey = "colorName"
if let colorName = self.accessValueForKVCKey(KVCKey) as? String {
let KVCKey = #keyPath(Palette.colorName)
if let colorName = self.getValue(forKvcKey: KVCKey) as? String {
return colorName
}
@@ -49,7 +49,7 @@ class Palette: NSManagedObject {
}
set {
self.setValue(newValue, forKVCKey: "colorName")
self.setValue(newValue.cs_toImportableNativeType(), forKvcKey: #keyPath(Palette.colorName))
}
}
@@ -3,7 +3,7 @@
// CoreStoreDemo
//
// Created by John Rommel Estropia on 2015/05/05.
// Copyright (c) 2015 John Rommel Estropia. All rights reserved.
// Copyright © 2015 John Rommel Estropia. All rights reserved.
//
import UIKit
@@ -3,12 +3,11 @@
// CoreStoreDemo
//
// Created by John Rommel Estropia on 2015/06/05.
// Copyright (c) 2015 John Rommel Estropia. All rights reserved.
// Copyright © 2015 John Rommel Estropia. All rights reserved.
//
import UIKit
import CoreStore
import GCDKit
// MARK: - CustomLoggerViewController
@@ -30,60 +29,61 @@ class CustomLoggerViewController: UIViewController, CoreStoreLogger {
super.viewDidLoad()
self.dataStack.addSQLiteStoreAndWait("emptyStore.sqlite")
try! self.dataStack.addStorageAndWait(SQLiteStore(fileName: "emptyStore.sqlite"))
CoreStore.logger = self
}
override func viewDidAppear(animated: Bool) {
override func viewDidAppear(_ animated: Bool) {
super.viewDidAppear(animated)
let alert = UIAlertController(
title: "Logger Demo",
message: "This demo shows how to plug-in any logging framework to CoreStore.\n\nThe view controller implements CoreStoreLogger and appends all logs to the text view.",
preferredStyle: .Alert
preferredStyle: .alert
)
alert.addAction(UIAlertAction(title: "OK", style: .Cancel, handler: nil))
self.presentViewController(alert, animated: true, completion: nil)
alert.addAction(UIAlertAction(title: "OK", style: .cancel, handler: nil))
self.present(alert, animated: true, completion: nil)
}
// MARK: CoreStoreLogger
func log(#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
switch level {
case .Trace: levelString = "Trace"
case .Notice: levelString = "Notice"
case .Warning: levelString = "Warning"
case .Fatal: levelString = "Fatal"
case .trace: levelString = "Trace"
case .notice: levelString = "Notice"
case .warning: levelString = "Warning"
case .fatal: levelString = "Fatal"
}
self?.textView?.insertText("\(fileName.stringValue.lastPathComponent):\(lineNumber) \(functionName)\n ↪︎ [Log:\(levelString)] \(message)\n\n")
self?.textView?.insertText("\((String(describing: fileName) as NSString).lastPathComponent):\(lineNumber) \(functionName)\n ↪︎ [Log:\(levelString)] \(message)\n\n")
}
}
func handleError(#error: NSError, message: String, fileName: StaticString, lineNumber: Int, functionName: StaticString) {
func log(error: 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.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, message: String, fileName: StaticString, lineNumber: Int, functionName: StaticString) {
func assert(_ condition: @autoclosure () -> Bool, message: @autoclosure () -> String, fileName: StaticString, lineNumber: Int, functionName: StaticString) {
if condition() {
return
}
GCDQueue.Main.async { [weak self] in
let messageString = message()
DispatchQueue.main.async { [weak self] in
self?.textView?.insertText("\(fileName.stringValue.lastPathComponent):\(lineNumber) \(functionName)\n ↪︎ [Assert] \(message)\n\n")
self?.textView?.insertText("\((String(describing: fileName) as NSString).lastPathComponent):\(lineNumber) \(functionName)\n ↪︎ [Assert] \(messageString)\n\n")
}
}
@@ -93,24 +93,27 @@ class CustomLoggerViewController: UIViewController, CoreStoreLogger {
@IBOutlet dynamic weak var textView: UITextView?
@IBOutlet dynamic weak var segmentedControl: UISegmentedControl?
@IBAction dynamic func segmentedControlValueChanged(sender: AnyObject?) {
@IBAction dynamic func segmentedControlValueChanged(_ sender: AnyObject?) {
switch self.segmentedControl?.selectedSegmentIndex {
case .Some(0):
self.dataStack.beginAsynchronous { (transaction) -> Void in
case 0?:
let request = NSFetchRequest<NSFetchRequestResult>()
Where(true).applyToFetchRequest(request)
Where(false).applyToFetchRequest(request)
transaction.create(Into(UserAccount))
}
case 1?:
_ = try? dataStack.addStorageAndWait(
SQLiteStore(
fileName: "emptyStore.sqlite",
configuration: "invalidStore"
)
)
case .Some(1):
self.dataStack.addSQLiteStoreAndWait("emptyStore.sqlite", configuration: "invalidStore")
case 2?:
DispatchQueue.global(qos: .background).async {
case .Some(2):
self.dataStack.beginAsynchronous { (transaction) -> Void in
transaction.commit()
transaction.commit()
_ = self.dataStack.fetchOne(From<Palette>())
}
default:
@@ -0,0 +1,424 @@
//
// MigrationsDemoViewController.swift
// CoreStoreDemo
//
// Created by John Rommel Estropia on 2015/06/21.
// Copyright © 2015 John Rommel Estropia. All rights reserved.
//
import UIKit
import CoreStore
// MARK: - MigrationsDemoViewController
class MigrationsDemoViewController: UIViewController, ListObserver, UITableViewDataSource, UITableViewDelegate {
// MARK: UIViewController
override func viewDidLoad() {
super.viewDidLoad()
if let segmentedControl = self.segmentedControl {
for (index, model) in self.models.enumerated() {
segmentedControl.setTitle(
model.label,
forSegmentAt: index
)
}
}
self.set(dataStack: nil, model: nil, scrollToSelection: false)
}
override func viewDidAppear(_ animated: Bool) {
super.viewDidAppear(animated)
let alert = UIAlertController(
title: "Migrations Demo",
message: "This demo shows how to run progressive migrations and how to support multiple model versions in a single project.\n\nThe persistent store contains 10000 organisms, which gain/lose properties when the migration evolves/devolves them.\n\nYou can use the \"mutate\" button to change an organism's properties then migrate to a different model to see how its value gets affected.",
preferredStyle: .alert
)
alert.addAction(UIAlertAction(title: "OK", style: .cancel, handler: nil))
self.present(alert, animated: true, completion: nil)
let modelMetadata = withExtendedLifetime(DataStack(modelName: "MigrationDemo")) {
(dataStack: DataStack) -> ModelMetadata in
let models = self.models
let migrations = try! dataStack.requiredMigrationsForStorage(
SQLiteStore(fileName: "MigrationDemo.sqlite")
)
guard let storeVersion = migrations.first?.sourceVersion else {
return models.first!
}
for model in models {
if model.schemaHistory.currentModelVersion == storeVersion {
return model
}
}
return models.first!
}
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
private typealias ModelMetadata = (label: String, entityType: NSManagedObject.Type, schemaHistory: SchemaHistory)
private let models: [ModelMetadata] = [
(
label: "Model V1",
entityType: OrganismV1.self,
schemaHistory: SchemaHistory(
modelName: "MigrationDemo",
migrationChain: ["MigrationDemoV3", "MigrationDemoV2", "MigrationDemo"]
)
),
(
label: "Model V2",
entityType: OrganismV2.self,
schemaHistory: SchemaHistory(
modelName: "MigrationDemo",
migrationChain: [
"MigrationDemo": "MigrationDemoV2",
"MigrationDemoV3": "MigrationDemoV2"
]
)
),
(
label: "Model V3",
entityType: OrganismV3.self,
schemaHistory: SchemaHistory(
modelName: "MigrationDemo",
migrationChain: ["MigrationDemo", "MigrationDemoV2", "MigrationDemoV3"]
)
)
]
private var _listMonitor: ListMonitor<NSManagedObject>?
private var listMonitor: ListMonitor<NSManagedObject>? {
return self._listMonitor
}
private var _dataStack: DataStack?
private var dataStack: DataStack? {
return self._dataStack
}
private var _lastSelectedIndexPath: IndexPath?
private var lastSelectedIndexPath: IndexPath? {
return self._lastSelectedIndexPath
}
private func setSelectedIndexPath(_ indexPath: IndexPath, scrollToSelection: Bool) {
self._lastSelectedIndexPath = indexPath
self.updateDisplay(reloadData: false, scrollToSelection: scrollToSelection, animated: true)
}
@IBOutlet private dynamic weak var headerContainer: UIView?
@IBOutlet private dynamic weak var titleLabel: UILabel?
@IBOutlet private dynamic weak var organismLabel: UILabel?
@IBOutlet private dynamic weak var segmentedControl: UISegmentedControl?
@IBOutlet private dynamic weak var progressView: UIProgressView?
@IBOutlet private dynamic weak var tableView: UITableView?
@IBAction private dynamic func segmentedControlValueChanged(_ sender: AnyObject?) {
guard let index = self.segmentedControl?.selectedSegmentIndex else {
return
}
self.selectModelVersion(self.models[index])
}
private func selectModelVersion(_ model: ModelMetadata) {
if self.dataStack?.modelVersion == model.schemaHistory.currentModelVersion {
return
}
self.set(dataStack: nil, model: nil, scrollToSelection: false) // explicitly trigger NSPersistentStore cleanup by deallocating the stack
let dataStack = DataStack(schemaHistory: model.schemaHistory)
self.setEnabled(false)
let progress = dataStack.addStorage(
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
guard let `self` = self else {
return
}
guard case .success = result else {
self.setEnabled(true)
return
}
self.set(dataStack: dataStack, model: model, scrollToSelection: true)
let count = dataStack.queryValue(
From(model.entityType),
Select<Int>(.count(#keyPath(OrganismV1.dna))))!
if count > 0 {
self.setEnabled(true)
}
else {
for i: Int64 in 0 ..< 20 {
dataStack.perform(
asynchronous: { (transaction) in
for j: Int64 in 0 ..< 500 {
let organism = transaction.create(Into(model.entityType)) as! OrganismProtocol
organism.dna = (i * 500) + j + 1
organism.mutate()
}
},
completion: { _ in }
)
}
dataStack.perform(
asynchronous: { _ in },
completion: { [weak self] _ in
self?.setEnabled(true)
}
)
}
}
)
if let progress = progress {
progress.setProgressHandler { [weak self] (progress) -> Void in
self?.reloadTableHeaderWithProgress(progress)
}
}
}
private func setEnabled(_ enabled: Bool) {
UIView.animate(
withDuration: 0.2,
delay: 0,
options: .beginFromCurrentState,
animations: { () -> Void in
let navigationItem = self.navigationItem
navigationItem.leftBarButtonItem?.isEnabled = enabled
navigationItem.rightBarButtonItem?.isEnabled = enabled
navigationItem.hidesBackButton = !enabled
self.segmentedControl?.isEnabled = enabled
if let tableView = self.tableView {
tableView.alpha = enabled ? 1.0 : 0.5
tableView.isUserInteractionEnabled = enabled
}
},
completion: nil
)
}
private func set(dataStack: DataStack?, model: ModelMetadata?, scrollToSelection: Bool) {
if let dataStack = dataStack, let model = model {
self.segmentedControl?.selectedSegmentIndex = self.models
.index(
where: { (_, _, schemaHistory) -> Bool in
schemaHistory.currentModelVersion == model.schemaHistory.currentModelVersion
}
)!
self._dataStack = dataStack
let listMonitor = dataStack.monitorList(From(model.entityType), OrderBy(.descending("dna")))
listMonitor.addObserver(self)
self._listMonitor = listMonitor
if self.lastSelectedIndexPath == nil {
if listMonitor.numberOfObjectsInSection(0) > 0 {
self.setSelectedIndexPath(IndexPath(row: 0, section: 0), scrollToSelection: true)
}
}
}
else {
self.segmentedControl?.selectedSegmentIndex = UISegmentedControlNoSegment
self._listMonitor = nil
self._dataStack = nil
}
self.updateDisplay(reloadData: true, scrollToSelection: scrollToSelection, animated: false)
}
private func reloadTableHeaderWithProgress(_ progress: Progress) {
self.progressView?.setProgress(Float(progress.fractionCompleted), animated: true)
self.titleLabel?.text = "Migrating: \(progress.localizedDescription ?? "")"
self.organismLabel?.text = "Progressive step \(progress.localizedAdditionalDescription ?? "")"
}
private func updateDisplay(reloadData: Bool, scrollToSelection: Bool, animated: Bool) {
var lines = [String]()
var organismType = ""
if let indexPath = self.lastSelectedIndexPath, let organism = self.listMonitor?[indexPath] {
for property in organism.entity.properties {
let value = organism.value(forKey: property.name) ?? NSNull()
lines.append("\(property.name): \(value)")
}
organismType = organism.entity.managedObjectClassName
}
self.titleLabel?.text = organismType
self.organismLabel?.text = lines.joined(separator: "\n")
self.progressView?.progress = 0
self.headerContainer?.setNeedsLayout()
guard let tableView = self.tableView else {
return
}
if reloadData {
tableView.reloadData()
}
tableView.layoutIfNeeded()
if let indexPath = self.lastSelectedIndexPath,
indexPath.row < tableView.numberOfRows(inSection: 0) {
tableView.selectRow(at: indexPath,
animated: scrollToSelection && animated,
scrollPosition: scrollToSelection ? .middle : .none
)
}
}
}
@@ -0,0 +1,5 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict/>
</plist>
@@ -0,0 +1,4 @@
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<model userDefinedModelVersionIdentifier="" type="com.apple.IDECoreDataModeler.DataModel" documentVersion="1.0" lastSavedToolsVersion="8166.2" systemVersion="14E46" minimumToolsVersion="Xcode 7.0">
<elements/>
</model>
@@ -0,0 +1,16 @@
//
// OrganismProtocol.swift
// CoreStoreDemo
//
// Created by John Rommel Estropia on 2015/06/27.
// Copyright © 2015 John Rommel Estropia. All rights reserved.
//
import Foundation
protocol OrganismProtocol: class {
var dna: Int64 { get set }
func mutate()
}
@@ -0,0 +1,22 @@
//
// OrganismTableViewCell.swift
// CoreStoreDemo
//
// Created by John Rommel Estropia on 2015/07/12.
// Copyright © 2015 John Rommel Estropia. All rights reserved.
//
import UIKit
class OrganismTableViewCell: UITableViewCell {
@IBOutlet weak dynamic var dnaLabel: UILabel?
@IBOutlet weak dynamic var mutateButton: UIButton?
var mutateButtonHandler: (() -> Void)?
@IBAction dynamic func mutateButtonTouchUpInside(_ sender: UIButton?) {
self.mutateButtonHandler?()
}
}
@@ -0,0 +1,25 @@
//
// OrganismV1.swift
// CoreStoreDemo
//
// Created by John Rommel Estropia on 2015/06/21.
// Copyright © 2015 John Rommel Estropia. All rights reserved.
//
import Foundation
import CoreData
class OrganismV1: NSManagedObject, OrganismProtocol {
@NSManaged var dna: Int64
@NSManaged var hasHead: Bool
@NSManaged var hasTail: Bool
// MARK: OrganismProtocol
func mutate() {
self.hasHead = arc4random_uniform(2) == 1
self.hasTail = arc4random_uniform(2) == 1
}
}
@@ -0,0 +1,27 @@
//
// OrganismV2.swift
// CoreStoreDemo
//
// Created by John Rommel Estropia on 2015/06/21.
// Copyright © 2015 John Rommel Estropia. All rights reserved.
//
import Foundation
import CoreData
class OrganismV2: NSManagedObject, OrganismProtocol {
@NSManaged var dna: Int64
@NSManaged var hasHead: Bool
@NSManaged var hasTail: Bool
@NSManaged var numberOfFlippers: Int32
// MARK: OrganismProtocol
func mutate() {
self.hasHead = arc4random_uniform(2) == 1
self.hasTail = arc4random_uniform(2) == 1
self.numberOfFlippers = Int32(arc4random_uniform(9) / 2 * 2)
}
}
File diff suppressed because one or more lines are too long
@@ -0,0 +1,29 @@
//
// OrganismV2ToV3MigrationPolicy.swift
// CoreStoreDemo
//
// Created by John Rommel Estropia on 2015/06/27.
// Copyright © 2015 John Rommel Estropia. All rights reserved.
//
import CoreData
class OrganismV2ToV3MigrationPolicy: NSEntityMigrationPolicy {
override func createDestinationInstances(forSource sInstance: NSManagedObject, in mapping: NSEntityMapping, manager: NSMigrationManager) throws {
try super.createDestinationInstances(forSource: sInstance, in: mapping, manager: manager)
for dInstance in manager.destinationInstances(forEntityMappingName: mapping.name, sourceInstances: [sInstance]) {
dInstance.setValue(
false,
forKey: #keyPath(OrganismV3.hasVertebrae)
)
dInstance.setValue(
sInstance.value(forKey: #keyPath(OrganismV2.numberOfFlippers)),
forKey: #keyPath(OrganismV3.numberOfLimbs)
)
}
}
}
@@ -0,0 +1,29 @@
//
// OrganismV3.swift
// CoreStoreDemo
//
// Created by John Rommel Estropia on 2015/06/27.
// Copyright © 2015 John Rommel Estropia. All rights reserved.
//
import Foundation
import CoreData
class OrganismV3: NSManagedObject, OrganismProtocol {
@NSManaged var dna: Int64
@NSManaged var hasHead: Bool
@NSManaged var hasTail: Bool
@NSManaged var numberOfLimbs: Int32
@NSManaged var hasVertebrae: Bool
// MARK: OrganismProtocol
func mutate() {
self.hasHead = arc4random_uniform(2) == 1
self.hasTail = arc4random_uniform(2) == 1
self.numberOfLimbs = Int32(arc4random_uniform(9) / 2 * 2)
self.hasVertebrae = arc4random_uniform(2) == 1
}
}
File diff suppressed because one or more lines are too long
@@ -3,6 +3,6 @@
<plist version="1.0">
<dict>
<key>_XCCurrentVersionName</key>
<string>MigrationDemoV2.xcdatamodel</string>
<string>MigrationDemoV3.xcdatamodel</string>
</dict>
</plist>
@@ -1,7 +1,11 @@
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<model userDefinedModelVersionIdentifier="" type="com.apple.IDECoreDataModeler.DataModel" documentVersion="1.0" lastSavedToolsVersion="7701" systemVersion="14D136" minimumToolsVersion="Xcode 4.3" macOSVersion="Automatic" iOSVersion="Automatic">
<entity name="Organism" syncable="YES"/>
<model 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">
<attribute name="dna" optional="YES" attributeType="Integer 64" usesScalarValueType="NO" syncable="YES"/>
<attribute name="hasHead" optional="YES" attributeType="Boolean" usesScalarValueType="NO" syncable="YES"/>
<attribute name="hasTail" optional="YES" attributeType="Boolean" usesScalarValueType="NO" syncable="YES"/>
</entity>
<elements>
<element name="Organism" positionX="-36" positionY="9" width="128" height="45"/>
<element name="Organism" positionX="-36" positionY="9" width="128" height="90"/>
</elements>
</model>
@@ -1,7 +1,12 @@
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<model userDefinedModelVersionIdentifier="" type="com.apple.IDECoreDataModeler.DataModel" documentVersion="1.0" lastSavedToolsVersion="7701" systemVersion="14D136" minimumToolsVersion="Xcode 4.3" macOSVersion="Automatic" iOSVersion="Automatic">
<entity name="Organism" syncable="YES"/>
<model 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">
<attribute name="dna" optional="YES" attributeType="Integer 64" usesScalarValueType="NO" syncable="YES"/>
<attribute name="hasHead" attributeType="Boolean" usesScalarValueType="NO" syncable="YES"/>
<attribute name="hasTail" attributeType="Boolean" usesScalarValueType="NO" syncable="YES"/>
<attribute name="numberOfFlippers" attributeType="Integer 32" defaultValueString="0" usesScalarValueType="NO" syncable="YES"/>
</entity>
<elements>
<element name="Organism" positionX="-36" positionY="9" width="128" height="45"/>
<element name="Organism" positionX="-36" positionY="9" width="128" height="105"/>
</elements>
</model>
@@ -0,0 +1,13 @@
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<model 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">
<attribute name="dna" optional="YES" attributeType="Integer 64" usesScalarValueType="NO" syncable="YES"/>
<attribute name="hasHead" attributeType="Boolean" usesScalarValueType="NO" syncable="YES"/>
<attribute name="hasTail" attributeType="Boolean" usesScalarValueType="NO" syncable="YES"/>
<attribute name="hasVertebrae" attributeType="Boolean" usesScalarValueType="NO" syncable="YES"/>
<attribute name="numberOfLimbs" attributeType="Integer 32" defaultValueString="0" usesScalarValueType="NO" elementID="numberOfFlippers" syncable="YES"/>
</entity>
<elements>
<element name="Organism" positionX="-36" positionY="9" width="128" height="120"/>
</elements>
</model>
@@ -3,7 +3,7 @@
// CoreStoreDemo
//
// Created by John Rommel Estropia on 2015/06/06.
// Copyright (c) 2015 John Rommel Estropia. All rights reserved.
// Copyright © 2015 John Rommel Estropia. All rights reserved.
//
import Foundation
@@ -3,7 +3,7 @@
// CoreStoreDemo
//
// Created by John Rommel Estropia on 2015/06/06.
// Copyright (c) 2015 John Rommel Estropia. All rights reserved.
// Copyright © 2015 John Rommel Estropia. All rights reserved.
//
import Foundation
@@ -3,7 +3,7 @@
// CoreStoreDemo
//
// Created by John Rommel Estropia on 2015/05/24.
// Copyright (c) 2015 John Rommel Estropia. All rights reserved.
// Copyright © 2015 John Rommel Estropia. All rights reserved.
//
import UIKit
@@ -18,20 +18,25 @@ private struct Static {
static let facebookStack: DataStack = {
let dataStack = DataStack(modelName: "StackSetupDemo")
dataStack.addSQLiteStoreAndWait(
"AccountsDemo_FB_Male.sqlite",
try! dataStack.addStorageAndWait(
SQLiteStore(
fileName: "AccountsDemo_FB_Male.sqlite",
configuration: maleConfiguration,
resetStoreOnMigrationFailure: true
localStorageOptions: .recreateStoreOnModelMismatch
)
dataStack.addSQLiteStoreAndWait(
"AccountsDemo_FB_Female.sqlite",
)
try! dataStack.addStorageAndWait(
SQLiteStore(
fileName: "AccountsDemo_FB_Female.sqlite",
configuration: femaleConfiguration,
resetStoreOnMigrationFailure: true
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"
@@ -42,9 +47,8 @@ private struct Static {
account2.accountType = "Facebook"
account2.name = "Jane Doe HCD"
account2.friends = 314
transaction.commit()
}
)
return dataStack
}()
@@ -52,20 +56,25 @@ private struct Static {
static let twitterStack: DataStack = {
let dataStack = DataStack(modelName: "StackSetupDemo")
dataStack.addSQLiteStoreAndWait(
"AccountsDemo_TW_Male.sqlite",
try! dataStack.addStorageAndWait(
SQLiteStore(
fileName: "AccountsDemo_TW_Male.sqlite",
configuration: maleConfiguration,
resetStoreOnMigrationFailure: true
localStorageOptions: .recreateStoreOnModelMismatch
)
dataStack.addSQLiteStoreAndWait(
"AccountsDemo_TW_Female.sqlite",
)
try! dataStack.addStorageAndWait(
SQLiteStore(
fileName: "AccountsDemo_TW_Female.sqlite",
configuration: femaleConfiguration,
resetStoreOnMigrationFailure: true
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"
@@ -76,10 +85,8 @@ private struct Static {
account2.accountType = "Twitter"
account2.name = "#janedoe_hcd"
account2.friends = 100
transaction.commit()
}
)
return dataStack
}()
}
@@ -92,53 +99,53 @@ private struct Static {
class StackSetupDemoViewController: UITableViewController {
let accounts = [
Static.facebookStack.fetchAll(From(UserAccount)) ?? [],
Static.twitterStack.fetchAll(From(UserAccount)) ?? []
Static.facebookStack.fetchAll(From(UserAccount.self)) ?? [],
Static.twitterStack.fetchAll(From(UserAccount.self)) ?? []
]
// MARK: UIViewController
override func viewWillAppear(animated: Bool) {
override func viewWillAppear(_ animated: Bool) {
super.viewWillAppear(animated)
self.tableView.reloadData()
let indexPath = NSIndexPath(forRow: 0, inSection: 0)
self.tableView.selectRowAtIndexPath(indexPath, animated: false, scrollPosition: .None)
self.updateDetailsWithAccount(self.accounts[indexPath.section][indexPath.row])
let indexPath = IndexPath(row: 0, section: 0)
self.tableView.selectRow(at: indexPath, animated: false, scrollPosition: .none)
self.updateDetails(account: self.accounts[indexPath.section][indexPath.row])
}
override func viewDidAppear(animated: Bool) {
override func viewDidAppear(_ animated: Bool) {
super.viewDidAppear(animated)
let alert = UIAlertController(
title: "Setup Demo",
message: "This demo shows how to initialize 2 DataStacks with 2 configurations each, for a total of 4 SQLite files, each with 1 instance of a \"UserAccount\" entity.",
preferredStyle: .Alert
preferredStyle: .alert
)
alert.addAction(UIAlertAction(title: "OK", style: .Cancel, handler: nil))
self.presentViewController(alert, animated: true, completion: nil)
alert.addAction(UIAlertAction(title: "OK", style: .cancel, handler: nil))
self.present(alert, animated: true, completion: nil)
}
// MARK: UITableViewDataSource
override func numberOfSectionsInTableView(tableView: UITableView) -> Int {
override func numberOfSections(in tableView: UITableView) -> Int {
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
}
override func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCellWithIdentifier("UITableViewCell") as! UITableViewCell
let cell = tableView.dequeueReusableCell(withIdentifier: "UITableViewCell")!
let account = self.accounts[indexPath.section][indexPath.row]
cell.textLabel?.text = account.name
@@ -150,13 +157,13 @@ class StackSetupDemoViewController: UITableViewController {
// 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]
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 {
@@ -176,11 +183,11 @@ class StackSetupDemoViewController: UITableViewController {
// MARK: Private
@IBOutlet weak var accountTypeLabel: UILabel?
@IBOutlet weak var nameLabel: UILabel?
@IBOutlet weak var friendsLabel: UILabel?
@IBOutlet private dynamic weak var accountTypeLabel: UILabel?
@IBOutlet private dynamic weak var nameLabel: UILabel?
@IBOutlet private dynamic weak var friendsLabel: UILabel?
func updateDetailsWithAccount(account: UserAccount) {
private func updateDetails(account: UserAccount) {
self.accountTypeLabel?.text = account.accountType
self.nameLabel?.text = account.name
@@ -3,7 +3,7 @@
// CoreStoreDemo
//
// Created by John Rommel Estropia on 2015/05/24.
// Copyright (c) 2015 John Rommel Estropia. All rights reserved.
// Copyright © 2015 John Rommel Estropia. All rights reserved.
//
import Foundation
@@ -3,7 +3,7 @@
// CoreStoreDemo
//
// Created by John Rommel Estropia on 2015/05/24.
// Copyright (c) 2015 John Rommel Estropia. All rights reserved.
// Copyright © 2015 John Rommel Estropia. All rights reserved.
//
import Foundation
@@ -3,7 +3,7 @@
// CoreStoreDemo
//
// Created by John Rommel Estropia on 2015/05/24.
// Copyright (c) 2015 John Rommel Estropia. All rights reserved.
// Copyright © 2015 John Rommel Estropia. All rights reserved.
//
import UIKit
@@ -11,40 +11,41 @@ import CoreLocation
import MapKit
import AddressBookUI
import CoreStore
import GCDKit
private struct Static {
static let placeController: ManagedObjectController<Place> = {
static let placeController: ObjectMonitor<Place> = {
CoreStore.addSQLiteStoreAndWait(
"PlaceDemo.sqlite",
try! CoreStore.addStorageAndWait(
SQLiteStore(
fileName: "PlaceDemo.sqlite",
configuration: "TransactionsDemo",
resetStoreOnMigrationFailure: true
localStorageOptions: .recreateStoreOnModelMismatch
)
)
var place = CoreStore.fetchOne(From(Place))
var place = CoreStore.fetchOne(From<Place>())
if place == nil {
CoreStore.beginSynchronous { (transaction) -> Void in
_ = try? CoreStore.perform(
synchronous: { (transaction) in
let place = transaction.create(Into(Place))
let place = transaction.create(Into<Place>())
place.setInitialValues()
transaction.commit()
}
place = CoreStore.fetchOne(From(Place))
)
place = CoreStore.fetchOne(From<Place>())
}
return CoreStore.observeObject(place!)
return CoreStore.monitorObject(place!)
}()
}
// MARK: - TransactionsDemoViewController
class TransactionsDemoViewController: UIViewController, MKMapViewDelegate, ManagedObjectObserver {
class TransactionsDemoViewController: UIViewController, MKMapViewDelegate, ObjectObserver {
// MARK: NSObject
@@ -60,39 +61,42 @@ class TransactionsDemoViewController: UIViewController, MKMapViewDelegate, Manag
super.viewDidLoad()
let longPressGesture = UILongPressGestureRecognizer(target: self, action: "longPressGestureRecognized:")
let longPressGesture = UILongPressGestureRecognizer(
target: self,
action: #selector(self.longPressGestureRecognized(_:))
)
self.mapView?.addGestureRecognizer(longPressGesture)
Static.placeController.addObserver(self)
self.navigationItem.rightBarButtonItem = UIBarButtonItem(
barButtonSystemItem: .Refresh,
barButtonSystemItem: .refresh,
target: self,
action: "refreshButtonTapped:"
action: #selector(self.refreshButtonTapped(_:))
)
}
override func viewDidAppear(animated: Bool) {
override func viewDidAppear(_ animated: Bool) {
super.viewDidAppear(animated)
let alert = UIAlertController(
title: "Transactions Demo",
message: "This demo shows how to use the 3 types of transactions to save updates: synchronous, asynchronous, and detached.\n\nTap and hold on the map to change the pin location.",
preferredStyle: .Alert
message: "This demo shows how to use the 3 types of transactions to save updates: synchronous, asynchronous, and unsafe.\n\nTap and hold on the map to change the pin location.",
preferredStyle: .alert
)
alert.addAction(UIAlertAction(title: "OK", style: .Cancel, handler: nil))
self.presentViewController(alert, animated: true, completion: nil)
alert.addAction(UIAlertAction(title: "OK", style: .cancel, handler: nil))
self.present(alert, animated: true, completion: nil)
}
override func viewWillAppear(animated: Bool) {
override func viewWillAppear(_ animated: Bool) {
super.viewWillAppear(animated)
if let mapView = self.mapView, let place = Static.placeController.object {
mapView.addAnnotation(place)
mapView.setCenterCoordinate(place.coordinate, animated: false)
mapView.setCenter(place.coordinate, animated: false)
mapView.selectAnnotation(place, animated: false)
}
}
@@ -100,14 +104,14 @@ class TransactionsDemoViewController: UIViewController, MKMapViewDelegate, Manag
// MARK: MKMapViewDelegate
func mapView(mapView: MKMapView!, viewForAnnotation annotation: MKAnnotation!) -> MKAnnotationView! {
func mapView(_ mapView: MKMapView, viewFor annotation: MKAnnotation) -> MKAnnotationView? {
let identifier = "MKAnnotationView"
var annotationView: MKPinAnnotationView! = mapView.dequeueReusableAnnotationViewWithIdentifier(identifier) as? MKPinAnnotationView
var annotationView: MKPinAnnotationView! = mapView.dequeueReusableAnnotationView(withIdentifier: identifier) as? MKPinAnnotationView
if annotationView == nil {
annotationView = MKPinAnnotationView(annotation: annotation, reuseIdentifier: identifier)
annotationView.enabled = true
annotationView.isEnabled = true
annotationView.canShowCallout = true
annotationView.animatesDrop = true
}
@@ -120,30 +124,30 @@ class TransactionsDemoViewController: UIViewController, MKMapViewDelegate, Manag
}
// MARK: ManagedObjectObserver
// MARK: ObjectObserver
func managedObjectWillUpdate(objectController: ManagedObjectController<Place>, object: Place) {
func objectMonitor(_ monitor: ObjectMonitor<Place>, willUpdateObject object: Place) {
// none
}
func managedObjectWasUpdated(objectController: ManagedObjectController<Place>, object: Place, changedPersistentKeys: Set<KeyPath>) {
func objectMonitor(_ monitor: ObjectMonitor<Place>, didUpdateObject object: Place, changedPersistentKeys: Set<KeyPath>) {
if let mapView = self.mapView {
mapView.removeAnnotations(mapView.annotations ?? [])
mapView.removeAnnotations(mapView.annotations)
mapView.addAnnotation(object)
mapView.setCenterCoordinate(object.coordinate, animated: true)
mapView.setCenter(object.coordinate, 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 managedObjectWasDeleted(objectController: ManagedObjectController<Place>, object: Place) {
func objectMonitor(_ monitor: ObjectMonitor<Place>, didDeleteObject object: Place) {
// none
}
@@ -155,49 +159,55 @@ class TransactionsDemoViewController: UIViewController, MKMapViewDelegate, Manag
@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 {
CoreStore.beginAsynchronous { (transaction) -> Void in
let coordinate = mapView.convert(
gesture.location(in: mapView),
toCoordinateFrom: mapView
)
CoreStore.perform(
asynchronous: { (transaction) in
let place = transaction.edit(Static.placeController.object)
place?.coordinate = mapView.convertPoint(
gesture.locationInView(mapView),
toCoordinateFromView: mapView
place?.coordinate = coordinate
},
completion: { _ in }
)
transaction.commit { (_) -> Void in }
}
}
}
@IBAction dynamic func refreshButtonTapped(sender: AnyObject?) {
@IBAction dynamic func refreshButtonTapped(_ sender: AnyObject?) {
CoreStore.beginSynchronous { (transaction) -> Void in
_ = try? CoreStore.perform(
synchronous: { (transaction) in
let place = transaction.edit(Static.placeController.object)
place?.setInitialValues()
transaction.commit()
}
)
}
func geocodePlace(place: Place) {
func geocode(place: Place) {
let transaction = CoreStore.beginDetached()
let transaction = CoreStore.beginUnsafe()
self.geocoder?.cancelGeocode()
var geocoder = CLGeocoder()
let geocoder = CLGeocoder()
self.geocoder = geocoder
geocoder.reverseGeocodeLocation(
CLLocation(latitude: place.latitude, longitude: place.longitude),
completionHandler: { [weak self] (placemarks, error) -> Void in
if let strongSelf = self, let placemark = (placemarks as? [CLPlacemark])?.first {
if let placemark = placemarks?.first, let addressDictionary = placemark.addressDictionary {
let place = transaction.edit(Static.placeController.object)
place?.title = placemark.name
place?.subtitle = ABCreateStringWithAddressDictionary(placemark.addressDictionary, true)
place?.subtitle = ABCreateStringWithAddressDictionary(addressDictionary, true)
transaction.commit { (_) -> Void in }
}

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