diff --git a/CoreStore.xcodeproj/project.pbxproj b/CoreStore.xcodeproj/project.pbxproj index a881a74..124a5b8 100644 --- a/CoreStore.xcodeproj/project.pbxproj +++ b/CoreStore.xcodeproj/project.pbxproj @@ -583,10 +583,10 @@ B5A992201EA898720091A2E3 /* UserInfo.swift in Sources */ = {isa = PBXBuildFile; fileRef = B5A9921E1EA898710091A2E3 /* UserInfo.swift */; }; B5A992211EA898720091A2E3 /* UserInfo.swift in Sources */ = {isa = PBXBuildFile; fileRef = B5A9921E1EA898710091A2E3 /* UserInfo.swift */; }; B5A992221EA898720091A2E3 /* UserInfo.swift in Sources */ = {isa = PBXBuildFile; fileRef = B5A9921E1EA898710091A2E3 /* UserInfo.swift */; }; - B5AA37F1235C28EE00FFD4B9 /* diffableDataSource.CollectionView-AppKit.swift in Sources */ = {isa = PBXBuildFile; fileRef = B5AA37F0235C28EE00FFD4B9 /* diffableDataSource.CollectionView-AppKit.swift */; }; - B5AA37F2235C28EE00FFD4B9 /* diffableDataSource.CollectionView-AppKit.swift in Sources */ = {isa = PBXBuildFile; fileRef = B5AA37F0235C28EE00FFD4B9 /* diffableDataSource.CollectionView-AppKit.swift */; }; - B5AA37F3235C28EE00FFD4B9 /* diffableDataSource.CollectionView-AppKit.swift in Sources */ = {isa = PBXBuildFile; fileRef = B5AA37F0235C28EE00FFD4B9 /* diffableDataSource.CollectionView-AppKit.swift */; }; - B5AA37F4235C28EE00FFD4B9 /* diffableDataSource.CollectionView-AppKit.swift in Sources */ = {isa = PBXBuildFile; fileRef = B5AA37F0235C28EE00FFD4B9 /* diffableDataSource.CollectionView-AppKit.swift */; }; + B5AA37F1235C28EE00FFD4B9 /* DiffableDataSource.CollectionView-AppKit.swift in Sources */ = {isa = PBXBuildFile; fileRef = B5AA37F0235C28EE00FFD4B9 /* DiffableDataSource.CollectionView-AppKit.swift */; }; + B5AA37F2235C28EE00FFD4B9 /* DiffableDataSource.CollectionView-AppKit.swift in Sources */ = {isa = PBXBuildFile; fileRef = B5AA37F0235C28EE00FFD4B9 /* DiffableDataSource.CollectionView-AppKit.swift */; }; + B5AA37F3235C28EE00FFD4B9 /* DiffableDataSource.CollectionView-AppKit.swift in Sources */ = {isa = PBXBuildFile; fileRef = B5AA37F0235C28EE00FFD4B9 /* DiffableDataSource.CollectionView-AppKit.swift */; }; + B5AA37F4235C28EE00FFD4B9 /* DiffableDataSource.CollectionView-AppKit.swift in Sources */ = {isa = PBXBuildFile; fileRef = B5AA37F0235C28EE00FFD4B9 /* DiffableDataSource.CollectionView-AppKit.swift */; }; B5AA37FD235C3D1A00FFD4B9 /* SwiftUI.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = B5AA37FC235C3D1A00FFD4B9 /* SwiftUI.framework */; settings = {ATTRIBUTES = (Weak, ); }; }; B5AEFAB51C9962AE00AD137F /* CoreStoreBridge.swift in Sources */ = {isa = PBXBuildFile; fileRef = B5AEFAB41C9962AE00AD137F /* CoreStoreBridge.swift */; }; B5AEFAB61C9962AE00AD137F /* CoreStoreBridge.swift in Sources */ = {isa = PBXBuildFile; fileRef = B5AEFAB41C9962AE00AD137F /* CoreStoreBridge.swift */; }; @@ -1014,7 +1014,7 @@ B5A80DF52212C1BC006096AA /* Playground_iOS.playground */ = {isa = PBXFileReference; lastKnownFileType = file.playground; path = Playground_iOS.playground; sourceTree = ""; xcLanguageSpecificationIdentifier = xcode.lang.swift; }; B5A991EB1E9DC2CE0091A2E3 /* VersionLock.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = VersionLock.swift; sourceTree = ""; }; B5A9921E1EA898710091A2E3 /* UserInfo.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = UserInfo.swift; sourceTree = ""; }; - B5AA37F0235C28EE00FFD4B9 /* diffableDataSource.CollectionView-AppKit.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "diffableDataSource.CollectionView-AppKit.swift"; sourceTree = ""; }; + B5AA37F0235C28EE00FFD4B9 /* DiffableDataSource.CollectionView-AppKit.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "DiffableDataSource.CollectionView-AppKit.swift"; sourceTree = ""; }; B5AA37FA235C3D1300FFD4B9 /* UIKit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = UIKit.framework; path = Platforms/WatchOS.platform/Developer/SDKs/WatchOS6.0.sdk/System/Library/Frameworks/UIKit.framework; sourceTree = DEVELOPER_DIR; }; B5AA37FC235C3D1A00FFD4B9 /* SwiftUI.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = SwiftUI.framework; path = Platforms/WatchOS.platform/Developer/SDKs/WatchOS6.0.sdk/System/Library/Frameworks/SwiftUI.framework; sourceTree = DEVELOPER_DIR; }; B5AD60CD1C90141E00F2B2E8 /* Package.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Package.swift; sourceTree = SOURCE_ROOT; }; @@ -1609,7 +1609,7 @@ B5BF7FB1234C97910070E741 /* DiffableDataSource.swift */, B5BF7FB6234C97CE0070E741 /* DiffableDataSource.TableView-UIKit.swift */, B5635D132356C39500B80E6B /* DiffableDataSource.CollectionView-UIKit.swift */, - B5AA37F0235C28EE00FFD4B9 /* diffableDataSource.CollectionView-AppKit.swift */, + B5AA37F0235C28EE00FFD4B9 /* DiffableDataSource.CollectionView-AppKit.swift */, ); name = DataSources; sourceTree = ""; @@ -2121,7 +2121,7 @@ B5A261211B64BFDB006EB6D3 /* MigrationType.swift in Sources */, B53FBA0B1CAB5E6500F0D40A /* CSCoreStore+Migrating.swift in Sources */, B5E84F141AFF847B0064E85B /* DataStack+Querying.swift in Sources */, - B5AA37F1235C28EE00FFD4B9 /* diffableDataSource.CollectionView-AppKit.swift in Sources */, + B5AA37F1235C28EE00FFD4B9 /* DiffableDataSource.CollectionView-AppKit.swift in Sources */, B5D7A5B61CA3BF8F005C752B /* CSInto.swift in Sources */, B56007141B3F6C2800A9A8F9 /* SectionBy.swift in Sources */, B5DE522B230BD7CC00A22534 /* Internals.swift in Sources */, @@ -2474,7 +2474,7 @@ B52F743E1E9B8724005F3DAC /* DynamicSchema.swift in Sources */, 18166884232B9ED00097C275 /* KeyPath+KeyPaths.swift in Sources */, B5E8A72121C1015300EF006A /* CoreStoreObject+Observing.swift in Sources */, - B5AA37F2235C28EE00FFD4B9 /* diffableDataSource.CollectionView-AppKit.swift in Sources */, + B5AA37F2235C28EE00FFD4B9 /* DiffableDataSource.CollectionView-AppKit.swift in Sources */, B50E175D2351848E004F033C /* Internals.DiffableDataUIDispatcher.DiffResult.swift in Sources */, B5474D162227C08700B21FEC /* Internals.CoreStoreFetchRequest.swift in Sources */, B501322B2346A9AE00FC238B /* ListPublisher.swift in Sources */, @@ -2698,7 +2698,7 @@ B52F74401E9B8724005F3DAC /* DynamicSchema.swift in Sources */, 18166886232B9ED20097C275 /* KeyPath+KeyPaths.swift in Sources */, B5E8A72321C1015300EF006A /* CoreStoreObject+Observing.swift in Sources */, - B5AA37F4235C28EE00FFD4B9 /* diffableDataSource.CollectionView-AppKit.swift in Sources */, + B5AA37F4235C28EE00FFD4B9 /* DiffableDataSource.CollectionView-AppKit.swift in Sources */, B50E175F2351848E004F033C /* Internals.DiffableDataUIDispatcher.DiffResult.swift in Sources */, B5474D182227C08700B21FEC /* Internals.CoreStoreFetchRequest.swift in Sources */, B501322E2346A9B100FC238B /* ListPublisher.swift in Sources */, @@ -2922,7 +2922,7 @@ B52F743F1E9B8724005F3DAC /* DynamicSchema.swift in Sources */, 18166885232B9ED10097C275 /* KeyPath+KeyPaths.swift in Sources */, B5E8A72221C1015300EF006A /* CoreStoreObject+Observing.swift in Sources */, - B5AA37F3235C28EE00FFD4B9 /* diffableDataSource.CollectionView-AppKit.swift in Sources */, + B5AA37F3235C28EE00FFD4B9 /* DiffableDataSource.CollectionView-AppKit.swift in Sources */, B50E175E2351848E004F033C /* Internals.DiffableDataUIDispatcher.DiffResult.swift in Sources */, B5474D172227C08700B21FEC /* Internals.CoreStoreFetchRequest.swift in Sources */, B501322D2346A9B000FC238B /* ListPublisher.swift in Sources */, diff --git a/Sources/diffableDataSource.CollectionView-AppKit.swift b/Sources/DiffableDataSource.CollectionView-AppKit.swift similarity index 100% rename from Sources/diffableDataSource.CollectionView-AppKit.swift rename to Sources/DiffableDataSource.CollectionView-AppKit.swift diff --git a/Sources/Internals.DiffableDataSourceSnapshot.swift b/Sources/Internals.DiffableDataSourceSnapshot.swift index 2aca088..cfa7f05 100644 --- a/Sources/Internals.DiffableDataSourceSnapshot.swift +++ b/Sources/Internals.DiffableDataSourceSnapshot.swift @@ -96,6 +96,11 @@ extension Internals { return self.structure.allItemIDs } + var updatedItemIdentifiers: Set { + + return self.structure.reloadedItems + } + func numberOfItems(inSection identifier: String) -> Int { return self.itemIdentifiers(inSection: identifier).count @@ -121,16 +126,6 @@ extension Internals { return self.structure.allSectionIDs.firstIndex(of: identifier) } - func isReloaded(sectionID: String) -> Bool? { - - return self.structure.isReloaded(sectionID: sectionID) - } - - func isReloaded(itemID: NSManagedObjectID) -> Bool? { - - return self.structure.isReloaded(itemID: itemID) - } - mutating func appendItems(_ identifiers: [NSManagedObjectID], toSection sectionIdentifier: String?) { self.structure.append(itemIDs: identifiers, to: sectionIdentifier) @@ -282,10 +277,12 @@ extension Internals { // MARK: Internal var sections: [Section] + private(set) var reloadedItems: Set init() { self.sections = [] + self.reloadedItems = [] } init(sections: [NSFetchedResultsSectionInfo], fetchOffset: Int, fetchLimit: Int?) { @@ -327,6 +324,7 @@ extension Internals { ) } self.sections = newSections + self.reloadedItems = [] } var allSectionIDs: [String] { @@ -339,24 +337,6 @@ extension Internals { return self.sections.lazy.flatMap({ $0.elements }).map({ $0.differenceIdentifier }) } - func isReloaded(sectionID: String) -> Bool? { - - return self.sections.first(where: { $0.differenceIdentifier == sectionID })?.isReloaded - } - - func isReloaded(itemID: NSManagedObjectID) -> Bool? { - - for section in self.sections { - - guard let item = section.elements.first(where: { $0.differenceIdentifier == itemID }) else { - - return nil - } - return item.isReloaded - } - return nil - } - func items(in sectionID: String) -> [NSManagedObjectID] { guard let sectionIndex = self.sectionIndex(of: sectionID) else { @@ -488,6 +468,7 @@ extension Internals { mutating func update(itemIDs: S) where S.Element == NSManagedObjectID { let itemPositionMap = self.itemPositionMap() + var newItemIDs: Set = [] for itemID in itemIDs { guard let itemPosition = itemPositionMap[itemID] else { @@ -496,7 +477,9 @@ extension Internals { } self.sections[itemPosition.sectionIndex] .elements[itemPosition.itemRelativeIndex].isReloaded = true + newItemIDs.insert(itemID) } + self.reloadedItems.formUnion(newItemIDs) } mutating func append(sectionIDs: [String]) { diff --git a/Sources/ListSnapshot.swift b/Sources/ListSnapshot.swift index bd47761..1990072 100644 --- a/Sources/ListSnapshot.swift +++ b/Sources/ListSnapshot.swift @@ -215,25 +215,11 @@ public struct ListSnapshot: RandomAccessCollection, Hashable { } /** - Checks if the `ListSnapshot` has changes in the specified section. - - - parameter sectionID: the section identifier. Using an index outside the valid range will return `nil`. - - returns: `true` if the specified section has changes, `false` if no changes, or `nil` if the `sectionID` does not exist + Returns item identifiers for updated objects. This is mainly useful for Data Source adapters such as `UICollectionViewDiffableDataSource` or `UITableViewDiffableDataSource` which work on collection diffs when reloading. Since objects with same IDs resolve as "equal" in their old and new states, adapters may need extra heuristics to determine which row items need reloading. If your row items are all observing changes from each corresponding `ObjectPublisher`, or if you are using CoreStore's built-in `DiffableDataSource`s, there is no need to inspect this property. */ - public func hasChanges(sectionID: String) -> Bool? { + var updatedItemIdentifiers: Set { - return self.diffableSnapshot.isReloaded(sectionID: sectionID) - } - - /** - Checks if the `ListSnapshot` has changes for the specified item. - - - parameter itemID: the item identifier. Using an index outside the valid range will return `nil`. - - returns: `true` if the specified item has changes, `false` if no changes, or `nil` if the `itemID` does not exist - */ - public func hasChanges(itemID: NSManagedObjectID) -> Bool? { - - return self.diffableSnapshot.isReloaded(itemID: itemID) + return self.diffableSnapshot.updatedItemIdentifiers } /**