Improve refetch method (may fix #118)

This commit is contained in:
John Estropia
2017-04-24 11:57:47 +09:00
parent 9dc4331b26
commit 53ab140341
3 changed files with 58 additions and 23 deletions

View File

@@ -43,7 +43,10 @@ private struct Static {
didSet { didSet {
self.palettes.refetch(self.filter.whereClause()) self.palettes.refetch(
self.filter.whereClause(),
OrderBy(.ascending(#keyPath(Palette.hue)))
)
} }
} }

View File

@@ -54,6 +54,9 @@ internal final class FetchedResultsControllerDelegate: NSObject, NSFetchedResult
@nonobjc @nonobjc
internal var enabled = true internal var enabled = true
@nonobjc
internal let taskGroup = DispatchGroup()
@nonobjc @nonobjc
internal weak var handler: FetchedResultsControllerHandler? internal weak var handler: FetchedResultsControllerHandler?
@@ -78,6 +81,7 @@ internal final class FetchedResultsControllerDelegate: NSObject, NSFetchedResult
@objc @objc
dynamic func controllerWillChangeContent(_ controller: NSFetchedResultsController<NSFetchRequestResult>) { dynamic func controllerWillChangeContent(_ controller: NSFetchedResultsController<NSFetchRequestResult>) {
self.taskGroup.enter()
guard self.enabled else { guard self.enabled else {
return return
@@ -92,6 +96,10 @@ internal final class FetchedResultsControllerDelegate: NSObject, NSFetchedResult
@objc @objc
dynamic func controllerDidChangeContent(_ controller: NSFetchedResultsController<NSFetchRequestResult>) { dynamic func controllerDidChangeContent(_ controller: NSFetchedResultsController<NSFetchRequestResult>) {
defer {
self.taskGroup.leave()
}
guard self.enabled else { guard self.enabled else {
return return

View File

@@ -555,7 +555,7 @@ public final class ListMonitor<D: DynamicObject>: Hashable {
`refetch(...)` broadcasts `listMonitorWillRefetch(...)` to its observers immediately, and then `listMonitorDidRefetch(...)` after the new fetch request completes. `refetch(...)` broadcasts `listMonitorWillRefetch(...)` to its observers immediately, and then `listMonitorDidRefetch(...)` after the new fetch request completes.
- parameter fetchClauses: a series of `FetchClause` instances for fetching the object list. Accepts `Where`, `OrderBy`, and `Tweak` clauses. Note that only specified clauses will be changed; unspecified clauses will use previous values. - parameter fetchClauses: a series of `FetchClause` instances for fetching the object list. Accepts `Where`, `OrderBy`, and `Tweak` clauses. Important: Starting CoreStore 4.0, all `FetchClause`s required by the `ListMonitor` should be provided in the arguments list of `refetch(...)`.
*/ */
public func refetch(_ fetchClauses: FetchClause...) { public func refetch(_ fetchClauses: FetchClause...) {
@@ -567,7 +567,7 @@ public final class ListMonitor<D: DynamicObject>: Hashable {
`refetch(...)` broadcasts `listMonitorWillRefetch(...)` to its observers immediately, and then `listMonitorDidRefetch(...)` after the new fetch request completes. `refetch(...)` broadcasts `listMonitorWillRefetch(...)` to its observers immediately, and then `listMonitorDidRefetch(...)` after the new fetch request completes.
- parameter fetchClauses: a series of `FetchClause` instances for fetching the object list. Accepts `Where`, `OrderBy`, and `Tweak` clauses. Note that only specified clauses will be changed; unspecified clauses will use previous values. - parameter fetchClauses: a series of `FetchClause` instances for fetching the object list. Accepts `Where`, `OrderBy`, and `Tweak` clauses. Important: Starting CoreStore 4.0, all `FetchClause`s required by the `ListMonitor` should be provided in the arguments list of `refetch(...)`.
*/ */
public func refetch(_ fetchClauses: [FetchClause]) { public func refetch(_ fetchClauses: [FetchClause]) {
@@ -946,8 +946,12 @@ public final class ListMonitor<D: DynamicObject>: Hashable {
return return
} }
self.fetchedResultsControllerDelegate.enabled = false let (newFetchedResultsController, newFetchedResultsControllerDelegate) = ListMonitor.recreateFetchedResultsController(
self.applyFetchClauses(self.fetchedResultsController.fetchRequest) context: self.fetchedResultsController.managedObjectContext,
from: self.from,
sectionBy: self.sectionBy,
applyFetchClauses: self.applyFetchClauses
)
self.transactionQueue.async { [weak self] in self.transactionQueue.async { [weak self] in
@@ -956,16 +960,21 @@ public final class ListMonitor<D: DynamicObject>: Hashable {
return return
} }
try! self.fetchedResultsController.performFetchFromSpecifiedStores() try! newFetchedResultsController.performFetchFromSpecifiedStores()
self.fetchedResultsControllerDelegate.taskGroup.notify(queue: .main) {
DispatchQueue.main.async { [weak self] () -> Void in
self.fetchedResultsControllerDelegate.enabled = false
}
newFetchedResultsControllerDelegate.taskGroup.notify(queue: .main) { [weak self] () -> Void in
guard let `self` = self else { guard let `self` = self else {
return return
} }
self.fetchedResultsControllerDelegate.enabled = true (self.fetchedResultsController, self.fetchedResultsControllerDelegate) = (newFetchedResultsController, newFetchedResultsControllerDelegate)
newFetchedResultsControllerDelegate.handler = self
self.isPendingRefetch = false self.isPendingRefetch = false
NotificationCenter.default.post( NotificationCenter.default.post(
@@ -986,7 +995,7 @@ public final class ListMonitor<D: DynamicObject>: Hashable {
// MARK: Private // MARK: Private
fileprivate let fetchedResultsController: CoreStoreFetchedResultsController fileprivate var fetchedResultsController: CoreStoreFetchedResultsController
fileprivate let taskGroup = DispatchGroup() fileprivate let taskGroup = DispatchGroup()
fileprivate let sectionIndexTransformer: (_ sectionName: KeyPath?) -> String? fileprivate let sectionIndexTransformer: (_ sectionName: KeyPath?) -> String?
@@ -1005,7 +1014,7 @@ public final class ListMonitor<D: DynamicObject>: Hashable {
private var didInsertSectionKey: Void? private var didInsertSectionKey: Void?
private var didDeleteSectionKey: Void? private var didDeleteSectionKey: Void?
private let fetchedResultsControllerDelegate: FetchedResultsControllerDelegate private var fetchedResultsControllerDelegate: FetchedResultsControllerDelegate
private var observerForWillChangePersistentStore: NotificationObserver! private var observerForWillChangePersistentStore: NotificationObserver!
private var observerForDidChangePersistentStore: NotificationObserver! private var observerForDidChangePersistentStore: NotificationObserver!
private let transactionQueue: DispatchQueue private let transactionQueue: DispatchQueue
@@ -1032,9 +1041,7 @@ public final class ListMonitor<D: DynamicObject>: Hashable {
} }
} }
private init(context: NSManagedObjectContext, transactionQueue: DispatchQueue, from: From<ObjectType>, sectionBy: SectionBy?, applyFetchClauses: @escaping (_ fetchRequest: NSFetchRequest<NSManagedObject>) -> Void, createAsynchronously: ((ListMonitor<ObjectType>) -> Void)?) { private static func recreateFetchedResultsController(context: NSManagedObjectContext, from: From<ObjectType>, sectionBy: SectionBy?, applyFetchClauses: @escaping (_ fetchRequest: NSFetchRequest<NSManagedObject>) -> Void) -> (controller: CoreStoreFetchedResultsController, delegate: FetchedResultsControllerDelegate) {
self.isSectioned = (sectionBy != nil)
let fetchRequest = CoreStoreFetchRequest() let fetchRequest = CoreStoreFetchRequest()
fetchRequest.fetchLimit = 0 fetchRequest.fetchLimit = 0
@@ -1052,9 +1059,25 @@ public final class ListMonitor<D: DynamicObject>: Hashable {
) )
let fetchedResultsControllerDelegate = FetchedResultsControllerDelegate() let fetchedResultsControllerDelegate = FetchedResultsControllerDelegate()
fetchedResultsControllerDelegate.fetchedResultsController = fetchedResultsController
self.fetchedResultsController = fetchedResultsController return (fetchedResultsController, fetchedResultsControllerDelegate)
self.fetchedResultsControllerDelegate = fetchedResultsControllerDelegate }
private let from: From<ObjectType>
private let sectionBy: SectionBy?
private init(context: NSManagedObjectContext, transactionQueue: DispatchQueue, from: From<ObjectType>, sectionBy: SectionBy?, applyFetchClauses: @escaping (_ fetchRequest: NSFetchRequest<NSManagedObject>) -> Void, createAsynchronously: ((ListMonitor<ObjectType>) -> Void)?) {
self.isSectioned = (sectionBy != nil)
self.from = from
self.sectionBy = sectionBy
(self.fetchedResultsController, self.fetchedResultsControllerDelegate) = ListMonitor.recreateFetchedResultsController(
context: context,
from: from,
sectionBy: sectionBy,
applyFetchClauses: applyFetchClauses
)
if let sectionIndexTransformer = sectionBy?.sectionIndexTransformer { if let sectionIndexTransformer = sectionBy?.sectionIndexTransformer {
@@ -1066,9 +1089,7 @@ public final class ListMonitor<D: DynamicObject>: Hashable {
} }
self.transactionQueue = transactionQueue self.transactionQueue = transactionQueue
self.applyFetchClauses = applyFetchClauses self.applyFetchClauses = applyFetchClauses
self.fetchedResultsControllerDelegate.handler = self
fetchedResultsControllerDelegate.handler = self
fetchedResultsControllerDelegate.fetchedResultsController = fetchedResultsController
guard let coordinator = context.parentStack?.coordinator else { guard let coordinator = context.parentStack?.coordinator else {
@@ -1129,7 +1150,7 @@ public final class ListMonitor<D: DynamicObject>: Hashable {
transactionQueue.async { transactionQueue.async {
try! fetchedResultsController.performFetchFromSpecifiedStores() try! self.fetchedResultsController.performFetchFromSpecifiedStores()
self.taskGroup.notify(queue: .main) { self.taskGroup.notify(queue: .main) {
createAsynchronously(self) createAsynchronously(self)
@@ -1138,7 +1159,7 @@ public final class ListMonitor<D: DynamicObject>: Hashable {
} }
else { else {
try! fetchedResultsController.performFetchFromSpecifiedStores() try! self.fetchedResultsController.performFetchFromSpecifiedStores()
} }
} }
} }
@@ -1326,12 +1347,15 @@ extension ListMonitor: FetchedResultsControllerHandler {
} }
internal func controllerDidChangeContent(_ controller: NSFetchedResultsController<NSFetchRequestResult>) { internal func controllerDidChangeContent(_ controller: NSFetchedResultsController<NSFetchRequestResult>) {
defer {
self.taskGroup.leave()
}
NotificationCenter.default.post( NotificationCenter.default.post(
name: Notification.Name.listMonitorDidChangeList, name: Notification.Name.listMonitorDidChangeList,
object: self object: self
) )
self.taskGroup.leave()
} }
internal func controller(_ controller: NSFetchedResultsController<NSFetchRequestResult>, sectionIndexTitleForSectionName sectionName: String?) -> String? { internal func controller(_ controller: NSFetchedResultsController<NSFetchRequestResult>, sectionIndexTitleForSectionName sectionName: String?) -> String? {