tag refetch methods with source identifiers

This commit is contained in:
John Estropia
2021-09-15 19:38:59 +09:00
parent 4ddfa95140
commit a1a04aaf8a
4 changed files with 224 additions and 46 deletions

View File

@@ -65,7 +65,8 @@ extension Modern {
sectionIndexTransformer: { $0?.first?.uppercased() }
)
.where(self.filter.whereClause())
.orderBy(.ascending(\.$hue))
.orderBy(.ascending(\.$hue)),
sourceIdentifier: TransactionSource.refetch
)
}
}
@@ -79,6 +80,7 @@ extension Modern {
case delete
case shuffle
case clear
case refetch
}
}
}

View File

@@ -47,7 +47,8 @@ extension Modern.ColorsDemo.UIKit {
.clear:
dataSource.apply(listPublisher.snapshot, animatingDifferences: true)
case nil:
case nil,
.refetch:
dataSource.apply(listPublisher.snapshot, animatingDifferences: false)
}
}

View File

@@ -393,19 +393,31 @@ public final class ListMonitor<O: DynamicObject>: Hashable {
observer,
willChange: { (observer, monitor) in
observer.listMonitorWillChange(monitor)
observer.listMonitorWillChange(
monitor,
sourceIdentifier: monitor.fetchedResultsController.managedObjectContext.saveMetadata?.sourceIdentifier
)
},
didChange: { (observer, monitor) in
observer.listMonitorDidChange(monitor)
observer.listMonitorDidChange(
monitor,
sourceIdentifier: monitor.fetchedResultsController.managedObjectContext.saveMetadata?.sourceIdentifier
)
},
willRefetch: { (observer, monitor) in
observer.listMonitorWillRefetch(monitor)
observer.listMonitorWillRefetch(
monitor,
sourceIdentifier: monitor.fetchedResultsController.managedObjectContext.saveMetadata?.sourceIdentifier
)
},
didRefetch: { (observer, monitor) in
observer.listMonitorDidRefetch(monitor)
observer.listMonitorDidRefetch(
monitor,
sourceIdentifier: monitor.fetchedResultsController.managedObjectContext.saveMetadata?.sourceIdentifier
)
}
)
}
@@ -428,38 +440,71 @@ public final class ListMonitor<O: DynamicObject>: Hashable {
observer,
willChange: { (observer, monitor) in
observer.listMonitorWillChange(monitor)
observer.listMonitorWillChange(
monitor,
sourceIdentifier: monitor.fetchedResultsController.managedObjectContext.saveMetadata?.sourceIdentifier
)
},
didChange: { (observer, monitor) in
observer.listMonitorDidChange(monitor)
observer.listMonitorDidChange(
monitor,
sourceIdentifier: monitor.fetchedResultsController.managedObjectContext.saveMetadata?.sourceIdentifier
)
},
willRefetch: { (observer, monitor) in
observer.listMonitorWillRefetch(monitor)
observer.listMonitorWillRefetch(
monitor,
sourceIdentifier: monitor.fetchedResultsController.managedObjectContext.saveMetadata?.sourceIdentifier
)
},
didRefetch: { (observer, monitor) in
observer.listMonitorDidRefetch(monitor)
observer.listMonitorDidRefetch(
monitor,
sourceIdentifier: monitor.fetchedResultsController.managedObjectContext.saveMetadata?.sourceIdentifier
)
}
)
self.registerObserver(
observer,
didInsertObject: { (observer, monitor, object, toIndexPath) in
observer.listMonitor(monitor, didInsertObject: object, toIndexPath: toIndexPath)
observer.listMonitor(
monitor,
didInsertObject: object,
toIndexPath: toIndexPath,
sourceIdentifier: monitor.fetchedResultsController.managedObjectContext.saveMetadata?.sourceIdentifier
)
},
didDeleteObject: { (observer, monitor, object, fromIndexPath) in
observer.listMonitor(monitor, didDeleteObject: object, fromIndexPath: fromIndexPath)
observer.listMonitor(
monitor,
didDeleteObject: object,
fromIndexPath: fromIndexPath,
sourceIdentifier: monitor.fetchedResultsController.managedObjectContext.saveMetadata?.sourceIdentifier
)
},
didUpdateObject: { (observer, monitor, object, atIndexPath) in
observer.listMonitor(monitor, didUpdateObject: object, atIndexPath: atIndexPath)
observer.listMonitor(
monitor,
didUpdateObject: object,
atIndexPath: atIndexPath,
sourceIdentifier: monitor.fetchedResultsController.managedObjectContext.saveMetadata?.sourceIdentifier
)
},
didMoveObject: { (observer, monitor, object, fromIndexPath, toIndexPath) in
observer.listMonitor(monitor, didMoveObject: object, fromIndexPath: fromIndexPath, toIndexPath: toIndexPath)
observer.listMonitor(
monitor,
didMoveObject: object,
fromIndexPath: fromIndexPath,
toIndexPath: toIndexPath,
sourceIdentifier: monitor.fetchedResultsController.managedObjectContext.saveMetadata?.sourceIdentifier
)
}
)
}
@@ -482,49 +527,92 @@ public final class ListMonitor<O: DynamicObject>: Hashable {
observer,
willChange: { (observer, monitor) in
observer.listMonitorWillChange(monitor)
observer.listMonitorWillChange(
monitor,
sourceIdentifier: monitor.fetchedResultsController.managedObjectContext.saveMetadata?.sourceIdentifier
)
},
didChange: { (observer, monitor) in
observer.listMonitorDidChange(monitor)
observer.listMonitorDidChange(
monitor,
sourceIdentifier: monitor.fetchedResultsController.managedObjectContext.saveMetadata?.sourceIdentifier
)
},
willRefetch: { (observer, monitor) in
observer.listMonitorWillRefetch(monitor)
observer.listMonitorWillRefetch(
monitor,
sourceIdentifier: monitor.fetchedResultsController.managedObjectContext.saveMetadata?.sourceIdentifier
)
},
didRefetch: { (observer, monitor) in
observer.listMonitorDidRefetch(monitor)
observer.listMonitorDidRefetch(
monitor,
sourceIdentifier: monitor.fetchedResultsController.managedObjectContext.saveMetadata?.sourceIdentifier
)
}
)
self.registerObserver(
observer,
didInsertObject: { (observer, monitor, object, toIndexPath) in
observer.listMonitor(monitor, didInsertObject: object, toIndexPath: toIndexPath)
observer.listMonitor(
monitor,
didInsertObject: object,
toIndexPath: toIndexPath,
sourceIdentifier: monitor.fetchedResultsController.managedObjectContext.saveMetadata?.sourceIdentifier
)
},
didDeleteObject: { (observer, monitor, object, fromIndexPath) in
observer.listMonitor(monitor, didDeleteObject: object, fromIndexPath: fromIndexPath)
observer.listMonitor(
monitor,
didDeleteObject: object,
fromIndexPath: fromIndexPath,
sourceIdentifier: monitor.fetchedResultsController.managedObjectContext.saveMetadata?.sourceIdentifier
)
},
didUpdateObject: { (observer, monitor, object, atIndexPath) in
observer.listMonitor(monitor, didUpdateObject: object, atIndexPath: atIndexPath)
observer.listMonitor(
monitor,
didUpdateObject: object,
atIndexPath: atIndexPath,
sourceIdentifier: monitor.fetchedResultsController.managedObjectContext.saveMetadata?.sourceIdentifier
)
},
didMoveObject: { (observer, monitor, object, fromIndexPath, toIndexPath) in
observer.listMonitor(monitor, didMoveObject: object, fromIndexPath: fromIndexPath, toIndexPath: toIndexPath)
observer.listMonitor(
monitor,
didMoveObject: object,
fromIndexPath: fromIndexPath,
toIndexPath: toIndexPath,
sourceIdentifier: monitor.fetchedResultsController.managedObjectContext.saveMetadata?.sourceIdentifier
)
}
)
self.registerObserver(
observer,
didInsertSection: { (observer, monitor, sectionInfo, toIndex) in
observer.listMonitor(monitor, didInsertSection: sectionInfo, toSectionIndex: toIndex)
observer.listMonitor(
monitor,
didInsertSection: sectionInfo,
toSectionIndex: toIndex,
sourceIdentifier: monitor.fetchedResultsController.managedObjectContext.saveMetadata?.sourceIdentifier
)
},
didDeleteSection: { (observer, monitor, sectionInfo, fromIndex) in
observer.listMonitor(monitor, didDeleteSection: sectionInfo, fromSectionIndex: fromIndex)
observer.listMonitor(
monitor,
didDeleteSection: sectionInfo,
fromSectionIndex: fromIndex,
sourceIdentifier: monitor.fetchedResultsController.managedObjectContext.saveMetadata?.sourceIdentifier
)
}
)
}
@@ -555,11 +643,18 @@ public final class ListMonitor<O: DynamicObject>: Hashable {
`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.
- parameter sourceIdentifier: an optional value that identifies the source of this transaction. This identifier will be passed to the change notifications and callers can use it for custom handling that depends on the source.
- 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...,
sourceIdentifier: Any?
) {
self.refetch(fetchClauses)
self.refetch(
fetchClauses,
sourceIdentifier: sourceIdentifier
)
}
/**
@@ -568,14 +663,21 @@ public final class ListMonitor<O: DynamicObject>: Hashable {
`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.
- parameter sourceIdentifier: an optional value that identifies the source of this transaction. This identifier will be passed to the change notifications and callers can use it for custom handling that depends on the source.
- 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],
sourceIdentifier: Any?
) {
self.refetch { (fetchRequest) in
fetchClauses.forEach { $0.applyToFetchRequest(fetchRequest) }
}
self.refetch(
{ (fetchRequest) in
fetchClauses.forEach { $0.applyToFetchRequest(fetchRequest) }
},
sourceIdentifier: sourceIdentifier
)
}
@@ -1023,7 +1125,10 @@ public final class ListMonitor<O: DynamicObject>: Hashable {
Internals.setAssociatedRetainedObject(nilValue, forKey: &self.didDeleteSectionKey, inObject: observer)
}
internal func refetch(_ applyFetchClauses: @escaping (_ fetchRequest: Internals.CoreStoreFetchRequest<NSManagedObject>) -> Void) {
internal func refetch(
_ applyFetchClauses: @escaping (_ fetchRequest: Internals.CoreStoreFetchRequest<NSManagedObject>) -> Void,
sourceIdentifier: Any?
) {
Internals.assert(
Thread.isMainThread,
@@ -1088,10 +1193,15 @@ public final class ListMonitor<O: DynamicObject>: Hashable {
self.isPendingRefetch = false
newFetchedResultsController.managedObjectContext.saveMetadata = .init(
isSavingSynchronously: false,
sourceIdentifier: sourceIdentifier
)
NotificationCenter.default.post(
name: Notification.Name.listMonitorDidRefetchList,
object: self
)
newFetchedResultsController.managedObjectContext.saveMetadata = nil
}
}
}
@@ -1152,7 +1262,15 @@ public final class ListMonitor<O: DynamicObject>: Hashable {
}
}
private static func recreateFetchedResultsController(context: NSManagedObjectContext, from: From<O>, sectionBy: SectionBy<O>?, applyFetchClauses: @escaping (_ fetchRequest: Internals.CoreStoreFetchRequest<NSManagedObject>) -> Void) -> (controller: Internals.CoreStoreFetchedResultsController, delegate: Internals.FetchedResultsControllerDelegate) {
private static func recreateFetchedResultsController(
context: NSManagedObjectContext,
from: From<O>,
sectionBy: SectionBy<O>?,
applyFetchClauses: @escaping (_ fetchRequest: Internals.CoreStoreFetchRequest<NSManagedObject>) -> Void
) -> (
controller: Internals.CoreStoreFetchedResultsController,
delegate: Internals.FetchedResultsControllerDelegate
) {
let fetchRequest = Internals.CoreStoreFetchRequest<NSManagedObject>()
fetchRequest.fetchLimit = 0
@@ -1232,7 +1350,7 @@ public final class ListMonitor<O: DynamicObject>: Hashable {
return
}
self.refetch(self.applyFetchClauses)
self.refetch(self.applyFetchClauses, sourceIdentifier: nil)
}
)
@@ -1256,7 +1374,7 @@ public final class ListMonitor<O: DynamicObject>: Hashable {
if previousStores != currentStores {
self.refetch(self.applyFetchClauses)
self.refetch(self.applyFetchClauses, sourceIdentifier: nil)
}
}

View File

@@ -181,8 +181,12 @@ public final class ListPublisher<O: DynamicObject>: Hashable {
)
```
- parameter clauseChain: a `FetchChainableBuilderType` built from a chain of clauses
- parameter sourceIdentifier: an optional value that identifies the source of this transaction. This identifier will be passed to the change notifications and callers can use it for custom handling that depends on the source.
*/
public func refetch<B: FetchChainableBuilderType>(_ clauseChain: B) throws where B.ObjectType == O {
public func refetch<B: FetchChainableBuilderType>(
_ clauseChain: B,
sourceIdentifier: Any? = nil
) throws where B.ObjectType == O {
try self.refetch(
from: clauseChain.from,
@@ -190,7 +194,8 @@ public final class ListPublisher<O: DynamicObject>: Hashable {
applyFetchClauses: { (fetchRequest) in
clauseChain.fetchClauses.forEach { $0.applyToFetchRequest(fetchRequest) }
}
},
sourceIdentifier: sourceIdentifier
)
}
@@ -205,8 +210,12 @@ public final class ListPublisher<O: DynamicObject>: Hashable {
)
```
- parameter clauseChain: a `SectionMonitorBuilderType` built from a chain of clauses
- parameter sourceIdentifier: an optional value that identifies the source of this transaction. This identifier will be passed to the change notifications and callers can use it for custom handling that depends on the source.
*/
public func refetch<B: SectionMonitorBuilderType>(_ clauseChain: B) throws where B.ObjectType == O {
public func refetch<B: SectionMonitorBuilderType>(
_ clauseChain: B,
sourceIdentifier: Any? = nil
) throws where B.ObjectType == O {
try self.refetch(
from: clauseChain.from,
@@ -214,7 +223,8 @@ public final class ListPublisher<O: DynamicObject>: Hashable {
applyFetchClauses: { (fetchRequest) in
clauseChain.fetchClauses.forEach { $0.applyToFetchRequest(fetchRequest) }
}
},
sourceIdentifier: sourceIdentifier
)
}
@@ -262,7 +272,12 @@ public final class ListPublisher<O: DynamicObject>: Hashable {
internal private(set) lazy var context: NSManagedObjectContext = self.fetchedResultsController.managedObjectContext
internal convenience init(dataStack: DataStack, from: From<ObjectType>, sectionBy: SectionBy<ObjectType>?, applyFetchClauses: @escaping (_ fetchRequest: Internals.CoreStoreFetchRequest<NSManagedObject>) -> Void) {
internal convenience init(
dataStack: DataStack,
from: From<ObjectType>,
sectionBy: SectionBy<ObjectType>?,
applyFetchClauses: @escaping (_ fetchRequest: Internals.CoreStoreFetchRequest<NSManagedObject>) -> Void
) {
self.init(
context: dataStack.mainContext,
@@ -273,7 +288,13 @@ public final class ListPublisher<O: DynamicObject>: Hashable {
)
}
internal convenience init(dataStack: DataStack, from: From<ObjectType>, sectionBy: SectionBy<ObjectType>?, applyFetchClauses: @escaping (_ fetchRequest: Internals.CoreStoreFetchRequest<NSManagedObject>) -> Void, createAsynchronously: @escaping (ListPublisher<ObjectType>) -> Void) {
internal convenience init(
dataStack: DataStack,
from: From<ObjectType>,
sectionBy: SectionBy<ObjectType>?,
applyFetchClauses: @escaping (_ fetchRequest: Internals.CoreStoreFetchRequest<NSManagedObject>) -> Void,
createAsynchronously: @escaping (ListPublisher<ObjectType>) -> Void
) {
self.init(
context: dataStack.mainContext,
@@ -284,7 +305,12 @@ public final class ListPublisher<O: DynamicObject>: Hashable {
)
}
internal convenience init(unsafeTransaction: UnsafeDataTransaction, from: From<ObjectType>, sectionBy: SectionBy<ObjectType>?, applyFetchClauses: @escaping (_ fetchRequest: Internals.CoreStoreFetchRequest<NSManagedObject>) -> Void) {
internal convenience init(
unsafeTransaction: UnsafeDataTransaction,
from: From<ObjectType>,
sectionBy: SectionBy<ObjectType>?,
applyFetchClauses: @escaping (_ fetchRequest: Internals.CoreStoreFetchRequest<NSManagedObject>) -> Void
) {
self.init(
context: unsafeTransaction.context,
@@ -295,7 +321,13 @@ public final class ListPublisher<O: DynamicObject>: Hashable {
)
}
internal convenience init(unsafeTransaction: UnsafeDataTransaction, from: From<ObjectType>, sectionBy: SectionBy<ObjectType>?, applyFetchClauses: @escaping (_ fetchRequest: Internals.CoreStoreFetchRequest<NSManagedObject>) -> Void, createAsynchronously: @escaping (ListPublisher<ObjectType>) -> Void) {
internal convenience init(
unsafeTransaction: UnsafeDataTransaction,
from: From<ObjectType>,
sectionBy: SectionBy<ObjectType>?,
applyFetchClauses: @escaping (_ fetchRequest: Internals.CoreStoreFetchRequest<NSManagedObject>) -> Void,
createAsynchronously: @escaping (ListPublisher<ObjectType>) -> Void
) {
self.init(
context: unsafeTransaction.context,
@@ -306,7 +338,12 @@ public final class ListPublisher<O: DynamicObject>: Hashable {
)
}
internal func refetch(from: From<O>, sectionBy: SectionBy<O>?, applyFetchClauses: @escaping (_ fetchRequest: Internals.CoreStoreFetchRequest<NSManagedObject>) -> Void) throws {
internal func refetch(
from: From<O>,
sectionBy: SectionBy<O>?,
applyFetchClauses: @escaping (_ fetchRequest: Internals.CoreStoreFetchRequest<NSManagedObject>) -> Void,
sourceIdentifier: Any?
) throws {
let (newFetchedResultsController, newFetchedResultsControllerDelegate) = Self.recreateFetchedResultsController(
context: self.fetchedResultsController.managedObjectContext,
@@ -323,7 +360,13 @@ public final class ListPublisher<O: DynamicObject>: Hashable {
(self.fetchedResultsController, self.fetchedResultsControllerDelegate) = (newFetchedResultsController, newFetchedResultsControllerDelegate)
newFetchedResultsControllerDelegate.handler = self
newFetchedResultsController.managedObjectContext.saveMetadata = .init(
isSavingSynchronously: true,
sourceIdentifier: sourceIdentifier
)
try newFetchedResultsController.performFetchFromSpecifiedStores()
newFetchedResultsController.managedObjectContext.saveMetadata = nil
}
deinit {
@@ -363,7 +406,15 @@ public final class ListPublisher<O: DynamicObject>: Hashable {
private lazy var observers: NSMapTable<AnyObject, ObserverClosureType> = .weakToStrongObjects()
private static func recreateFetchedResultsController(context: NSManagedObjectContext, from: From<ObjectType>, sectionBy: SectionBy<ObjectType>?, applyFetchClauses: @escaping (_ fetchRequest: Internals.CoreStoreFetchRequest<NSManagedObject>) -> Void) -> (controller: Internals.CoreStoreFetchedResultsController, delegate: Internals.FetchedDiffableDataSourceSnapshotDelegate) {
private static func recreateFetchedResultsController(
context: NSManagedObjectContext,
from: From<ObjectType>,
sectionBy: SectionBy<ObjectType>?,
applyFetchClauses: @escaping (_ fetchRequest: Internals.CoreStoreFetchRequest<NSManagedObject>) -> Void
) -> (
controller: Internals.CoreStoreFetchedResultsController,
delegate: Internals.FetchedDiffableDataSourceSnapshotDelegate
) {
let fetchRequest = Internals.CoreStoreFetchRequest<NSManagedObject>()
fetchRequest.fetchLimit = 0
@@ -385,7 +436,13 @@ public final class ListPublisher<O: DynamicObject>: Hashable {
return (fetchedResultsController, fetchedResultsControllerDelegate)
}
private init(context: NSManagedObjectContext, from: From<ObjectType>, sectionBy: SectionBy<ObjectType>?, applyFetchClauses: @escaping (_ fetchRequest: Internals.CoreStoreFetchRequest<NSManagedObject>) -> Void, createAsynchronously: ((ListPublisher<ObjectType>) -> Void)?) {
private init(
context: NSManagedObjectContext,
from: From<ObjectType>,
sectionBy: SectionBy<ObjectType>?,
applyFetchClauses: @escaping (_ fetchRequest: Internals.CoreStoreFetchRequest<NSManagedObject>) -> Void,
createAsynchronously: ((ListPublisher<ObjectType>) -> Void)?
) {
self.query = (
from: from,