mirror of
https://github.com/JohnEstropia/CoreStore.git
synced 2026-01-17 22:46:51 +01:00
improved caching in utility methods
This commit is contained in:
@@ -51,6 +51,6 @@
|
||||
<key>UIViewControllerBasedStatusBarAppearance</key>
|
||||
<false/>
|
||||
<key>UIUserInterfaceStyle</key>
|
||||
<string>light</string>
|
||||
<string>Light</string>
|
||||
</dict>
|
||||
</plist>
|
||||
|
||||
@@ -39,7 +39,7 @@ struct SwiftUIView: View {
|
||||
var body: some View {
|
||||
NavigationView {
|
||||
List {
|
||||
ForEach(palettes.sections, id: \.self) { (sectionID) in
|
||||
ForEach(palettes.sectionIdentifiers, id: \.self) { (sectionID) in
|
||||
Section(header: Text(sectionID)) {
|
||||
ForEach(self.palettes[section: sectionID], id: \.self) { palette in
|
||||
NavigationLink(
|
||||
@@ -118,7 +118,6 @@ struct SwiftUIView: View {
|
||||
self.needsShowAlert = true
|
||||
}
|
||||
}
|
||||
.colorScheme(.dark)
|
||||
}
|
||||
|
||||
@State
|
||||
|
||||
@@ -31,4 +31,32 @@ import CoreData
|
||||
|
||||
internal protocol DiffableDataSourceSnapshotProtocol {
|
||||
|
||||
init()
|
||||
|
||||
var numberOfItems: Int { get }
|
||||
var numberOfSections: Int { get }
|
||||
var sectionIdentifiers: [String] { get }
|
||||
var itemIdentifiers: [NSManagedObjectID] { get }
|
||||
|
||||
func numberOfItems(inSection identifier: String) -> Int
|
||||
func itemIdentifiers(inSection identifier: String) -> [NSManagedObjectID]
|
||||
func sectionIdentifier(containingItem identifier: NSManagedObjectID) -> String?
|
||||
func indexOfItem(_ identifier: NSManagedObjectID) -> Int?
|
||||
func indexOfSection(_ identifier: String) -> Int?
|
||||
|
||||
mutating func appendItems(_ identifiers: [NSManagedObjectID], toSection sectionIdentifier: String?)
|
||||
mutating func insertItems(_ identifiers: [NSManagedObjectID], beforeItem beforeIdentifier: NSManagedObjectID)
|
||||
mutating func insertItems(_ identifiers: [NSManagedObjectID], afterItem afterIdentifier: NSManagedObjectID)
|
||||
mutating func deleteItems(_ identifiers: [NSManagedObjectID])
|
||||
mutating func deleteAllItems()
|
||||
mutating func moveItem(_ identifier: NSManagedObjectID, beforeItem toIdentifier: NSManagedObjectID)
|
||||
mutating func moveItem(_ identifier: NSManagedObjectID, afterItem toIdentifier: NSManagedObjectID)
|
||||
mutating func reloadItems(_ identifiers: [NSManagedObjectID])
|
||||
mutating func appendSections(_ identifiers: [String])
|
||||
mutating func insertSections(_ identifiers: [String], beforeSection toIdentifier: String)
|
||||
mutating func insertSections(_ identifiers: [String], afterSection toIdentifier: String)
|
||||
mutating func deleteSections(_ identifiers: [String])
|
||||
mutating func moveSection(_ identifier: String, beforeSection toIdentifier: String)
|
||||
mutating func moveSection(_ identifier: String, afterSection toIdentifier: String)
|
||||
mutating func reloadSections(_ identifiers: [String])
|
||||
}
|
||||
|
||||
@@ -40,24 +40,26 @@ import AppKit
|
||||
|
||||
extension Internals {
|
||||
|
||||
|
||||
// MARK: - DiffableDataSourceSnapshot
|
||||
|
||||
// Implementation based on https://github.com/ra1028/DiffableDataSources
|
||||
internal struct DiffableDataSourceSnapshot {
|
||||
internal struct DiffableDataSourceSnapshot: DiffableDataSourceSnapshotProtocol {
|
||||
|
||||
// MARK: Internal
|
||||
|
||||
init() {
|
||||
|
||||
self.structure = .init()
|
||||
}
|
||||
|
||||
init(sections: [NSFetchedResultsSectionInfo]) {
|
||||
|
||||
self.structure = .init(sections: sections)
|
||||
}
|
||||
|
||||
|
||||
// MARK: DiffableDataSourceSnapshotProtocol
|
||||
|
||||
init() {
|
||||
|
||||
self.structure = .init()
|
||||
}
|
||||
|
||||
var numberOfItems: Int {
|
||||
|
||||
return self.structure.allItemIDs.count
|
||||
@@ -68,37 +70,37 @@ extension Internals {
|
||||
return self.structure.allSectionIDs.count
|
||||
}
|
||||
|
||||
var allSectionIDs: [String] {
|
||||
var sectionIdentifiers: [String] {
|
||||
|
||||
return self.structure.allSectionIDs
|
||||
}
|
||||
|
||||
var allItemIDs: [NSManagedObjectID] {
|
||||
var itemIdentifiers: [NSManagedObjectID] {
|
||||
|
||||
return self.structure.allItemIDs
|
||||
}
|
||||
|
||||
func numberOfItems(inSection identifier: String) -> Int {
|
||||
|
||||
return self.itemIDs(inSection: identifier).count
|
||||
return self.itemIdentifiers(inSection: identifier).count
|
||||
}
|
||||
|
||||
func itemIDs(inSection identifier: String) -> [NSManagedObjectID] {
|
||||
func itemIdentifiers(inSection identifier: String) -> [NSManagedObjectID] {
|
||||
|
||||
return self.structure.items(in: identifier)
|
||||
}
|
||||
|
||||
func sectionIDs(containingItem identifier: NSManagedObjectID) -> String? {
|
||||
func sectionIdentifier(containingItem identifier: NSManagedObjectID) -> String? {
|
||||
|
||||
return self.structure.section(containing: identifier)
|
||||
}
|
||||
|
||||
func indexOfItemID(_ identifier: NSManagedObjectID) -> Int? {
|
||||
func indexOfItem(_ identifier: NSManagedObjectID) -> Int? {
|
||||
|
||||
return self.structure.allItemIDs.firstIndex(of: identifier)
|
||||
}
|
||||
|
||||
func indexOfSectionID(_ identifier: String) -> Int? {
|
||||
func indexOfSection(_ identifier: String) -> Int? {
|
||||
|
||||
return self.structure.allSectionIDs.firstIndex(of: identifier)
|
||||
}
|
||||
@@ -138,9 +140,9 @@ extension Internals {
|
||||
self.structure.move(itemID: identifier, after: toIdentifier)
|
||||
}
|
||||
|
||||
mutating func reloadItems<S: Sequence>(_ identifiers: S, nextStateTag: UUID) where S.Element == NSManagedObjectID {
|
||||
mutating func reloadItems(_ identifiers: [NSManagedObjectID]) {
|
||||
|
||||
self.structure.update(itemIDs: identifiers, nextStateTag: nextStateTag)
|
||||
self.structure.update(itemIDs: identifiers)
|
||||
}
|
||||
|
||||
mutating func appendSections(_ identifiers: [String]) {
|
||||
@@ -173,9 +175,9 @@ extension Internals {
|
||||
self.structure.move(sectionID: identifier, after: toIdentifier)
|
||||
}
|
||||
|
||||
mutating func reloadSections<S: Sequence>(_ identifiers: S, nextStateTag: UUID) where S.Element == String {
|
||||
mutating func reloadSections(_ identifiers: [String]) {
|
||||
|
||||
self.structure.update(sectionIDs: identifiers, nextStateTag: nextStateTag)
|
||||
self.structure.update(sectionIDs: identifiers)
|
||||
}
|
||||
|
||||
|
||||
@@ -388,7 +390,7 @@ extension Internals {
|
||||
.insert(removed, at: itemIndex)
|
||||
}
|
||||
|
||||
mutating func update<S: Sequence>(itemIDs: S, nextStateTag: UUID) where S.Element == NSManagedObjectID {
|
||||
mutating func update<S: Sequence>(itemIDs: S) where S.Element == NSManagedObjectID {
|
||||
|
||||
let itemPositionMap = self.itemPositionMap()
|
||||
for itemID in itemIDs {
|
||||
@@ -464,7 +466,7 @@ extension Internals {
|
||||
self.sections.insert(removed, at: sectionIndex)
|
||||
}
|
||||
|
||||
mutating func update<S: Sequence>(sectionIDs: S, nextStateTag: UUID) where S.Element == String {
|
||||
mutating func update<S: Sequence>(sectionIDs: S) where S.Element == String {
|
||||
|
||||
for sectionID in sectionIDs {
|
||||
|
||||
@@ -590,4 +592,76 @@ extension Internals {
|
||||
}
|
||||
|
||||
|
||||
// MARK: - NSDiffableDataSourceSnapshot: DiffableDataSourceSnapshotProtocol
|
||||
|
||||
@available(iOS 13.0, tvOS 13.0, watchOS 6.0, macOS 15.0, *)
|
||||
extension NSDiffableDataSourceSnapshot: DiffableDataSourceSnapshotProtocol where SectionIdentifierType == NSString, ItemIdentifierType == NSManagedObjectID {
|
||||
|
||||
internal var sectionIdentifiers: [String] {
|
||||
|
||||
return self.sectionIdentifiers as [NSString] as [String]
|
||||
}
|
||||
|
||||
internal func numberOfItems(inSection identifier: String) -> Int {
|
||||
|
||||
return self.numberOfItems(inSection: identifier as NSString)
|
||||
}
|
||||
|
||||
internal func itemIdentifiers(inSection identifier: String) -> [NSManagedObjectID] {
|
||||
|
||||
return self.itemIdentifiers(inSection: identifier as NSString)
|
||||
}
|
||||
|
||||
internal func sectionIdentifier(containingItem identifier: NSManagedObjectID) -> String? {
|
||||
|
||||
return self.sectionIdentifier(containingItem: identifier) as NSString? as String?
|
||||
}
|
||||
|
||||
internal func indexOfSection(_ identifier: String) -> Int? {
|
||||
|
||||
return self.indexOfSection(identifier as NSString)
|
||||
}
|
||||
|
||||
internal mutating func appendItems(_ identifiers: [NSManagedObjectID], toSection sectionIdentifier: String?) {
|
||||
|
||||
self.appendItems(identifiers, toSection: sectionIdentifier as NSString?)
|
||||
}
|
||||
|
||||
internal mutating func appendSections(_ identifiers: [String]) {
|
||||
|
||||
self.appendSections(identifiers as [NSString])
|
||||
}
|
||||
|
||||
internal mutating func insertSections(_ identifiers: [String], beforeSection toIdentifier: String) {
|
||||
|
||||
self.insertSections(identifiers as [NSString], beforeSection: toIdentifier as NSString)
|
||||
}
|
||||
|
||||
internal mutating func insertSections(_ identifiers: [String], afterSection toIdentifier: String) {
|
||||
|
||||
return self.insertSections(identifiers as [NSString], afterSection: toIdentifier as NSString)
|
||||
}
|
||||
|
||||
internal mutating func deleteSections(_ identifiers: [String]) {
|
||||
|
||||
self.deleteSections(identifiers as [NSString])
|
||||
}
|
||||
|
||||
internal mutating func moveSection(_ identifier: String, beforeSection toIdentifier: String) {
|
||||
|
||||
self.moveSection(identifier as NSString, beforeSection: toIdentifier as NSString)
|
||||
}
|
||||
|
||||
internal mutating func moveSection(_ identifier: String, afterSection toIdentifier: String) {
|
||||
|
||||
self.moveSection(identifier as NSString, afterSection: toIdentifier as NSString)
|
||||
}
|
||||
|
||||
internal mutating func reloadSections(_ identifiers: [String]) {
|
||||
|
||||
self.reloadSections(identifiers as [NSString])
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
#endif
|
||||
|
||||
@@ -41,7 +41,7 @@ import AppKit
|
||||
|
||||
internal protocol FetchedDiffableDataSourceSnapshotHandler: AnyObject {
|
||||
|
||||
func controller(_ controller: NSFetchedResultsController<NSFetchRequestResult>, didChangContentWith snapshot: Internals.DiffableDataSourceSnapshot)
|
||||
func controller(_ controller: NSFetchedResultsController<NSFetchRequestResult>, didChangeContentWith snapshot: DiffableDataSourceSnapshotProtocol)
|
||||
}
|
||||
|
||||
|
||||
@@ -75,14 +75,14 @@ extension Internals {
|
||||
|
||||
internal func initialFetch() {
|
||||
|
||||
// #if canImport(UIKit) || canImport(AppKit)
|
||||
//
|
||||
// if #available(iOS 13.0, tvOS 13.0, watchOS 6.0, macOS 10.15, *) {
|
||||
//
|
||||
// return
|
||||
// }
|
||||
//
|
||||
// #endif
|
||||
#if canImport(UIKit) || canImport(AppKit)
|
||||
|
||||
if #available(iOS 13.0, tvOS 13.0, watchOS 6.0, macOS 10.15, *) {
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
guard let fetchedResultsController = self.fetchedResultsController else {
|
||||
|
||||
@@ -94,26 +94,26 @@ extension Internals {
|
||||
|
||||
// MARK: NSFetchedResultsControllerDelegate
|
||||
|
||||
// #if canImport(UIKit) || canImport(AppKit)
|
||||
//
|
||||
// @available(iOS 13.0, tvOS 13.0, watchOS 6.0, macOS 10.15, *)
|
||||
// @objc
|
||||
// dynamic func controller(_ controller: NSFetchedResultsController<NSFetchRequestResult>, didChangeContentWith snapshot: NSDiffableDataSourceSnapshotReference) {
|
||||
//
|
||||
// self.handler?.controller(
|
||||
// controller,
|
||||
// didChangContentWith: snapshot as NSDiffableDataSourceSnapshot<NSString, NSManagedObjectID>
|
||||
// )
|
||||
// }
|
||||
//
|
||||
// #endif
|
||||
#if canImport(UIKit) || canImport(AppKit)
|
||||
|
||||
@available(iOS 13.0, tvOS 13.0, watchOS 6.0, macOS 10.15, *)
|
||||
@objc
|
||||
dynamic func controller(_ controller: NSFetchedResultsController<NSFetchRequestResult>, didChangeContentWith snapshot: NSDiffableDataSourceSnapshotReference) {
|
||||
|
||||
self.handler?.controller(
|
||||
controller,
|
||||
didChangeContentWith: snapshot as NSDiffableDataSourceSnapshot<NSString, NSManagedObjectID>
|
||||
)
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
@objc
|
||||
dynamic func controllerDidChangeContent(_ controller: NSFetchedResultsController<NSFetchRequestResult>) {
|
||||
|
||||
self.handler?.controller(
|
||||
controller,
|
||||
didChangContentWith: Internals.DiffableDataSourceSnapshot(
|
||||
didChangeContentWith: Internals.DiffableDataSourceSnapshot(
|
||||
sections: controller.sections ?? []
|
||||
)
|
||||
)
|
||||
|
||||
@@ -25,32 +25,83 @@
|
||||
|
||||
import Foundation
|
||||
|
||||
|
||||
// MARK: - Internal
|
||||
|
||||
extension Internals {
|
||||
|
||||
// MARK: - SharedNotificationObserver
|
||||
|
||||
internal final class SharedNotificationObserver {
|
||||
internal final class SharedNotificationObserver<T> {
|
||||
|
||||
// MARK: Internal
|
||||
|
||||
let observer: NSObjectProtocol
|
||||
|
||||
init(notificationName: Notification.Name, object: Any?, queue: OperationQueue? = nil, closure: @escaping (_ note: Notification) -> Void) {
|
||||
internal init(notificationName: Notification.Name, object: Any?, queue: OperationQueue? = nil, sharedValue: @escaping (_ note: Notification) -> T) {
|
||||
|
||||
self.observer = NotificationCenter.default.addObserver(
|
||||
forName: notificationName,
|
||||
object: object,
|
||||
queue: queue,
|
||||
using: closure
|
||||
using: { [weak self] (notification) in
|
||||
|
||||
guard let self = self else {
|
||||
|
||||
return
|
||||
}
|
||||
let value = sharedValue(notification)
|
||||
self.notifyObservers(value)
|
||||
}
|
||||
)
|
||||
}
|
||||
|
||||
deinit {
|
||||
|
||||
NotificationCenter.default.removeObserver(self.observer)
|
||||
self.observer.map(NotificationCenter.default.removeObserver(_:))
|
||||
}
|
||||
|
||||
internal func addObserver<U: AnyObject>(_ observer: U, closure: @escaping (T) -> Void) {
|
||||
|
||||
self.observers.setObject(Closure(closure), forKey: observer)
|
||||
}
|
||||
|
||||
|
||||
// MARK: Private
|
||||
|
||||
private var observer: NSObjectProtocol!
|
||||
private let observers: NSMapTable<AnyObject, Closure> = .weakToStrongObjects()
|
||||
|
||||
private func notifyObservers(_ sharedValue: T) {
|
||||
|
||||
guard let enumerator = self.observers.objectEnumerator() else {
|
||||
|
||||
return
|
||||
}
|
||||
for closure in enumerator {
|
||||
|
||||
(closure as! Closure).invoke(with: sharedValue)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// MARK: - Closure
|
||||
|
||||
fileprivate final class Closure {
|
||||
|
||||
// MARK: FilePrivate
|
||||
|
||||
fileprivate init(_ closure: @escaping (T) -> Void) {
|
||||
|
||||
self.closure = closure
|
||||
}
|
||||
|
||||
fileprivate func invoke(with argument: T) {
|
||||
|
||||
self.closure(argument)
|
||||
}
|
||||
|
||||
|
||||
// MARK: Private
|
||||
|
||||
private let closure: (T) -> Void
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -46,7 +46,7 @@ public struct ListSnapshot<O: DynamicObject>: SnapshotResult, RandomAccessCollec
|
||||
public subscript<S: Sequence>(indices indices: S) -> [LiveObject<O>] where S.Element == Index {
|
||||
|
||||
let context = self.context!
|
||||
let itemIDs = self.diffableSnapshot.allItemIDs
|
||||
let itemIDs = self.diffableSnapshot.itemIdentifiers
|
||||
return indices.map { position in
|
||||
|
||||
let itemID = itemIDs[position]
|
||||
@@ -57,7 +57,7 @@ public struct ListSnapshot<O: DynamicObject>: SnapshotResult, RandomAccessCollec
|
||||
public subscript(section sectionID: SectionID) -> [LiveObject<O>] {
|
||||
|
||||
let context = self.context!
|
||||
let itemIDs = self.diffableSnapshot.itemIDs(inSection: sectionID)
|
||||
let itemIDs = self.diffableSnapshot.itemIdentifiers(inSection: sectionID)
|
||||
return itemIDs.map {
|
||||
|
||||
return LiveObject<O>(id: $0, context: context)
|
||||
@@ -67,7 +67,7 @@ public struct ListSnapshot<O: DynamicObject>: SnapshotResult, RandomAccessCollec
|
||||
public subscript<S: Sequence>(section sectionID: SectionID, itemIndices itemIndices: S) -> [LiveObject<O>] where S.Element == Int {
|
||||
|
||||
let context = self.context!
|
||||
let itemIDs = self.diffableSnapshot.itemIDs(inSection: sectionID)
|
||||
let itemIDs = self.diffableSnapshot.itemIdentifiers(inSection: sectionID)
|
||||
return itemIndices.map { position in
|
||||
|
||||
let itemID = itemIDs[position]
|
||||
@@ -85,14 +85,14 @@ public struct ListSnapshot<O: DynamicObject>: SnapshotResult, RandomAccessCollec
|
||||
return self.diffableSnapshot.numberOfSections
|
||||
}
|
||||
|
||||
public var sectionIDs: [SectionID] {
|
||||
public var sectionIdentifiers: [SectionID] {
|
||||
|
||||
return self.diffableSnapshot.allSectionIDs
|
||||
return self.diffableSnapshot.sectionIdentifiers
|
||||
}
|
||||
|
||||
public var itemIdentifiers: [ItemID] {
|
||||
|
||||
return self.diffableSnapshot.allItemIDs
|
||||
return self.diffableSnapshot.itemIdentifiers
|
||||
}
|
||||
|
||||
public func numberOfItems(inSection identifier: SectionID) -> Int {
|
||||
@@ -102,28 +102,28 @@ public struct ListSnapshot<O: DynamicObject>: SnapshotResult, RandomAccessCollec
|
||||
|
||||
public func itemIdentifiers(inSection identifier: SectionID) -> [ItemID] {
|
||||
|
||||
return self.diffableSnapshot.itemIDs(inSection: identifier)
|
||||
return self.diffableSnapshot.itemIdentifiers(inSection: identifier)
|
||||
}
|
||||
|
||||
public func itemIdentifiers(inSection identifier: SectionID, atIndices indices: IndexSet) -> [ItemID] {
|
||||
|
||||
let itemIDs = self.diffableSnapshot.itemIDs(inSection: identifier)
|
||||
let itemIDs = self.diffableSnapshot.itemIdentifiers(inSection: identifier)
|
||||
return indices.map({ itemIDs[$0] })
|
||||
}
|
||||
|
||||
public func sectionIdentifier(containingItem identifier: ItemID) -> SectionID? {
|
||||
|
||||
return self.diffableSnapshot.sectionIDs(containingItem: identifier)
|
||||
return self.diffableSnapshot.sectionIdentifier(containingItem: identifier)
|
||||
}
|
||||
|
||||
public func indexOfItem(_ identifier: ItemID) -> Index? {
|
||||
|
||||
return self.diffableSnapshot.indexOfItemID(identifier)
|
||||
return self.diffableSnapshot.indexOfItem(identifier)
|
||||
}
|
||||
|
||||
public func indexOfSection(_ identifier: SectionID) -> Int? {
|
||||
|
||||
return self.diffableSnapshot.indexOfSectionID(identifier)
|
||||
return self.diffableSnapshot.indexOfSection(identifier)
|
||||
}
|
||||
|
||||
public mutating func appendItems(_ identifiers: [ItemID], toSection sectionIdentifier: SectionID? = nil) {
|
||||
@@ -163,7 +163,7 @@ public struct ListSnapshot<O: DynamicObject>: SnapshotResult, RandomAccessCollec
|
||||
|
||||
public mutating func reloadItems(_ identifiers: [ItemID]) {
|
||||
|
||||
self.diffableSnapshot.reloadItems(identifiers, nextStateTag: .init())
|
||||
self.diffableSnapshot.reloadItems(identifiers)
|
||||
}
|
||||
|
||||
public mutating func appendSections(_ identifiers: [SectionID]) {
|
||||
@@ -198,7 +198,7 @@ public struct ListSnapshot<O: DynamicObject>: SnapshotResult, RandomAccessCollec
|
||||
|
||||
public mutating func reloadSections(_ identifiers: [SectionID]) {
|
||||
|
||||
self.diffableSnapshot.reloadSections(identifiers, nextStateTag: .init())
|
||||
self.diffableSnapshot.reloadSections(identifiers)
|
||||
}
|
||||
|
||||
|
||||
@@ -211,18 +211,18 @@ public struct ListSnapshot<O: DynamicObject>: SnapshotResult, RandomAccessCollec
|
||||
|
||||
public var startIndex: Index {
|
||||
|
||||
return self.diffableSnapshot.allItemIDs.startIndex
|
||||
return self.diffableSnapshot.itemIdentifiers.startIndex
|
||||
}
|
||||
|
||||
public var endIndex: Index {
|
||||
|
||||
return self.diffableSnapshot.allItemIDs.endIndex
|
||||
return self.diffableSnapshot.itemIdentifiers.endIndex
|
||||
}
|
||||
|
||||
public subscript(position: Index) -> Element {
|
||||
|
||||
let context = self.context!
|
||||
let itemID = self.diffableSnapshot.allItemIDs[position]
|
||||
let itemID = self.diffableSnapshot.itemIdentifiers[position]
|
||||
return LiveObject<O>(id: itemID, context: context)
|
||||
}
|
||||
|
||||
@@ -254,11 +254,11 @@ public struct ListSnapshot<O: DynamicObject>: SnapshotResult, RandomAccessCollec
|
||||
|
||||
internal init() {
|
||||
|
||||
self.diffableSnapshot = .init()
|
||||
self.diffableSnapshot = Internals.DiffableDataSourceSnapshot()
|
||||
self.context = nil
|
||||
}
|
||||
|
||||
internal init(diffableSnapshot: Internals.DiffableDataSourceSnapshot, context: NSManagedObjectContext) {
|
||||
internal init(diffableSnapshot: DiffableDataSourceSnapshotProtocol, context: NSManagedObjectContext) {
|
||||
|
||||
self.diffableSnapshot = diffableSnapshot
|
||||
self.context = context
|
||||
@@ -270,5 +270,5 @@ public struct ListSnapshot<O: DynamicObject>: SnapshotResult, RandomAccessCollec
|
||||
private let id: UUID = .init()
|
||||
private let context: NSManagedObjectContext?
|
||||
|
||||
private var diffableSnapshot: Internals.DiffableDataSourceSnapshot
|
||||
private var diffableSnapshot: DiffableDataSourceSnapshotProtocol
|
||||
}
|
||||
|
||||
@@ -63,9 +63,9 @@ public final class LiveList<O: DynamicObject>: Hashable {
|
||||
return self.snapshot.numberOfSections
|
||||
}
|
||||
|
||||
public var sections: [SectionID] {
|
||||
public var sectionIdentifiers: [SectionID] {
|
||||
|
||||
return self.snapshot.sectionIDs
|
||||
return self.snapshot.sectionIdentifiers
|
||||
}
|
||||
|
||||
public subscript(section sectionID: SectionID) -> [LiveObject<O>] {
|
||||
@@ -302,7 +302,7 @@ extension LiveList: FetchedDiffableDataSourceSnapshotHandler {
|
||||
|
||||
// MARK: FetchedDiffableDataSourceSnapshotHandler
|
||||
|
||||
internal func controller(_ controller: NSFetchedResultsController<NSFetchRequestResult>, didChangContentWith snapshot: Internals.DiffableDataSourceSnapshot) {
|
||||
internal func controller(_ controller: NSFetchedResultsController<NSFetchRequestResult>, didChangeContentWith snapshot: DiffableDataSourceSnapshotProtocol) {
|
||||
|
||||
self.snapshot = .init(
|
||||
diffableSnapshot: snapshot,
|
||||
|
||||
@@ -114,36 +114,23 @@ public final class LiveObject<O: DynamicObject>: Identifiable, Hashable {
|
||||
|
||||
self.rawObjectWillChange = nil
|
||||
}
|
||||
self.observer = NotificationCenter.default.addObserver(
|
||||
forName: .NSManagedObjectContextObjectsDidChange,
|
||||
object: context,
|
||||
queue: .main,
|
||||
using: { [weak self] (notification) in
|
||||
|
||||
guard let self = self, let userInfo = notification.userInfo else {
|
||||
|
||||
return
|
||||
}
|
||||
let updatedObjects = (userInfo[NSUpdatedObjectsKey] as! NSSet? ?? [])
|
||||
let mergedObjects = (userInfo[NSRefreshedObjectsKey] as! NSSet? ?? [])
|
||||
guard mergedObjects.contains(where: { ($0 as! NSManagedObject).objectID == id })
|
||||
|| updatedObjects.contains(where: { ($0 as! NSManagedObject).objectID == id }) else {
|
||||
|
||||
return
|
||||
}
|
||||
self.$lazySnapshot.reset({ initializer(id, context) })
|
||||
self.willChange()
|
||||
}
|
||||
)
|
||||
|
||||
self.$lazySnapshot.initialize({ initializer(id, context) })
|
||||
|
||||
context.objectsDidChangeObserver(for: self).addObserver(self) { [weak self] (objectIDs) in
|
||||
|
||||
guard let self = self else {
|
||||
|
||||
return
|
||||
}
|
||||
self.$lazySnapshot.reset({ initializer(id, context) })
|
||||
self.willChange()
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// MARK: Private
|
||||
|
||||
private let context: NSManagedObjectContext
|
||||
private var observer: NSObjectProtocol?
|
||||
|
||||
@Internals.LazyNonmutating(uninitialized: ())
|
||||
private var lazySnapshot: ObjectSnapshot<O>
|
||||
|
||||
@@ -89,7 +89,10 @@ extension NSManagedObjectContext {
|
||||
@nonobjc
|
||||
internal func liveObject<D: DynamicObject>(id: NSManagedObjectID) -> LiveObject<D> {
|
||||
|
||||
let cache = self.liveObjectsCache(D.self)
|
||||
let cache: NSMapTable<NSManagedObjectID, LiveObject<D>> = self.userInfo(for: .liveObjectsCache(D.self)) {
|
||||
|
||||
return .strongToWeakObjects()
|
||||
}
|
||||
return Internals.with {
|
||||
|
||||
if let liveObject = cache.object(forKey: id) {
|
||||
@@ -103,27 +106,38 @@ extension NSManagedObjectContext {
|
||||
}
|
||||
|
||||
@nonobjc
|
||||
private func liveObjectsCache<D: DynamicObject>(_ objectType: D.Type) -> NSMapTable<NSManagedObjectID, LiveObject<D>> {
|
||||
internal func objectsDidChangeObserver<U: AnyObject>(for observer: U) -> Internals.SharedNotificationObserver<Set<NSManagedObjectID>> {
|
||||
|
||||
let key = Internals.typeName(objectType)
|
||||
if let cache = self.userInfo[key] {
|
||||
return self.userInfo(for: .objectsChangeObserver(U.self)) { [unowned self] in
|
||||
|
||||
return cache as! NSMapTable<NSManagedObjectID, LiveObject<D>>
|
||||
return .init(
|
||||
notificationName: .NSManagedObjectContextObjectsDidChange,
|
||||
object: self,
|
||||
queue: .main,
|
||||
sharedValue: { (notification) -> Set<NSManagedObjectID> in
|
||||
|
||||
guard let userInfo = notification.userInfo else {
|
||||
|
||||
return []
|
||||
}
|
||||
var updatedObjectIDs: Set<NSManagedObjectID> = []
|
||||
if let updatedObjects = userInfo[NSUpdatedObjectsKey] as? Set<NSManagedObjectID> {
|
||||
|
||||
updatedObjectIDs.formUnion(updatedObjects)
|
||||
}
|
||||
if let mergedObjects = userInfo[NSRefreshedObjectsKey] as? Set<NSManagedObjectID> {
|
||||
|
||||
updatedObjectIDs.formUnion(mergedObjects)
|
||||
}
|
||||
return updatedObjectIDs
|
||||
}
|
||||
)
|
||||
}
|
||||
let cache = NSMapTable<NSManagedObjectID, LiveObject<D>>.strongToWeakObjects()
|
||||
self.userInfo[key] = cache
|
||||
return cache
|
||||
}
|
||||
|
||||
|
||||
// MARK: Private
|
||||
|
||||
private struct PropertyKeys {
|
||||
|
||||
static var observerForWillSaveNotification: Void?
|
||||
static var shouldCascadeSavesToParent: Void?
|
||||
}
|
||||
|
||||
@nonobjc
|
||||
private var observerForWillSaveNotification: Internals.NotificationObserver? {
|
||||
|
||||
@@ -143,5 +157,47 @@ extension NSManagedObjectContext {
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
private func userInfo<T>(for key: UserInfoKeys, initialize: @escaping () -> T) -> T {
|
||||
|
||||
let keyString = key.keyString
|
||||
if let value = self.userInfo[keyString] {
|
||||
|
||||
return value as! T
|
||||
}
|
||||
let value = initialize()
|
||||
self.userInfo[keyString] = value
|
||||
return value
|
||||
}
|
||||
|
||||
|
||||
// MARK: - PropertyKeys
|
||||
|
||||
private struct PropertyKeys {
|
||||
|
||||
static var observerForWillSaveNotification: Void?
|
||||
static var shouldCascadeSavesToParent: Void?
|
||||
}
|
||||
|
||||
|
||||
// MARK: - UserInfoKeys
|
||||
|
||||
private enum UserInfoKeys {
|
||||
|
||||
case liveObjectsCache(DynamicObject.Type)
|
||||
case objectsChangeObserver(AnyObject.Type)
|
||||
|
||||
var keyString: String {
|
||||
|
||||
switch self {
|
||||
|
||||
case .liveObjectsCache(let objectType):
|
||||
return "CoreStore.liveObjectsCache(\(Internals.typeName(objectType)))"
|
||||
|
||||
case .objectsChangeObserver:
|
||||
return "CoreStore.objectsChangeObserver"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user