From bc0757cf06b8a839b97a691ec816535712d6d098 Mon Sep 17 00:00:00 2001 From: John Estropia Date: Wed, 18 Nov 2015 19:46:17 +0900 Subject: [PATCH 1/8] README: Added link to poll for new features --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index fc1ebf7..263fa4c 100644 --- a/README.md +++ b/README.md @@ -24,7 +24,7 @@ Unleashing the real power of Core Data with the elegance and safety of Swift - Documentation! No magic here; all public classes, functions, properties, etc. have detailed Apple Docs. This README also introduces a lot of concepts and explains a lot of CoreStore's behavior. - **New in 1.3.0:** Efficient importing utilities! -**CoreStore's goal is not to expose shorter, magical syntax, but to provide an API that focuses on readability, consistency, and safety.** +**[Or vote for the next feature!](http://goo.gl/RIiHMP)** From eef5a3d80bbd02a23139320555399345fb6d83ee Mon Sep 17 00:00:00 2001 From: John Estropia Date: Tue, 24 Nov 2015 11:33:52 +0900 Subject: [PATCH 2/8] allow CoreStore installation both through frameworks or through direct linking --- CoreStore.podspec | 2 ++ CoreStore.xcodeproj/project.pbxproj | 4 +++- CoreStore/Convenience Helpers/NSProgress+Convenience.swift | 4 +++- CoreStore/CoreStore.swift | 4 +++- CoreStore/Fetching and Querying/DataStack+Querying.swift | 4 +++- CoreStore/Internal/NSManagedObjectContext+CoreStore.swift | 4 +++- CoreStore/Internal/NSManagedObjectContext+Transaction.swift | 4 +++- CoreStore/Migrating/CoreStore+Migration.swift | 4 +++- CoreStore/Migrating/DataStack+Migration.swift | 4 +++- CoreStore/Observing/DataStack+Observing.swift | 4 +++- CoreStore/Observing/ListMonitor.swift | 4 +++- CoreStore/Observing/ObjectMonitor.swift | 4 +++- .../Saving and Processing/AsynchronousDataTransaction.swift | 4 +++- CoreStore/Saving and Processing/BaseDataTransaction.swift | 4 +++- CoreStore/Saving and Processing/DataStack+Transaction.swift | 4 +++- .../Saving and Processing/SynchronousDataTransaction.swift | 4 +++- CoreStore/Saving and Processing/UnsafeDataTransaction.swift | 4 +++- CoreStore/Setting Up/CoreStore+Setup.swift | 4 +++- CoreStore/Setting Up/DataStack.swift | 4 +++- .../Loggers Demo/CustomLoggerViewController.swift | 4 +++- .../Transactions Demo/TransactionsDemoViewController.swift | 4 +++- 21 files changed, 62 insertions(+), 20 deletions(-) diff --git a/CoreStore.podspec b/CoreStore.podspec index e2d0391..fba19e6 100644 --- a/CoreStore.podspec +++ b/CoreStore.podspec @@ -15,5 +15,7 @@ Pod::Spec.new do |s| s.osx.exclude_files = "CoreStore/Observing/*.{swift}", "CoreStore/Internal/FetchedResultsControllerDelegate.swift" s.frameworks = "Foundation", "CoreData" s.requires_arc = true + s.pod_target_xcconfig = { 'OTHER_SWIFT_FLAGS' => '-D USE_FRAMEWORKS' } + s.dependency "GCDKit", "1.1.3" end \ No newline at end of file diff --git a/CoreStore.xcodeproj/project.pbxproj b/CoreStore.xcodeproj/project.pbxproj index 7b5aff8..4ad23a3 100644 --- a/CoreStore.xcodeproj/project.pbxproj +++ b/CoreStore.xcodeproj/project.pbxproj @@ -295,7 +295,7 @@ B5D39A0119FD00C9000E91BB /* Foundation.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Foundation.framework; path = System/Library/Frameworks/Foundation.framework; sourceTree = SDKROOT; }; B5D5E0CE1A4D6AAB006468AF /* TestEntity2.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = TestEntity2.swift; sourceTree = ""; }; B5D806C51A34715700A44484 /* GCDKit.xcodeproj */ = {isa = PBXFileReference; lastKnownFileType = "wrapper.pb-project"; path = GCDKit.xcodeproj; sourceTree = ""; }; - B5D9C8F61B160ED200E64F0E /* CoreStore.podspec */ = {isa = PBXFileReference; lastKnownFileType = text; path = CoreStore.podspec; sourceTree = SOURCE_ROOT; }; + B5D9C8F61B160ED200E64F0E /* CoreStore.podspec */ = {isa = PBXFileReference; explicitFileType = text.script.ruby; path = CoreStore.podspec; sourceTree = SOURCE_ROOT; }; B5E834B81B76311F001D3D50 /* BaseDataTransaction+Importing.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "BaseDataTransaction+Importing.swift"; sourceTree = ""; }; B5E834BA1B7691F3001D3D50 /* Functions.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Functions.swift; sourceTree = ""; }; B5E84ED81AFF82360064E85B /* README.md */ = {isa = PBXFileReference; lastKnownFileType = net.daringfireball.markdown; path = README.md; sourceTree = SOURCE_ROOT; }; @@ -1169,6 +1169,7 @@ IPHONEOS_DEPLOYMENT_TARGET = 8.1; MTL_ENABLE_DEBUG_INFO = YES; ONLY_ACTIVE_ARCH = YES; + OTHER_SWIFT_FLAGS = "-D USE_FRAMEWORKS"; SDKROOT = iphoneos; SWIFT_OPTIMIZATION_LEVEL = "-Onone"; TARGETED_DEVICE_FAMILY = "1,2"; @@ -1208,6 +1209,7 @@ GCC_WARN_UNUSED_VARIABLE = YES; IPHONEOS_DEPLOYMENT_TARGET = 8.1; MTL_ENABLE_DEBUG_INFO = NO; + OTHER_SWIFT_FLAGS = "-D USE_FRAMEWORKS"; SDKROOT = iphoneos; SWIFT_OPTIMIZATION_LEVEL = "-O"; TARGETED_DEVICE_FAMILY = "1,2"; diff --git a/CoreStore/Convenience Helpers/NSProgress+Convenience.swift b/CoreStore/Convenience Helpers/NSProgress+Convenience.swift index 0d811b3..b2fd744 100644 --- a/CoreStore/Convenience Helpers/NSProgress+Convenience.swift +++ b/CoreStore/Convenience Helpers/NSProgress+Convenience.swift @@ -24,7 +24,9 @@ // import Foundation -import GCDKit +#if USE_FRAMEWORKS + import GCDKit +#endif // MARK: - NSProgress diff --git a/CoreStore/CoreStore.swift b/CoreStore/CoreStore.swift index 532c54e..37e0e58 100644 --- a/CoreStore/CoreStore.swift +++ b/CoreStore/CoreStore.swift @@ -24,7 +24,9 @@ // import CoreData -import GCDKit +#if USE_FRAMEWORKS + import GCDKit +#endif // MARK: - CoreStore diff --git a/CoreStore/Fetching and Querying/DataStack+Querying.swift b/CoreStore/Fetching and Querying/DataStack+Querying.swift index 5408b98..9161a25 100644 --- a/CoreStore/Fetching and Querying/DataStack+Querying.swift +++ b/CoreStore/Fetching and Querying/DataStack+Querying.swift @@ -25,7 +25,9 @@ import Foundation import CoreData -import GCDKit +#if USE_FRAMEWORKS + import GCDKit +#endif // MARK: - DataStack diff --git a/CoreStore/Internal/NSManagedObjectContext+CoreStore.swift b/CoreStore/Internal/NSManagedObjectContext+CoreStore.swift index 30ee6a6..f9b1f17 100644 --- a/CoreStore/Internal/NSManagedObjectContext+CoreStore.swift +++ b/CoreStore/Internal/NSManagedObjectContext+CoreStore.swift @@ -25,7 +25,9 @@ import Foundation import CoreData -import GCDKit +#if USE_FRAMEWORKS + import GCDKit +#endif // MARK: - NSManagedObjectContext diff --git a/CoreStore/Internal/NSManagedObjectContext+Transaction.swift b/CoreStore/Internal/NSManagedObjectContext+Transaction.swift index 17b5676..cd0f03a 100644 --- a/CoreStore/Internal/NSManagedObjectContext+Transaction.swift +++ b/CoreStore/Internal/NSManagedObjectContext+Transaction.swift @@ -25,7 +25,9 @@ import Foundation import CoreData -import GCDKit +#if USE_FRAMEWORKS + import GCDKit +#endif // MARK: - NSManagedObjectContext diff --git a/CoreStore/Migrating/CoreStore+Migration.swift b/CoreStore/Migrating/CoreStore+Migration.swift index bd909b2..6f4d0dc 100644 --- a/CoreStore/Migrating/CoreStore+Migration.swift +++ b/CoreStore/Migrating/CoreStore+Migration.swift @@ -25,7 +25,9 @@ import Foundation import CoreData -import GCDKit +#if USE_FRAMEWORKS + import GCDKit +#endif // MARK: - CoreStore diff --git a/CoreStore/Migrating/DataStack+Migration.swift b/CoreStore/Migrating/DataStack+Migration.swift index 6e6ff37..8c82604 100644 --- a/CoreStore/Migrating/DataStack+Migration.swift +++ b/CoreStore/Migrating/DataStack+Migration.swift @@ -25,7 +25,9 @@ import Foundation import CoreData -import GCDKit +#if USE_FRAMEWORKS + import GCDKit +#endif // MARK: - DataStack diff --git a/CoreStore/Observing/DataStack+Observing.swift b/CoreStore/Observing/DataStack+Observing.swift index 4b7b039..662c857 100644 --- a/CoreStore/Observing/DataStack+Observing.swift +++ b/CoreStore/Observing/DataStack+Observing.swift @@ -25,7 +25,9 @@ import Foundation import CoreData -import GCDKit +#if USE_FRAMEWORKS + import GCDKit +#endif // MARK: - DataStack diff --git a/CoreStore/Observing/ListMonitor.swift b/CoreStore/Observing/ListMonitor.swift index 7457388..4158479 100644 --- a/CoreStore/Observing/ListMonitor.swift +++ b/CoreStore/Observing/ListMonitor.swift @@ -25,7 +25,9 @@ import Foundation import CoreData -import GCDKit +#if USE_FRAMEWORKS + import GCDKit +#endif // MARK: - ListMonitor diff --git a/CoreStore/Observing/ObjectMonitor.swift b/CoreStore/Observing/ObjectMonitor.swift index ada879a..499b43f 100644 --- a/CoreStore/Observing/ObjectMonitor.swift +++ b/CoreStore/Observing/ObjectMonitor.swift @@ -25,7 +25,9 @@ import Foundation import CoreData -import GCDKit +#if USE_FRAMEWORKS + import GCDKit +#endif // MARK: - ObjectMonitor diff --git a/CoreStore/Saving and Processing/AsynchronousDataTransaction.swift b/CoreStore/Saving and Processing/AsynchronousDataTransaction.swift index cddd47f..6aafa36 100644 --- a/CoreStore/Saving and Processing/AsynchronousDataTransaction.swift +++ b/CoreStore/Saving and Processing/AsynchronousDataTransaction.swift @@ -25,7 +25,9 @@ import Foundation import CoreData -import GCDKit +#if USE_FRAMEWORKS + import GCDKit +#endif // MARK: - AsynchronousDataTransaction diff --git a/CoreStore/Saving and Processing/BaseDataTransaction.swift b/CoreStore/Saving and Processing/BaseDataTransaction.swift index addc74e..3a47e5e 100644 --- a/CoreStore/Saving and Processing/BaseDataTransaction.swift +++ b/CoreStore/Saving and Processing/BaseDataTransaction.swift @@ -25,7 +25,9 @@ import Foundation import CoreData -import GCDKit +#if USE_FRAMEWORKS + import GCDKit +#endif // MARK: - BaseDataTransaction diff --git a/CoreStore/Saving and Processing/DataStack+Transaction.swift b/CoreStore/Saving and Processing/DataStack+Transaction.swift index aa00a64..789b157 100644 --- a/CoreStore/Saving and Processing/DataStack+Transaction.swift +++ b/CoreStore/Saving and Processing/DataStack+Transaction.swift @@ -25,7 +25,9 @@ import Foundation import CoreData -import GCDKit +#if USE_FRAMEWORKS + import GCDKit +#endif // MARK: - DataStack diff --git a/CoreStore/Saving and Processing/SynchronousDataTransaction.swift b/CoreStore/Saving and Processing/SynchronousDataTransaction.swift index 2733320..229a763 100644 --- a/CoreStore/Saving and Processing/SynchronousDataTransaction.swift +++ b/CoreStore/Saving and Processing/SynchronousDataTransaction.swift @@ -25,7 +25,9 @@ import Foundation import CoreData -import GCDKit +#if USE_FRAMEWORKS + import GCDKit +#endif // MARK: - SynchronousDataTransaction diff --git a/CoreStore/Saving and Processing/UnsafeDataTransaction.swift b/CoreStore/Saving and Processing/UnsafeDataTransaction.swift index 98831ba..29c5b40 100644 --- a/CoreStore/Saving and Processing/UnsafeDataTransaction.swift +++ b/CoreStore/Saving and Processing/UnsafeDataTransaction.swift @@ -25,7 +25,9 @@ import Foundation import CoreData -import GCDKit +#if USE_FRAMEWORKS + import GCDKit +#endif @available(*, deprecated=1.3.1, renamed="UnsafeDataTransaction") diff --git a/CoreStore/Setting Up/CoreStore+Setup.swift b/CoreStore/Setting Up/CoreStore+Setup.swift index c54c387..bd8364c 100644 --- a/CoreStore/Setting Up/CoreStore+Setup.swift +++ b/CoreStore/Setting Up/CoreStore+Setup.swift @@ -25,7 +25,9 @@ import Foundation import CoreData -import GCDKit +#if USE_FRAMEWORKS + import GCDKit +#endif // MARK: - CoreStore diff --git a/CoreStore/Setting Up/DataStack.swift b/CoreStore/Setting Up/DataStack.swift index d46dc7f..a65c5e2 100644 --- a/CoreStore/Setting Up/DataStack.swift +++ b/CoreStore/Setting Up/DataStack.swift @@ -25,7 +25,9 @@ import Foundation import CoreData -import GCDKit +#if USE_FRAMEWORKS + import GCDKit +#endif internal let applicationSupportDirectory = NSFileManager.defaultManager().URLsForDirectory(.ApplicationSupportDirectory, inDomains: .UserDomainMask).first! diff --git a/CoreStoreDemo/CoreStoreDemo/Loggers Demo/CustomLoggerViewController.swift b/CoreStoreDemo/CoreStoreDemo/Loggers Demo/CustomLoggerViewController.swift index eea35a3..2e00ff6 100644 --- a/CoreStoreDemo/CoreStoreDemo/Loggers Demo/CustomLoggerViewController.swift +++ b/CoreStoreDemo/CoreStoreDemo/Loggers Demo/CustomLoggerViewController.swift @@ -8,7 +8,9 @@ import UIKit import CoreStore -import GCDKit +#if USE_FRAMEWORKS + import GCDKit +#endif // MARK: - CustomLoggerViewController diff --git a/CoreStoreDemo/CoreStoreDemo/Transactions Demo/TransactionsDemoViewController.swift b/CoreStoreDemo/CoreStoreDemo/Transactions Demo/TransactionsDemoViewController.swift index 9f1962d..62e24aa 100644 --- a/CoreStoreDemo/CoreStoreDemo/Transactions Demo/TransactionsDemoViewController.swift +++ b/CoreStoreDemo/CoreStoreDemo/Transactions Demo/TransactionsDemoViewController.swift @@ -11,7 +11,9 @@ import CoreLocation import MapKit import AddressBookUI import CoreStore -import GCDKit +#if USE_FRAMEWORKS + import GCDKit +#endif private struct Static { From c5ff02335ee7b7fd71ccd7436a11267216a7d277 Mon Sep 17 00:00:00 2001 From: John Estropia Date: Tue, 24 Nov 2015 12:32:10 +0900 Subject: [PATCH 3/8] debug flag --- CoreStore.xcodeproj/project.pbxproj | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/CoreStore.xcodeproj/project.pbxproj b/CoreStore.xcodeproj/project.pbxproj index 4ad23a3..6f4b636 100644 --- a/CoreStore.xcodeproj/project.pbxproj +++ b/CoreStore.xcodeproj/project.pbxproj @@ -1169,7 +1169,7 @@ IPHONEOS_DEPLOYMENT_TARGET = 8.1; MTL_ENABLE_DEBUG_INFO = YES; ONLY_ACTIVE_ARCH = YES; - OTHER_SWIFT_FLAGS = "-D USE_FRAMEWORKS"; + OTHER_SWIFT_FLAGS = "-D USE_FRAMEWORKS -D DEBUG"; SDKROOT = iphoneos; SWIFT_OPTIMIZATION_LEVEL = "-Onone"; TARGETED_DEVICE_FAMILY = "1,2"; @@ -1232,7 +1232,6 @@ INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; IPHONEOS_DEPLOYMENT_TARGET = 8.0; LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; - OTHER_SWIFT_FLAGS = "-D DEBUG"; PRODUCT_BUNDLE_IDENTIFIER = "com.johnestropia.$(PRODUCT_NAME:rfc1034identifier)"; PRODUCT_NAME = CoreStore; SKIP_INSTALL = YES; From 718d2c9b7d464afe7af79b54bb114da6a8dc5fae Mon Sep 17 00:00:00 2001 From: John Estropia Date: Tue, 24 Nov 2015 14:49:43 +0900 Subject: [PATCH 4/8] 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) --- CoreStore.podspec | 2 +- CoreStore/Info.plist | 2 +- CoreStore/Observing/CoreStore+Observing.swift | 50 ++++++++++++ CoreStore/Observing/DataStack+Observing.swift | 80 +++++++++++++++++++ CoreStore/Observing/ListMonitor.swift | 37 ++++++++- README.md | 2 +- 6 files changed, 168 insertions(+), 5 deletions(-) diff --git a/CoreStore.podspec b/CoreStore.podspec index fba19e6..4378141 100644 --- a/CoreStore.podspec +++ b/CoreStore.podspec @@ -1,6 +1,6 @@ Pod::Spec.new do |s| s.name = "CoreStore" - s.version = "1.3.3" + s.version = "1.3.4" s.license = "MIT" s.summary = "Unleashing the real power of Core Data with the elegance and safety of Swift" s.homepage = "https://github.com/JohnEstropia/CoreStore" diff --git a/CoreStore/Info.plist b/CoreStore/Info.plist index 009ff7e..2e9a7c2 100644 --- a/CoreStore/Info.plist +++ b/CoreStore/Info.plist @@ -15,7 +15,7 @@ CFBundlePackageType FMWK CFBundleShortVersionString - 1.3.3 + 1.3.4 CFBundleSignature ???? CFBundleVersion diff --git a/CoreStore/Observing/CoreStore+Observing.swift b/CoreStore/Observing/CoreStore+Observing.swift index df5b735..90303bf 100644 --- a/CoreStore/Observing/CoreStore+Observing.swift +++ b/CoreStore/Observing/CoreStore+Observing.swift @@ -72,6 +72,30 @@ public extension CoreStore { return self.defaultStack.monitorList(from, queryClauses) } + /** + Using the `defaultStack`, asynchronously creates a `ListMonitor` for a list of `NSManagedObject`s that satisfy the specified fetch clauses. Multiple `ListObserver`s may then register themselves to be notified when changes are made to the list. Since `NSFetchedResultsController` greedily locks the persistent store on initial fetch, you may prefer this method instead of the synchronous counterpart to avoid deadlocks while background updates/saves are being executed. + + - parameter createAsynchronously: the closure that receives the created `ListMonitor` instance + - parameter from: a `From` clause indicating the entity type + - parameter fetchClauses: a series of `FetchClause` instances for fetching the object list. Accepts `Where`, `OrderBy`, and `Tweak` clauses. + */ + public static func monitorList(createAsynchronously createAsynchronously: (ListMonitor) -> Void, _ from: From, _ fetchClauses: FetchClause...) { + + self.defaultStack.monitorList(createAsynchronously: createAsynchronously, from, fetchClauses) + } + + /** + Using the `defaultStack`, asynchronously creates a `ListMonitor` for a list of `NSManagedObject`s that satisfy the specified fetch clauses. Multiple `ListObserver`s may then register themselves to be notified when changes are made to the list. Since `NSFetchedResultsController` greedily locks the persistent store on initial fetch, you may prefer this method instead of the synchronous counterpart to avoid deadlocks while background updates/saves are being executed. + + - parameter createAsynchronously: the closure that receives the created `ListMonitor` instance + - parameter from: a `From` clause indicating the entity type + - parameter fetchClauses: a series of `FetchClause` instances for fetching the object list. Accepts `Where`, `OrderBy`, and `Tweak` clauses. + */ + public static func monitorList(createAsynchronously createAsynchronously: (ListMonitor) -> Void, _ from: From, _ fetchClauses: [FetchClause]) { + + self.defaultStack.monitorList(createAsynchronously: createAsynchronously, from, fetchClauses) + } + /** Using the `defaultStack`, creates a `ListMonitor` for a sectioned list of `NSManagedObject`s that satisfy the specified fetch clauses. Multiple `ListObserver`s may then register themselves to be notified when changes are made to the list. @@ -99,4 +123,30 @@ public extension CoreStore { return self.defaultStack.monitorSectionedList(from, sectionBy, fetchClauses) } + + /** + Using the `defaultStack`, asynchronously creates a `ListMonitor` for a sectioned list of `NSManagedObject`s that satisfy the specified fetch clauses. Multiple `ListObserver`s may then register themselves to be notified when changes are made to the list. Since `NSFetchedResultsController` greedily locks the persistent store on initial fetch, you may prefer this method instead of the synchronous counterpart to avoid deadlocks while background updates/saves are being executed. + + - parameter createAsynchronously: the closure that receives the created `ListMonitor` instance + - parameter from: a `From` clause indicating the entity type + - parameter sectionBy: a `SectionBy` clause indicating the keyPath for the attribute to use when sorting the list into sections. + - parameter fetchClauses: a series of `FetchClause` instances for fetching the object list. Accepts `Where`, `OrderBy`, and `Tweak` clauses. + */ + public static func monitorSectionedList(createAsynchronously createAsynchronously: (ListMonitor) -> Void, _ from: From, _ sectionBy: SectionBy, _ fetchClauses: FetchClause...) { + + self.defaultStack.monitorSectionedList(createAsynchronously: createAsynchronously, from, sectionBy, fetchClauses) + } + + /** + Using the `defaultStack`, asynchronously creates a `ListMonitor` for a sectioned list of `NSManagedObject`s that satisfy the specified fetch clauses. Multiple `ListObserver`s may then register themselves to be notified when changes are made to the list. Since `NSFetchedResultsController` greedily locks the persistent store on initial fetch, you may prefer this method instead of the synchronous counterpart to avoid deadlocks while background updates/saves are being executed. + + - parameter createAsynchronously: the closure that receives the created `ListMonitor` instance + - parameter from: a `From` clause indicating the entity type + - parameter sectionBy: a `SectionBy` clause indicating the keyPath for the attribute to use when sorting the list into sections. + - parameter fetchClauses: a series of `FetchClause` instances for fetching the object list. Accepts `Where`, `OrderBy`, and `Tweak` clauses. + */ + public static func monitorSectionedList(createAsynchronously createAsynchronously: (ListMonitor) -> Void, _ from: From, _ sectionBy: SectionBy, _ fetchClauses: [FetchClause]) { + + self.defaultStack.monitorSectionedList(createAsynchronously: createAsynchronously, from, sectionBy, fetchClauses) + } } diff --git a/CoreStore/Observing/DataStack+Observing.swift b/CoreStore/Observing/DataStack+Observing.swift index 662c857..73006bd 100644 --- a/CoreStore/Observing/DataStack+Observing.swift +++ b/CoreStore/Observing/DataStack+Observing.swift @@ -97,6 +97,45 @@ public extension DataStack { ) } + /** + Asynchronously creates a `ListMonitor` for a list of `NSManagedObject`s that satisfy the specified fetch clauses. Multiple `ListObserver`s may then register themselves to be notified when changes are made to the list. Since `NSFetchedResultsController` greedily locks the persistent store on initial fetch, you may prefer this method instead of the synchronous counterpart to avoid deadlocks while background updates/saves are being executed. + + - parameter createAsynchronously: the closure that receives the created `ListMonitor` instance + - parameter from: a `From` clause indicating the entity type + - parameter fetchClauses: a series of `FetchClause` instances for fetching the object list. Accepts `Where`, `OrderBy`, and `Tweak` clauses. + */ + public func monitorList(createAsynchronously createAsynchronously: (ListMonitor) -> Void, _ from: From, _ fetchClauses: FetchClause...) { + + self.monitorList(createAsynchronously: createAsynchronously, from, fetchClauses) + } + + /** + Asynchronously creates a `ListMonitor` for a list of `NSManagedObject`s that satisfy the specified fetch clauses. Multiple `ListObserver`s may then register themselves to be notified when changes are made to the list. Since `NSFetchedResultsController` greedily locks the persistent store on initial fetch, you may prefer this method instead of the synchronous counterpart to avoid deadlocks while background updates/saves are being executed. + + - parameter createAsynchronously: the closure that receives the created `ListMonitor` instance + - parameter from: a `From` clause indicating the entity type + - parameter fetchClauses: a series of `FetchClause` instances for fetching the object list. Accepts `Where`, `OrderBy`, and `Tweak` clauses. + */ + public func monitorList(createAsynchronously createAsynchronously: (ListMonitor) -> Void, _ from: From, _ fetchClauses: [FetchClause]) { + + CoreStore.assert( + NSThread.isMainThread(), + "Attempted to observe objects from \(typeName(self)) outside the main thread." + ) + CoreStore.assert( + fetchClauses.filter { $0 is OrderBy }.count > 0, + "A ListMonitor requires an OrderBy clause." + ) + + _ = ListMonitor( + dataStack: self, + from: from, + sectionBy: nil, + fetchClauses: fetchClauses, + createAsynchronously: createAsynchronously + ) + } + /** Creates a `ListMonitor` for a sectioned list of `NSManagedObject`s that satisfy the specified fetch clauses. Multiple `ListObserver`s may then register themselves to be notified when changes are made to the list. @@ -138,4 +177,45 @@ public extension DataStack { fetchClauses: fetchClauses ) } + + /** + Asynchronously creates a `ListMonitor` for a sectioned list of `NSManagedObject`s that satisfy the specified fetch clauses. Multiple `ListObserver`s may then register themselves to be notified when changes are made to the list. Since `NSFetchedResultsController` greedily locks the persistent store on initial fetch, you may prefer this method instead of the synchronous counterpart to avoid deadlocks while background updates/saves are being executed. + + - parameter createAsynchronously: the closure that receives the created `ListMonitor` instance + - parameter from: a `From` clause indicating the entity type + - parameter sectionBy: a `SectionBy` clause indicating the keyPath for the attribute to use when sorting the list into sections. + - parameter fetchClauses: a series of `FetchClause` instances for fetching the object list. Accepts `Where`, `OrderBy`, and `Tweak` clauses. + */ + public func monitorSectionedList(createAsynchronously createAsynchronously: (ListMonitor) -> Void, _ from: From, _ sectionBy: SectionBy, _ fetchClauses: FetchClause...) { + + self.monitorSectionedList(createAsynchronously: createAsynchronously, from, sectionBy, fetchClauses) + } + + /** + Asynchronously creates a `ListMonitor` for a sectioned list of `NSManagedObject`s that satisfy the specified fetch clauses. Multiple `ListObserver`s may then register themselves to be notified when changes are made to the list. Since `NSFetchedResultsController` greedily locks the persistent store on initial fetch, you may prefer this method instead of the synchronous counterpart to avoid deadlocks while background updates/saves are being executed. + + - parameter createAsynchronously: the closure that receives the created `ListMonitor` instance + - parameter from: a `From` clause indicating the entity type + - parameter sectionBy: a `SectionBy` clause indicating the keyPath for the attribute to use when sorting the list into sections. + - parameter fetchClauses: a series of `FetchClause` instances for fetching the object list. Accepts `Where`, `OrderBy`, and `Tweak` clauses. + */ + public func monitorSectionedList(createAsynchronously createAsynchronously: (ListMonitor) -> Void, _ from: From, _ sectionBy: SectionBy, _ fetchClauses: [FetchClause]) { + + CoreStore.assert( + NSThread.isMainThread(), + "Attempted to observe objects from \(typeName(self)) outside the main thread." + ) + CoreStore.assert( + fetchClauses.filter { $0 is OrderBy }.count > 0, + "A ListMonitor requires an OrderBy clause." + ) + + _ = ListMonitor( + dataStack: self, + from: from, + sectionBy: sectionBy, + fetchClauses: fetchClauses, + createAsynchronously: createAsynchronously + ) + } } diff --git a/CoreStore/Observing/ListMonitor.swift b/CoreStore/Observing/ListMonitor.swift index 4158479..98a41a0 100644 --- a/CoreStore/Observing/ListMonitor.swift +++ b/CoreStore/Observing/ListMonitor.swift @@ -885,7 +885,39 @@ public final class ListMonitor { // MARK: Internal - internal init(dataStack: DataStack, from: From, sectionBy: SectionBy?, fetchClauses: [FetchClause]) { + internal convenience init(dataStack: DataStack, from: From, sectionBy: SectionBy?, fetchClauses: [FetchClause]) { + + self.init( + dataStack: dataStack, + from: from, + sectionBy: sectionBy, + fetchClauses: fetchClauses, + prepareFetch: { _, performFetch in performFetch() } + ) + } + + internal convenience init(dataStack: DataStack, from: From, sectionBy: SectionBy?, fetchClauses: [FetchClause], createAsynchronously: (ListMonitor) -> Void) { + + self.init( + dataStack: dataStack, + from: from, + sectionBy: sectionBy, + fetchClauses: fetchClauses, + prepareFetch: { listMonitor, performFetch in + + dataStack.childTransactionQueue.async { + + performFetch() + GCDQueue.Main.async { + + createAsynchronously(listMonitor) + } + } + } + ) + } + + private init(dataStack: DataStack, from: From, sectionBy: SectionBy?, fetchClauses: [FetchClause], prepareFetch: (ListMonitor, () -> Void) -> Void) { let context = dataStack.mainContext @@ -927,7 +959,8 @@ public final class ListMonitor { fetchedResultsControllerDelegate.handler = self fetchedResultsControllerDelegate.fetchedResultsController = fetchedResultsController - try! fetchedResultsController.performFetch() + + prepareFetch(self, { try! fetchedResultsController.performFetch() }) } deinit { diff --git a/README.md b/README.md index 263fa4c..50cdc96 100644 --- a/README.md +++ b/README.md @@ -255,7 +255,7 @@ class MyViewController: UIViewController { ## Migrations -So far we have only seen `addSQLiteStoreAndWait(...)` used to initialize our persistent store. As the method name's "AndWait" suffix suggests, this method will block, even if a migration occurs. If migrations are expected, the asynchronous variant `addSQLiteStore(... completion:)` method is recommended: +So far we have only seen `addSQLiteStoreAndWait(...)` used to initialize our persistent store. As the method name's "AndWait" suffix suggests, this method blocks so it should not do long tasks such as store migrations (in fact CoreStore won't even attempt to, and any model mismatch will be reported as an error). If migrations are expected, the asynchronous variant `addSQLiteStore(... completion:)` method should be used instead: ```swift do { let progress: NSProgress = try dataStack.addSQLiteStore( From 1f2a70fd4209b689a61b730cd45332df1b2e6f5b Mon Sep 17 00:00:00 2001 From: John Estropia Date: Tue, 24 Nov 2015 16:06:48 +0900 Subject: [PATCH 5/8] minor fixes --- CoreStore/Internal/NSManagedObjectModel+Setup.swift | 11 +++++++---- CoreStore/Observing/ListObserver.swift | 2 -- 2 files changed, 7 insertions(+), 6 deletions(-) diff --git a/CoreStore/Internal/NSManagedObjectModel+Setup.swift b/CoreStore/Internal/NSManagedObjectModel+Setup.swift index ace2548..b975888 100644 --- a/CoreStore/Internal/NSManagedObjectModel+Setup.swift +++ b/CoreStore/Internal/NSManagedObjectModel+Setup.swift @@ -65,10 +65,13 @@ internal extension NSManagedObjectModel { } else if let resolvedVersion = modelVersions.first ?? modelVersionHints.first { - CoreStore.log( - .Warning, - message: "The MigrationChain leaf versions do not include any of the model file's embedded versions. Resolving to version \"\(resolvedVersion)\"." - ) + if !modelVersionHints.isEmpty { + + CoreStore.log( + .Warning, + message: "The MigrationChain leaf versions do not include any of the model file's embedded versions. Resolving to version \"\(resolvedVersion)\"." + ) + } currentModelVersion = resolvedVersion } else { diff --git a/CoreStore/Observing/ListObserver.swift b/CoreStore/Observing/ListObserver.swift index 7d33a18..b10b1c1 100644 --- a/CoreStore/Observing/ListObserver.swift +++ b/CoreStore/Observing/ListObserver.swift @@ -205,7 +205,6 @@ public protocol ListSectionObserver: ListObjectObserver { - parameter sectionInfo: the `NSFetchedResultsSectionInfo` for the inserted section - parameter sectionIndex: the new section index for the new section */ - @available(iOS 8.0, *) func listMonitor(monitor: ListMonitor, didInsertSection sectionInfo: NSFetchedResultsSectionInfo, toSectionIndex sectionIndex: Int) /** @@ -215,7 +214,6 @@ public protocol ListSectionObserver: ListObjectObserver { - parameter sectionInfo: the `NSFetchedResultsSectionInfo` for the deleted section - parameter sectionIndex: the previous section index for the deleted section */ - @available(iOS 8.0, *) func listMonitor(monitor: ListMonitor, didDeleteSection sectionInfo: NSFetchedResultsSectionInfo, fromSectionIndex sectionIndex: Int) } From f79a77ab78bb2a5c3753adb0d59335be28b84379 Mon Sep 17 00:00:00 2001 From: John Estropia Date: Tue, 24 Nov 2015 17:02:23 +0900 Subject: [PATCH 6/8] remove unneeded imports in demo app --- .../CoreStoreDemo.xcodeproj/project.pbxproj | 36 +++++++++++++++++-- .../CustomLoggerViewController.swift | 4 +-- .../TransactionsDemoViewController.swift | 4 +-- 3 files changed, 35 insertions(+), 9 deletions(-) diff --git a/CoreStoreDemo/CoreStoreDemo.xcodeproj/project.pbxproj b/CoreStoreDemo/CoreStoreDemo.xcodeproj/project.pbxproj index 8693038..b66c960 100644 --- a/CoreStoreDemo/CoreStoreDemo.xcodeproj/project.pbxproj +++ b/CoreStoreDemo/CoreStoreDemo.xcodeproj/project.pbxproj @@ -48,6 +48,20 @@ /* End PBXBuildFile section */ /* Begin PBXContainerItemProxy section */ + B5202CF11C044CC800DED140 /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = B583A9141AF5F4F3001F76AF /* CoreStore.xcodeproj */; + proxyType = 2; + remoteGlobalIDString = B52DD1741BE1F8CC00949AFE; + remoteInfo = "CoreStore OSX"; + }; + B5202CF31C044CC800DED140 /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = B583A9141AF5F4F3001F76AF /* CoreStore.xcodeproj */; + proxyType = 2; + remoteGlobalIDString = B52DD17D1BE1F8CC00949AFE; + remoteInfo = "CoreStoreTests OSX"; + }; B56321C51BD65965006C9394 /* PBXContainerItemProxy */ = { isa = PBXContainerItemProxy; containerPortal = B583A9141AF5F4F3001F76AF /* CoreStore.xcodeproj */; @@ -286,8 +300,10 @@ isa = PBXGroup; children = ( B583A91B1AF5F4F4001F76AF /* CoreStore.framework */, - B583A91D1AF5F4F4001F76AF /* CoreStoreTests iOS.xctest */, + B583A91D1AF5F4F4001F76AF /* CoreStoreTests.xctest */, B56321C61BD65965006C9394 /* CoreStore.framework */, + B5202CF21C044CC800DED140 /* CoreStore.framework */, + B5202CF41C044CC800DED140 /* CoreStoreTests.xctest */, ); name = Products; sourceTree = ""; @@ -355,6 +371,20 @@ /* End PBXProject section */ /* Begin PBXReferenceProxy section */ + B5202CF21C044CC800DED140 /* CoreStore.framework */ = { + isa = PBXReferenceProxy; + fileType = wrapper.framework; + path = CoreStore.framework; + remoteRef = B5202CF11C044CC800DED140 /* PBXContainerItemProxy */; + sourceTree = BUILT_PRODUCTS_DIR; + }; + B5202CF41C044CC800DED140 /* CoreStoreTests.xctest */ = { + isa = PBXReferenceProxy; + fileType = wrapper.cfbundle; + path = CoreStoreTests.xctest; + remoteRef = B5202CF31C044CC800DED140 /* PBXContainerItemProxy */; + sourceTree = BUILT_PRODUCTS_DIR; + }; B56321C61BD65965006C9394 /* CoreStore.framework */ = { isa = PBXReferenceProxy; fileType = wrapper.framework; @@ -369,10 +399,10 @@ remoteRef = B583A91A1AF5F4F4001F76AF /* PBXContainerItemProxy */; sourceTree = BUILT_PRODUCTS_DIR; }; - B583A91D1AF5F4F4001F76AF /* CoreStoreTests iOS.xctest */ = { + B583A91D1AF5F4F4001F76AF /* CoreStoreTests.xctest */ = { isa = PBXReferenceProxy; fileType = wrapper.cfbundle; - path = "CoreStoreTests iOS.xctest"; + path = CoreStoreTests.xctest; remoteRef = B583A91C1AF5F4F4001F76AF /* PBXContainerItemProxy */; sourceTree = BUILT_PRODUCTS_DIR; }; diff --git a/CoreStoreDemo/CoreStoreDemo/Loggers Demo/CustomLoggerViewController.swift b/CoreStoreDemo/CoreStoreDemo/Loggers Demo/CustomLoggerViewController.swift index 2e00ff6..eea35a3 100644 --- a/CoreStoreDemo/CoreStoreDemo/Loggers Demo/CustomLoggerViewController.swift +++ b/CoreStoreDemo/CoreStoreDemo/Loggers Demo/CustomLoggerViewController.swift @@ -8,9 +8,7 @@ import UIKit import CoreStore -#if USE_FRAMEWORKS - import GCDKit -#endif +import GCDKit // MARK: - CustomLoggerViewController diff --git a/CoreStoreDemo/CoreStoreDemo/Transactions Demo/TransactionsDemoViewController.swift b/CoreStoreDemo/CoreStoreDemo/Transactions Demo/TransactionsDemoViewController.swift index 62e24aa..9f1962d 100644 --- a/CoreStoreDemo/CoreStoreDemo/Transactions Demo/TransactionsDemoViewController.swift +++ b/CoreStoreDemo/CoreStoreDemo/Transactions Demo/TransactionsDemoViewController.swift @@ -11,9 +11,7 @@ import CoreLocation import MapKit import AddressBookUI import CoreStore -#if USE_FRAMEWORKS - import GCDKit -#endif +import GCDKit private struct Static { From b741626574e8f885bd0c39238c67792daa1ea5f2 Mon Sep 17 00:00:00 2001 From: John Estropia Date: Tue, 24 Nov 2015 17:50:23 +0900 Subject: [PATCH 7/8] updated GCDKit --- CoreStore.podspec | 2 +- Libraries/GCDKit | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/CoreStore.podspec b/CoreStore.podspec index 4378141..d138dd5 100644 --- a/CoreStore.podspec +++ b/CoreStore.podspec @@ -17,5 +17,5 @@ Pod::Spec.new do |s| s.requires_arc = true s.pod_target_xcconfig = { 'OTHER_SWIFT_FLAGS' => '-D USE_FRAMEWORKS' } - s.dependency "GCDKit", "1.1.3" + s.dependency "GCDKit", "1.1.4" end \ No newline at end of file diff --git a/Libraries/GCDKit b/Libraries/GCDKit index 6b72512..5c5b4c1 160000 --- a/Libraries/GCDKit +++ b/Libraries/GCDKit @@ -1 +1 @@ -Subproject commit 6b72512258092d76e6e515672a308b8ec34257ae +Subproject commit 5c5b4c178e6c47df98cf0444364fa5a48f4c93ca From 578e4966fc87a10ebbf1bb0c4eb13e88696dc527 Mon Sep 17 00:00:00 2001 From: John Estropia Date: Tue, 24 Nov 2015 19:12:04 +0900 Subject: [PATCH 8/8] added a convenience initializer for clients that only support NSFetchedResultsController (i.e. Objective-C) --- CoreStore.podspec | 2 +- CoreStore.xcodeproj/project.pbxproj | 6 +++ ...FetchedResultsController+Convenience.swift | 50 +++++++++++++++++++ CoreStore/Observing/ListMonitor.swift | 16 ++---- CoreStore/Observing/ObjectMonitor.swift | 11 +--- 5 files changed, 63 insertions(+), 22 deletions(-) create mode 100644 CoreStore/Convenience Helpers/NSFetchedResultsController+Convenience.swift diff --git a/CoreStore.podspec b/CoreStore.podspec index d138dd5..5174ecf 100644 --- a/CoreStore.podspec +++ b/CoreStore.podspec @@ -12,7 +12,7 @@ Pod::Spec.new do |s| s.watchos.deployment_target = "2.0" s.source_files = "CoreStore", "CoreStore/**/*.{swift}" - s.osx.exclude_files = "CoreStore/Observing/*.{swift}", "CoreStore/Internal/FetchedResultsControllerDelegate.swift" + s.osx.exclude_files = "CoreStore/Observing/*.{swift}", "CoreStore/Internal/FetchedResultsControllerDelegate.swift", "CoreStore/Internal/NSFetchedResultsController+Convenience.swift" s.frameworks = "Foundation", "CoreData" s.requires_arc = true s.pod_target_xcconfig = { 'OTHER_SWIFT_FLAGS' => '-D USE_FRAMEWORKS' } diff --git a/CoreStore.xcodeproj/project.pbxproj b/CoreStore.xcodeproj/project.pbxproj index 6f4b636..20d777b 100644 --- a/CoreStore.xcodeproj/project.pbxproj +++ b/CoreStore.xcodeproj/project.pbxproj @@ -13,6 +13,8 @@ 2F291E2719C6D3CF007AF63F /* CoreStore.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2F291E2619C6D3CF007AF63F /* CoreStore.swift */; }; B504D0D61B02362500B2BBB1 /* CoreStore+Setup.swift in Sources */ = {isa = PBXBuildFile; fileRef = B504D0D51B02362500B2BBB1 /* CoreStore+Setup.swift */; }; B51BE06A1B47FC4B0069F532 /* NSManagedObjectModel+Setup.swift in Sources */ = {isa = PBXBuildFile; fileRef = B51BE0691B47FC4B0069F532 /* NSManagedObjectModel+Setup.swift */; }; + B5202CFA1C04688100DED140 /* NSFetchedResultsController+Convenience.swift in Sources */ = {isa = PBXBuildFile; fileRef = B5202CF91C04688100DED140 /* NSFetchedResultsController+Convenience.swift */; }; + B5202CFD1C046E8400DED140 /* NSFetchedResultsController+Convenience.swift in Sources */ = {isa = PBXBuildFile; fileRef = B5202CF91C04688100DED140 /* NSFetchedResultsController+Convenience.swift */; }; B52DD17E1BE1F8CD00949AFE /* CoreStore.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = B52DD1741BE1F8CC00949AFE /* CoreStore.framework */; }; B52DD1901BE1F8E600949AFE /* GCDKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = B5D808021A34715700A44484 /* GCDKit.framework */; }; B52DD1911BE1F8EB00949AFE /* Foundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = B5548CD51BD65AE00077652A /* Foundation.framework */; }; @@ -274,6 +276,7 @@ 2F291E2619C6D3CF007AF63F /* CoreStore.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; lineEnding = 0; path = CoreStore.swift; sourceTree = ""; }; B504D0D51B02362500B2BBB1 /* CoreStore+Setup.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "CoreStore+Setup.swift"; sourceTree = ""; }; B51BE0691B47FC4B0069F532 /* NSManagedObjectModel+Setup.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "NSManagedObjectModel+Setup.swift"; sourceTree = ""; }; + B5202CF91C04688100DED140 /* NSFetchedResultsController+Convenience.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "NSFetchedResultsController+Convenience.swift"; sourceTree = ""; }; B52DD1741BE1F8CC00949AFE /* CoreStore.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = CoreStore.framework; sourceTree = BUILT_PRODUCTS_DIR; }; B52DD17D1BE1F8CC00949AFE /* CoreStoreTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = CoreStoreTests.xctest; sourceTree = BUILT_PRODUCTS_DIR; }; B54A6A541BA15F2A007870FD /* FetchedResultsControllerDelegate.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = FetchedResultsControllerDelegate.swift; sourceTree = ""; }; @@ -617,6 +620,7 @@ children = ( B5E84F271AFF84920064E85B /* NSManagedObject+Convenience.swift */, B5FAD6A81B50A4B300714891 /* NSProgress+Convenience.swift */, + B5202CF91C04688100DED140 /* NSFetchedResultsController+Convenience.swift */, ); path = "Convenience Helpers"; sourceTree = ""; @@ -918,6 +922,7 @@ B5E84EE71AFF84610064E85B /* CoreStore+Logging.swift in Sources */, B56007111B3F6BD500A9A8F9 /* Into.swift in Sources */, B5E84F111AFF847B0064E85B /* Select.swift in Sources */, + B5202CFA1C04688100DED140 /* NSFetchedResultsController+Convenience.swift in Sources */, B5E84EE11AFF84500064E85B /* PersistentStoreResult.swift in Sources */, B5E84F251AFF84860064E85B /* ObjectObserver.swift in Sources */, B5E84F2F1AFF849C0064E85B /* NotificationObserver.swift in Sources */, @@ -1056,6 +1061,7 @@ B56321811BD65216006C9394 /* DataStack.swift in Sources */, B56321A81BD65219006C9394 /* NSManagedObject+Convenience.swift in Sources */, B56321981BD65216006C9394 /* Where.swift in Sources */, + B5202CFD1C046E8400DED140 /* NSFetchedResultsController+Convenience.swift in Sources */, B56321AF1BD6521C006C9394 /* NSFileManager+Setup.swift in Sources */, B56321971BD65216006C9394 /* Select.swift in Sources */, B56321AB1BD6521C006C9394 /* FetchedResultsControllerDelegate.swift in Sources */, diff --git a/CoreStore/Convenience Helpers/NSFetchedResultsController+Convenience.swift b/CoreStore/Convenience Helpers/NSFetchedResultsController+Convenience.swift new file mode 100644 index 0000000..0b468b2 --- /dev/null +++ b/CoreStore/Convenience Helpers/NSFetchedResultsController+Convenience.swift @@ -0,0 +1,50 @@ +// +// NSManagedObject+Convenience.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: - NSFetchedResultsController + +public extension NSFetchedResultsController { + + public convenience init(dataStack: DataStack, fetchRequest: NSFetchRequest, from: From? = nil, sectionBy: SectionBy? = nil, fetchClauses: [FetchClause]) { + + let context = dataStack.mainContext + from?.applyToFetchRequest(fetchRequest, context: context) + for clause in fetchClauses { + + clause.applyToFetchRequest(fetchRequest) + } + + self.init( + fetchRequest: fetchRequest, + managedObjectContext: context, + sectionNameKeyPath: sectionBy?.sectionKeyPath, + cacheName: nil + ) + } +} diff --git a/CoreStore/Observing/ListMonitor.swift b/CoreStore/Observing/ListMonitor.swift index 98a41a0..d2a6179 100644 --- a/CoreStore/Observing/ListMonitor.swift +++ b/CoreStore/Observing/ListMonitor.swift @@ -919,27 +919,19 @@ public final class ListMonitor { private init(dataStack: DataStack, from: From, sectionBy: SectionBy?, fetchClauses: [FetchClause], prepareFetch: (ListMonitor, () -> Void) -> Void) { - let context = dataStack.mainContext - let fetchRequest = NSFetchRequest() - from.applyToFetchRequest(fetchRequest, context: context) - fetchRequest.fetchLimit = 0 fetchRequest.resultType = .ManagedObjectResultType fetchRequest.fetchBatchSize = 20 fetchRequest.includesPendingChanges = false fetchRequest.shouldRefreshRefetchedObjects = true - for clause in fetchClauses { - - clause.applyToFetchRequest(fetchRequest) - } - let fetchedResultsController = NSFetchedResultsController( + dataStack: dataStack, fetchRequest: fetchRequest, - managedObjectContext: context, - sectionNameKeyPath: sectionBy?.sectionKeyPath, - cacheName: nil + from: from, + sectionBy: sectionBy, + fetchClauses: fetchClauses ) let fetchedResultsControllerDelegate = FetchedResultsControllerDelegate() diff --git a/CoreStore/Observing/ObjectMonitor.swift b/CoreStore/Observing/ObjectMonitor.swift index 499b43f..6458b35 100644 --- a/CoreStore/Observing/ObjectMonitor.swift +++ b/CoreStore/Observing/ObjectMonitor.swift @@ -167,25 +167,18 @@ public final class ObjectMonitor { internal init(dataStack: DataStack, object: T) { - let context = dataStack.mainContext - let fetchRequest = NSFetchRequest() fetchRequest.entity = object.entity - fetchRequest.fetchLimit = 0 fetchRequest.resultType = .ManagedObjectResultType fetchRequest.sortDescriptors = [] fetchRequest.includesPendingChanges = false fetchRequest.shouldRefreshRefetchedObjects = true - let originalObjectID = object.objectID - Where("SELF", isEqualTo: originalObjectID).applyToFetchRequest(fetchRequest) - let fetchedResultsController = NSFetchedResultsController( + dataStack: dataStack, fetchRequest: fetchRequest, - managedObjectContext: context, - sectionNameKeyPath: nil, - cacheName: nil + fetchClauses: [Where("SELF", isEqualTo: object.objectID)] ) let fetchedResultsControllerDelegate = FetchedResultsControllerDelegate()