From a2673956180f45f34dc88f45226372cef48397c1 Mon Sep 17 00:00:00 2001 From: John Estropia Date: Sat, 19 Oct 2019 22:17:25 +0900 Subject: [PATCH] WIP: README --- README.md | 2 +- Sources/CSDataStack+Observing.swift | 2 +- Sources/CoreStore+Observing.swift | 2 +- Sources/DataStack+DataSources.swift | 149 +++++++++--------- Sources/DataStack+Observing.swift | 2 +- .../DiffableDataSource.CollectionView.swift | 92 +++++++++-- Sources/DiffableDataSource.TableView.swift | 101 +++++++++++- Sources/DiffableDataSource.swift | 3 + Sources/ListSnapshot.swift | 84 +++++++++- Sources/ObjectObserver.swift | 2 +- Sources/ObjectPublisher.swift | 3 - Sources/ObjectSnapshot.swift | 8 +- Sources/UnsafeDataTransaction+Observing.swift | 2 +- 13 files changed, 348 insertions(+), 104 deletions(-) diff --git a/README.md b/README.md index c355c14..e0b976d 100644 --- a/README.md +++ b/README.md @@ -1476,7 +1476,7 @@ class MyViewController: UIViewController, ObjectObserver { } } ``` -We then need to keep a `ObjectMonitor` instance and register our `ObjectObserver` as an observer: +We then need to keep an `ObjectMonitor` instance and register our `ObjectObserver` as an observer: ```swift let person: MyPersonEntity = // ... self.monitor = CoreStore.monitorObject(person) diff --git a/Sources/CSDataStack+Observing.swift b/Sources/CSDataStack+Observing.swift index f7f9c4a..7f97735 100644 --- a/Sources/CSDataStack+Observing.swift +++ b/Sources/CSDataStack+Observing.swift @@ -36,7 +36,7 @@ extension CSDataStack { Creates a `CSObjectMonitor` for the specified `NSManagedObject`. Multiple `ObjectObserver`s may then register themselves to be notified when changes are made to the `NSManagedObject`. - parameter object: the `NSManagedObject` to observe changes from - - returns: a `ObjectMonitor` that monitors changes to `object` + - returns: an `ObjectMonitor` that monitors changes to `object` */ @objc public func monitorObject(_ object: NSManagedObject) -> CSObjectMonitor { diff --git a/Sources/CoreStore+Observing.swift b/Sources/CoreStore+Observing.swift index 02bfa1e..a8aa4dd 100644 --- a/Sources/CoreStore+Observing.swift +++ b/Sources/CoreStore+Observing.swift @@ -37,7 +37,7 @@ extension CoreStore { Using the `defaultStack`, creates an `ObjectMonitor` for the specified `DynamicObject`. Multiple `ObjectObserver`s may then register themselves to be notified when changes are made to the `DynamicObject`. - parameter object: the `DynamicObject` to observe changes from - - returns: a `ObjectMonitor` that monitors changes to `object` + - returns: an `ObjectMonitor` that monitors changes to `object` */ public static func monitorObject(_ object: O) -> ObjectMonitor { diff --git a/Sources/DataStack+DataSources.swift b/Sources/DataStack+DataSources.swift index 1e899c1..1b1ad43 100644 --- a/Sources/DataStack+DataSources.swift +++ b/Sources/DataStack+DataSources.swift @@ -34,21 +34,35 @@ import CoreData extension DataStack { /** - Creates a `ObjectPublisher` for the specified `DynamicObject`. Multiple objects may then register themselves to be notified when changes are made to the `DynamicObject`. + Creates an `ObjectPublisher` for the specified `DynamicObject`. Multiple objects may then register themselves to be notified when changes are made to the `DynamicObject`. - parameter object: the `DynamicObject` to observe changes from - - returns: a `ObjectPublisher` that broadcasts changes to `object` + - returns: an `ObjectPublisher` that broadcasts changes to `object` */ public func objectPublisher(_ object: O) -> ObjectPublisher { return ObjectPublisher(objectID: object.cs_id(), context: self.unsafeContext()) } - + + /** + Creates a `ListPublisher` for the specified `From` and `FetchClause`s. Multiple objects may then register themselves to be notified when changes are made to the fetched results. + + - 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. + - returns: a `ListPublisher` that broadcasts changes to the fetched results + */ public func listPublisher(_ from: From, _ fetchClauses: FetchClause...) -> ListPublisher { return self.listPublisher(from, fetchClauses) } - + + /** + Creates a `ListPublisher` for the specified `From` and `FetchClause`s. Multiple objects may then register themselves to be notified when changes are made to the fetched results. + + - 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. + - returns: a `ListPublisher` that broadcasts changes to the fetched results + */ public func listPublisher(_ from: From, _ fetchClauses: [FetchClause]) -> ListPublisher { return ListPublisher( @@ -66,7 +80,25 @@ extension DataStack { } ) } - + + /** + Creates a `ListPublisher` that satisfy the specified `FetchChainableBuilderType` built from a chain of clauses. + ``` + let listPublisher = dataStack.listPublisher( + From() + .where(\.age > 18) + .orderBy(.ascending(\.age)) + ) + ``` + Multiple objects may then register themselves to be notified when changes are made to the fetched results. + ``` + listPublisher.addObserver(self) { (listPublisher) in + // handle changes + } + ``` + - parameter clauseChain: a `FetchChainableBuilderType` built from a chain of clauses + - returns: a `ListPublisher` that broadcasts changes to the fetched results + */ public func listPublisher(_ clauseChain: B) -> ListPublisher { return self.listPublisher( @@ -74,34 +106,15 @@ extension DataStack { clauseChain.fetchClauses ) } - - public func listPublisher(createAsynchronously: @escaping (ListPublisher) -> Void, _ from: From, _ fetchClauses: FetchClause...) { - - self.listPublisher( - createAsynchronously: createAsynchronously, - from, fetchClauses - ) - } - - public func listPublisher(createAsynchronously: @escaping (ListPublisher) -> Void, _ from: From, _ fetchClauses: [FetchClause]) { - - _ = ListPublisher( - dataStack: self, - from: from, - sectionBy: nil, - applyFetchClauses: { fetchRequest in - - fetchClauses.forEach { $0.applyToFetchRequest(fetchRequest) } - - Internals.assert( - fetchRequest.sortDescriptors?.isEmpty == false, - "An \(Internals.typeName(ListPublisher.self)) requires a sort information. Specify from a \(Internals.typeName(OrderBy.self)) clause or any custom \(Internals.typeName(FetchClause.self)) that provides a sort descriptor." - ) - }, - createAsynchronously: createAsynchronously - ) - } - + + /** + Creates a `ListPublisher` for a sectioned list that satisfy the fetch clauses. Multiple objects may then register themselves to be notified when changes are made to the fetched results. + + - 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. + - returns: a `ListPublisher` that broadcasts changes to the fetched results + */ public func listPublisher(_ from: From, _ sectionBy: SectionBy, _ fetchClauses: FetchClause...) -> ListPublisher { return self.listPublisher( @@ -110,7 +123,15 @@ extension DataStack { fetchClauses ) } - + + /** + Creates a `ListPublisher` for a sectioned list that satisfy the fetch clauses. Multiple objects may then register themselves to be notified when changes are made to the fetched results. + + - 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. + - returns: a `ListPublisher` that broadcasts changes to the fetched results + */ public func listPublisher(_ from: From, _ sectionBy: SectionBy, _ fetchClauses: [FetchClause]) -> ListPublisher { return ListPublisher( @@ -128,7 +149,26 @@ extension DataStack { } ) } - + + /** + Creates a `ListPublisher` for a sectioned list that satisfy the specified `FetchChainableBuilderType` built from a chain of clauses. + ``` + let listPublisher = dataStack.listPublisher( + From() + .sectionBy(\.age, { "\($0!) years old" }) + .where(\.age > 18) + .orderBy(.ascending(\.age)) + ) + ``` + Multiple objects may then register themselves to be notified when changes are made to the fetched results. + ``` + listPublisher.addObserver(self) { (listPublisher) in + // handle changes + } + ``` + - parameter clauseChain: a `SectionMonitorBuilderType` built from a chain of clauses + - returns: a `ListPublisher` that broadcasts changes to the fetched results + */ public func listPublisher(_ clauseChain: B) -> ListPublisher { return self.listPublisher( @@ -137,45 +177,6 @@ extension DataStack { clauseChain.fetchClauses ) } - - public func listPublisher(createAsynchronously: @escaping (ListPublisher) -> Void, _ from: From, _ sectionBy: SectionBy, _ fetchClauses: FetchClause...) { - - self.listPublisher( - createAsynchronously: createAsynchronously, - from, - sectionBy, - fetchClauses - ) - } - - public func listPublisher(createAsynchronously: @escaping (ListPublisher) -> Void, _ from: From, _ sectionBy: SectionBy, _ fetchClauses: [FetchClause]) { - - _ = ListPublisher( - dataStack: self, - from: from, - sectionBy: sectionBy, - applyFetchClauses: { fetchRequest in - - fetchClauses.forEach { $0.applyToFetchRequest(fetchRequest) } - - Internals.assert( - fetchRequest.sortDescriptors?.isEmpty == false, - "An \(Internals.typeName(ListPublisher.self)) requires a sort information. Specify from a \(Internals.typeName(OrderBy.self)) clause or any custom \(Internals.typeName(FetchClause.self)) that provides a sort descriptor." - ) - }, - createAsynchronously: createAsynchronously - ) - } - - public func listPublisher(createAsynchronously: @escaping (ListPublisher) -> Void, _ clauseChain: B) { - - self.listPublisher( - createAsynchronously: createAsynchronously, - clauseChain.from, - clauseChain.sectionBy, - clauseChain.fetchClauses - ) - } } #endif diff --git a/Sources/DataStack+Observing.swift b/Sources/DataStack+Observing.swift index f111ee0..78b4069 100644 --- a/Sources/DataStack+Observing.swift +++ b/Sources/DataStack+Observing.swift @@ -36,7 +36,7 @@ extension DataStack { Creates an `ObjectMonitor` for the specified `DynamicObject`. Multiple `ObjectObserver`s may then register themselves to be notified when changes are made to the `DynamicObject`. - parameter object: the `DynamicObject` to observe changes from - - returns: a `ObjectMonitor` that monitors changes to `object` + - returns: an `ObjectMonitor` that monitors changes to `object` */ public func monitorObject(_ object: O) -> ObjectMonitor { diff --git a/Sources/DiffableDataSource.CollectionView.swift b/Sources/DiffableDataSource.CollectionView.swift index 8b4fa93..34a0cb3 100644 --- a/Sources/DiffableDataSource.CollectionView.swift +++ b/Sources/DiffableDataSource.CollectionView.swift @@ -34,13 +34,59 @@ import CoreData extension DiffableDataSource { // MARK: - CollectionView - + + /** + The `DiffableDataSource.CollectionView` serves as a `UICollectionViewDataSource` that handles `ListPublisher` snapshots for a `UICollectionView`. Subclasses of `DiffableDataSource.CollectionView` may override some `UICollectionViewDataSource` methods as needed. + The `DiffableDataSource.CollectionView` instance needs to be held on (retained) for as long as the `UICollectionView`'s lifecycle. + ``` + self.dataSource = DiffableDataSource.CollectionView( + collectionView: self.collectionView, + dataStack: Shared.defaultStack, + cellProvider: { (collectionView, indexPath, person) in + let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "PersonCell") as! PersonCell + cell.setPerson(person) + return cell + } + ) + ``` + The dataSource can then apply changes from a `ListPublisher` as shown: + ``` + listPublisher.addObserver(self) { [weak self] (listPublisher) in + self?.dataSource?.apply( + listPublisher.snapshot, + animatingDifferences: true + ) + } + ``` + `DiffableDataSource.CollectionView` fully handles the reload animations. + */ open class CollectionView: NSObject, UICollectionViewDataSource { // MARK: Public - + + /** + The object type represented by this dataSource + */ public typealias ObjectType = O - + + /** + Initializes the `DiffableDataSource.CollectionView`. This instance needs to be held on (retained) for as long as the `UICollectionView`'s lifecycle. + ``` + self.dataSource = DiffableDataSource.CollectionView( + collectionView: self.collectionView, + dataStack: Shared.defaultStack, + cellProvider: { (collectionView, indexPath, person) in + let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "PersonCell") as! PersonCell + cell.setPerson(person) + return cell + } + ) + ``` + - parameter collectionView: the `UICollectionView` to set the `dataSource` of. This instance is not retained by the `DiffableDataSource.CollectionView`. + - parameter dataStack: the `DataStack` instance that the dataSource will fetch objects from + - parameter cellProvider: a closure that configures and returns the `UICollectionViewCell` for the object + - parameter supplementaryViewProvider: an optional closure for providing `UICollectionReusableView` supplementary views. If not set, defaults to returning `nil` + */ @nonobjc public init(collectionView: UICollectionView, dataStack: DataStack, cellProvider: @escaping (UICollectionView, IndexPath, O) -> UICollectionViewCell?, supplementaryViewProvider: @escaping (UICollectionView, String, IndexPath) -> UICollectionReusableView? = { _, _, _ in nil }) { @@ -76,7 +122,21 @@ extension DiffableDataSource { collectionView.dataSource = self } - + + /** + Reloads the `UICollectionView` using a `ListSnapshot`. This is typically from the `snapshot` property of a `ListPublisher`: + ``` + listPublisher.addObserver(self) { [weak self] (listPublisher) in + self?.dataSource?.apply( + listPublisher.snapshot, + animatingDifferences: true + ) + } + ``` + + - parameter snapshot: the `ListSnapshot` used to reload the `UITableView` with. This is typically from the `snapshot` property of a `ListPublisher`. + - parameter animatingDifferences: if `true`, animations will be applied as configured by the `defaultRowAnimation` value. Defaults to `true`. + */ public func apply(_ snapshot: ListSnapshot, animatingDifferences: Bool = true) { let diffableSnapshot = snapshot.diffableSnapshot @@ -104,8 +164,15 @@ extension DiffableDataSource { ) // } } - - public func itemIdentifier(for indexPath: IndexPath) -> O.ObjectID? { + + /** + Returns the object identifier for the item at the specified `IndexPath`, or `nil` if not found + + - parameter indexPath: the `IndexPath` to search for + - returns: the object identifier for the item at the specified `IndexPath`, or `nil` if not found + */ + @nonobjc + public func itemID(for indexPath: IndexPath) -> O.ObjectID? { // if #available(iOS 13.0, tvOS 13.0, watchOS 6.0, macOS 10.15, *) { // @@ -116,8 +183,15 @@ extension DiffableDataSource { return self.legacyDataSource.itemIdentifier(for: indexPath) // } } - - public func indexPath(for itemIdentifier: O.ObjectID) -> IndexPath? { + + /** + Returns the `IndexPath` for the item with the specified object identifier, or `nil` if not found + + - parameter itemID: the object identifier to search for + - returns: the `IndexPath` for the item with the specified object identifier, or `nil` if not found + */ + @nonobjc + public func indexPath(for itemID: O.ObjectID) -> IndexPath? { // if #available(iOS 13.0, tvOS 13.0, watchOS 6.0, macOS 10.15, *) { // @@ -125,7 +199,7 @@ extension DiffableDataSource { // } // else { - return self.legacyDataSource.indexPath(for: itemIdentifier) + return self.legacyDataSource.indexPath(for: itemID) // } } diff --git a/Sources/DiffableDataSource.TableView.swift b/Sources/DiffableDataSource.TableView.swift index eedc726..c100dc1 100644 --- a/Sources/DiffableDataSource.TableView.swift +++ b/Sources/DiffableDataSource.TableView.swift @@ -35,18 +35,66 @@ extension DiffableDataSource { // MARK: - TableView + /** + The `DiffableDataSource.TableView` serves as a `UITableViewDataSource` that handles `ListPublisher` snapshots for a `UITableView`. Subclasses of `DiffableDataSource.TableView` may override some `UITableViewDataSource` methods as needed. + The `DiffableDataSource.TableView` instance needs to be held on (retained) for as long as the `UITableView`'s lifecycle. + ``` + self.dataSource = DiffableDataSource.TableView( + tableView: self.tableView, + dataStack: Shared.defaultStack, + cellProvider: { (tableView, indexPath, person) in + let cell = tableView.dequeueReusableCell(withIdentifier: "PersonCell") as! PersonCell + cell.setPerson(person) + return cell + } + ) + ``` + The dataSource can then apply changes from a `ListPublisher` as shown: + ``` + listPublisher.addObserver(self) { [weak self] (listPublisher) in + self?.dataSource?.apply( + listPublisher.snapshot, + animatingDifferences: true + ) + } + ``` + `DiffableDataSource.TableView` fully handles the reload animations. To turn change the default animation, set the `defaultRowAnimation`. + */ open class TableView: NSObject, UITableViewDataSource { // MARK: Open + /** + The animation style for row changes + */ @nonobjc open var defaultRowAnimation: UITableView.RowAnimation = .automatic // MARK: Public + /** + The object type represented by this dataSource + */ public typealias ObjectType = O - + + /** + Initializes the `DiffableDataSource.TableView`. This instance needs to be held on (retained) for as long as the `UITableView`'s lifecycle. + ``` + self.dataSource = DiffableDataSource.TableView( + tableView: self.tableView, + dataStack: Shared.defaultStack, + cellProvider: { (tableView, indexPath, person) in + let cell = tableView.dequeueReusableCell(withIdentifier: "PersonCell") as! PersonCell + cell.setPerson(person) + return cell + } + ) + ``` + - parameter tableView: the `UITableView` to set the `dataSource` of. This instance is not retained by the `DiffableDataSource.TableView`. + - parameter dataStack: the `DataStack` instance that the dataSource will fetch objects from + - parameter cellProvider: a closure that configures and returns the `UITableViewCell` for the object + */ @nonobjc public init(tableView: UITableView, dataStack: DataStack, cellProvider: @escaping (UITableView, IndexPath, O) -> UITableViewCell?) { @@ -81,7 +129,23 @@ extension DiffableDataSource { tableView.dataSource = self } - + + /** + Reloads the `UITableView` using a `ListSnapshot`. This is typically from the `snapshot` property of a `ListPublisher`: + ``` + listPublisher.addObserver(self) { [weak self] (listPublisher) in + self?.dataSource?.apply( + listPublisher.snapshot, + animatingDifferences: true + ) + } + ``` + If the `defaultRowAnimation` is configured to, animations are also applied accordingly. + + - parameter snapshot: the `ListSnapshot` used to reload the `UITableView` with. This is typically from the `snapshot` property of a `ListPublisher`. + - parameter animatingDifferences: if `true`, animations will be applied as configured by the `defaultRowAnimation` value. Defaults to `true`. + */ + @nonobjc public func apply(_ snapshot: ListSnapshot, animatingDifferences: Bool = true) { let diffableSnapshot = snapshot.diffableSnapshot @@ -110,8 +174,15 @@ extension DiffableDataSource { ) // } } - - public func itemIdentifier(for indexPath: IndexPath) -> O.ObjectID? { + + /** + Returns the object identifier for the item at the specified `IndexPath`, or `nil` if not found + + - parameter indexPath: the `IndexPath` to search for + - returns: the object identifier for the item at the specified `IndexPath`, or `nil` if not found + */ + @nonobjc + public func itemID(for indexPath: IndexPath) -> O.ObjectID? { // if #available(iOS 13.0, tvOS 13.0, watchOS 6.0, macOS 10.15, *) { // @@ -122,8 +193,15 @@ extension DiffableDataSource { return self.legacyDataSource.itemIdentifier(for: indexPath) // } } - - public func indexPath(for itemIdentifier: O.ObjectID) -> IndexPath? { + + /** + Returns the `IndexPath` for the item with the specified object identifier, or `nil` if not found + + - parameter itemID: the object identifier to search for + - returns: the `IndexPath` for the item with the specified object identifier, or `nil` if not found + */ + @nonobjc + public func indexPath(for itemID: O.ObjectID) -> IndexPath? { // if #available(iOS 13.0, tvOS 13.0, watchOS 6.0, macOS 10.15, *) { // @@ -131,7 +209,7 @@ extension DiffableDataSource { // } // else { - return self.legacyDataSource.indexPath(for: itemIdentifier) + return self.legacyDataSource.indexPath(for: itemID) // } } @@ -232,11 +310,17 @@ extension DiffableDataSource { // MARK: Private - + + @nonobjc private weak var tableView: UITableView? + @nonobjc private let dataStack: DataStack + + @nonobjc private let cellProvider: (UITableView, IndexPath, O) -> UITableViewCell? + + @nonobjc private var rawDataSource: Any! // @available(iOS 13.0, tvOS 13.0, watchOS 6.0, macOS 10.15, *) @@ -245,6 +329,7 @@ extension DiffableDataSource { // return self.rawDataSource as! UITableViewDiffableDataSource // } + @nonobjc private var legacyDataSource: Internals.DiffableDataUIDispatcher { return self.rawDataSource as! Internals.DiffableDataUIDispatcher diff --git a/Sources/DiffableDataSource.swift b/Sources/DiffableDataSource.swift index f4bcc45..82c487b 100644 --- a/Sources/DiffableDataSource.swift +++ b/Sources/DiffableDataSource.swift @@ -26,4 +26,7 @@ // MARK: - DiffableDataSource +/** + Namespace for diffable data source types. See `DiffableDataSource.TableView` and `DiffableDataSource.CollectionView` for actual implementations + */ public enum DiffableDataSource {} diff --git a/Sources/ListSnapshot.swift b/Sources/ListSnapshot.swift index ffda6c9..2ec94b7 100644 --- a/Sources/ListSnapshot.swift +++ b/Sources/ListSnapshot.swift @@ -431,77 +431,159 @@ public struct ListSnapshot: RandomAccessCollection, Hashable { // MARK: Public (Mutators) + + /** + Appends extra items to the specified section + - parameter itemIDs: the object identifiers for the objects to append + - parameter sectionID: the section to append the items to + */ public mutating func appendItems(withIDs itemIDs: [ItemID], toSectionWithID sectionID: SectionID? = nil) { self.diffableSnapshot.appendItems(itemIDs, toSection: sectionID) } + + /** + Inserts extra items before a specified item + - parameter itemIDs: the object identifiers for the objects to insert + - parameter beforeItemID: an existing identifier to insert items before of. Specifying an invalid value will raise an exception. + */ public mutating func insertItems(withIDs itemIDs: [ItemID], beforeItemID: ItemID) { self.diffableSnapshot.insertItems(itemIDs, beforeItem: beforeItemID) } + + /** + Inserts extra items after a specified item + - parameter itemIDs: the object identifiers for the objects to insert + - parameter beforeItemID: an existing identifier to insert items after of. Specifying an invalid value will raise an exception. + */ public mutating func insertItems(withIDs itemIDs: [ItemID], afterItemID: ItemID) { self.diffableSnapshot.insertItems(itemIDs, afterItem: afterItemID) } + + /** + Deletes the specified items + - parameter itemIDs: the object identifiers for the objects to delete + */ public mutating func deleteItems(withIDs itemIDs: [ItemID]) { self.diffableSnapshot.deleteItems(itemIDs) } - + + /** + Deletes all items + */ public mutating func deleteAllItems() { self.diffableSnapshot.deleteAllItems() } + + /** + Moves an item before another specified item + - parameter itemID: an object identifier in the list to move. Specifying an invalid value will raise an exception. + - parameter beforeItemID: another identifier to move the item before of. Specifying an invalid value will raise an exception. + */ public mutating func moveItem(withID itemID: ItemID, beforeItemID: ItemID) { self.diffableSnapshot.moveItem(itemID, beforeItem: beforeItemID) } + + /** + Moves an item after another specified item + - parameter itemID: an object identifier in the list to move. Specifying an invalid value will raise an exception. + - parameter beforeItemID: another identifier to move the item after of. Specifying an invalid value will raise an exception. + */ public mutating func moveItem(withID itemID: ItemID, afterItemID: ItemID) { self.diffableSnapshot.moveItem(itemID, afterItem: afterItemID) } + + /** + Marks the specified items as reloaded + - parameter itemIDs: the object identifiers to reload + */ public mutating func reloadItems(withIDs itemIDs: [ItemID]) { self.diffableSnapshot.reloadItems(itemIDs) } + + /** + Appends new section identifiers to the end of the list + - parameter sectionIDs: the sections to append + */ public mutating func appendSections(withIDs sectionIDs: [SectionID]) { self.diffableSnapshot.appendSections(sectionIDs) } + + /** + Inserts new sections before an existing section + - parameter sectionIDs: the section identifiers for the sections to insert + - parameter beforeSectionID: an existing identifier to insert items before of. Specifying an invalid value will raise an exception. + */ public mutating func insertSections(withIDs sectionIDs: [SectionID], beforeSectionID: SectionID) { self.diffableSnapshot.insertSections(sectionIDs, beforeSection: beforeSectionID) } + + /** + Inserts new sections after an existing section + - parameter sectionIDs: the section identifiers for the sections to insert + - parameter beforeSectionID: an existing identifier to insert items after of. Specifying an invalid value will raise an exception. + */ public mutating func insertSections(withIDs sectionIDs: [SectionID], afterSectionID: SectionID) { self.diffableSnapshot.insertSections(sectionIDs, afterSection: afterSectionID) } + + /** + Deletes the specified sections + - parameter sectionIDs: the section identifiers for the sections to delete + */ public mutating func deleteSections(withIDs sectionIDs: [SectionID]) { self.diffableSnapshot.deleteSections(sectionIDs) } + + /** + Moves a section before another specified section + - parameter sectionID: a section identifier in the list to move. Specifying an invalid value will raise an exception. + - parameter beforeSectionID: another identifier to move the section before of. Specifying an invalid value will raise an exception. + */ public mutating func moveSection(withID sectionID: SectionID, beforeSectionID: SectionID) { self.diffableSnapshot.moveSection(sectionID, beforeSection: beforeSectionID) } + + /** + Moves a section after another specified section + - parameter sectionID: a section identifier in the list to move. Specifying an invalid value will raise an exception. + - parameter afterSectionID: another identifier to move the section after of. Specifying an invalid value will raise an exception. + */ public mutating func moveSection(withID sectionID: SectionID, afterSectionID: SectionID) { self.diffableSnapshot.moveSection(sectionID, afterSection: afterSectionID) } + + /** + Marks the specified sections as reloaded + - parameter sectionIDs: the section identifiers to reload + */ public mutating func reloadSections(withIDs sectionIDs: [SectionID]) { self.diffableSnapshot.reloadSections(sectionIDs) diff --git a/Sources/ObjectObserver.swift b/Sources/ObjectObserver.swift index b9508f3..e5dc377 100644 --- a/Sources/ObjectObserver.swift +++ b/Sources/ObjectObserver.swift @@ -30,7 +30,7 @@ import CoreData // MARK: - ObjectObserver /** - Implement the `ObjectObserver` protocol to observe changes to a single `DynamicObject` instance. `ObjectObserver`s may register themselves to a `ObjectMonitor`'s `addObserver(_:)` method: + Implement the `ObjectObserver` protocol to observe changes to a single `DynamicObject` instance. `ObjectObserver`s may register themselves to an `ObjectMonitor`'s `addObserver(_:)` method: ``` let monitor = CoreStore.monitorObject(object) monitor.addObserver(self) diff --git a/Sources/ObjectPublisher.swift b/Sources/ObjectPublisher.swift index c1a6a0d..7bc262c 100644 --- a/Sources/ObjectPublisher.swift +++ b/Sources/ObjectPublisher.swift @@ -116,9 +116,6 @@ public final class ObjectPublisher: ObjectRepresentation, Hash // MARK: ObjectRepresentation - /** - The `DynamicObject` type associated with this list - */ public typealias ObjectType = O public func objectID() -> O.ObjectID { diff --git a/Sources/ObjectSnapshot.swift b/Sources/ObjectSnapshot.swift index b4b95cd..dc94e1c 100644 --- a/Sources/ObjectSnapshot.swift +++ b/Sources/ObjectSnapshot.swift @@ -36,13 +36,15 @@ import AppKit // MARK: - ObjectSnapshot +/** + The `ObjectSnapshot` is a full copy of a `DynamicObject`'s properties at a given point in time. This is useful especially when keeping thread-safe state values, in ViewModels for example. Since this is a value type, any changes in this `struct` does not affect the actual object. + */ @dynamicMemberLookup public struct ObjectSnapshot: ObjectRepresentation, Hashable { - - public typealias ObjectType = O - // MARK: ObjectRepresentation + + public typealias ObjectType = O public func objectID() -> O.ObjectID { diff --git a/Sources/UnsafeDataTransaction+Observing.swift b/Sources/UnsafeDataTransaction+Observing.swift index ad12bb8..72bd683 100644 --- a/Sources/UnsafeDataTransaction+Observing.swift +++ b/Sources/UnsafeDataTransaction+Observing.swift @@ -36,7 +36,7 @@ extension UnsafeDataTransaction { Creates an `ObjectMonitor` for the specified `DynamicObject`. Multiple `ObjectObserver`s may then register themselves to be notified when changes are made to the `DynamicObject`. - parameter object: the `DynamicObject` to observe changes from - - returns: a `ObjectMonitor` that monitors changes to `object` + - returns: an `ObjectMonitor` that monitors changes to `object` */ public func monitorObject(_ object: O) -> ObjectMonitor {