diff --git a/CoreStore.xcodeproj/project.pbxproj b/CoreStore.xcodeproj/project.pbxproj index 35598f5..553a2d2 100644 --- a/CoreStore.xcodeproj/project.pbxproj +++ b/CoreStore.xcodeproj/project.pbxproj @@ -465,6 +465,10 @@ B56321B31BD6521C006C9394 /* NSManagedObjectContext+Setup.swift in Sources */ = {isa = PBXBuildFile; fileRef = B5E84F321AFF85470064E85B /* NSManagedObjectContext+Setup.swift */; }; B56321B41BD6521C006C9394 /* NSManagedObjectContext+Transaction.swift in Sources */ = {isa = PBXBuildFile; fileRef = B5E84F331AFF85470064E85B /* NSManagedObjectContext+Transaction.swift */; }; B56321B61BD6521C006C9394 /* Internals.WeakObject.swift in Sources */ = {isa = PBXBuildFile; fileRef = B5E84F2D1AFF849C0064E85B /* Internals.WeakObject.swift */; }; + B5635D142356C39500B80E6B /* DiffableDataSource.CollectionView.swift in Sources */ = {isa = PBXBuildFile; fileRef = B5635D132356C39500B80E6B /* DiffableDataSource.CollectionView.swift */; }; + B5635D152356C39500B80E6B /* DiffableDataSource.CollectionView.swift in Sources */ = {isa = PBXBuildFile; fileRef = B5635D132356C39500B80E6B /* DiffableDataSource.CollectionView.swift */; }; + B5635D162356C39500B80E6B /* DiffableDataSource.CollectionView.swift in Sources */ = {isa = PBXBuildFile; fileRef = B5635D132356C39500B80E6B /* DiffableDataSource.CollectionView.swift */; }; + B5635D172356C39500B80E6B /* DiffableDataSource.CollectionView.swift in Sources */ = {isa = PBXBuildFile; fileRef = B5635D132356C39500B80E6B /* DiffableDataSource.CollectionView.swift */; }; B56507941D3930BC000596DA /* CoreData.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = B56507931D3930BC000596DA /* CoreData.framework */; }; B56507961D3930C1000596DA /* Foundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = B56507951D3930C1000596DA /* Foundation.framework */; }; B56507981D3930CC000596DA /* CoreData.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = B56507971D3930CC000596DA /* CoreData.framework */; }; @@ -977,6 +981,7 @@ B563216F1BD65082006C9394 /* CoreStore.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = CoreStore.framework; sourceTree = BUILT_PRODUCTS_DIR; }; B56321791BD650DE006C9394 /* CoreData.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = CoreData.framework; path = Platforms/WatchOS.platform/Developer/SDKs/WatchOS2.0.sdk/System/Library/Frameworks/CoreData.framework; sourceTree = DEVELOPER_DIR; }; B563217B1BD650E3006C9394 /* Foundation.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Foundation.framework; path = Platforms/WatchOS.platform/Developer/SDKs/WatchOS2.0.sdk/System/Library/Frameworks/Foundation.framework; sourceTree = DEVELOPER_DIR; }; + B5635D132356C39500B80E6B /* DiffableDataSource.CollectionView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DiffableDataSource.CollectionView.swift; sourceTree = ""; }; B56507931D3930BC000596DA /* CoreData.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = CoreData.framework; path = Platforms/AppleTVOS.platform/Developer/SDKs/AppleTVOS10.0.sdk/System/Library/Frameworks/CoreData.framework; sourceTree = DEVELOPER_DIR; }; B56507951D3930C1000596DA /* Foundation.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Foundation.framework; path = Platforms/AppleTVOS.platform/Developer/SDKs/AppleTVOS10.0.sdk/System/Library/Frameworks/Foundation.framework; sourceTree = DEVELOPER_DIR; }; B56507971D3930CC000596DA /* CoreData.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = CoreData.framework; path = Platforms/WatchOS.platform/Developer/SDKs/WatchOS3.0.sdk/System/Library/Frameworks/CoreData.framework; sourceTree = DEVELOPER_DIR; }; @@ -1609,6 +1614,7 @@ B5E294DC2349F8E7003E5956 /* SnapshotResult.swift */, B5BF7FB1234C97910070E741 /* DiffableDataSource.swift */, B5BF7FB6234C97CE0070E741 /* DiffableDataSource.TableView.swift */, + B5635D132356C39500B80E6B /* DiffableDataSource.CollectionView.swift */, ); name = DataSources; sourceTree = ""; @@ -2151,6 +2157,7 @@ B5F335582348D75D00FD649F /* LiveResult.swift in Sources */, B5E84F121AFF847B0064E85B /* OrderBy.swift in Sources */, B546F9581C99B17400D5AC55 /* CSCoreStore+Setup.swift in Sources */, + B5635D142356C39500B80E6B /* DiffableDataSource.CollectionView.swift in Sources */, B5E84F361AFF85470064E85B /* NSManagedObjectContext+Setup.swift in Sources */, B5FAD6AE1B518DCB00714891 /* CoreStore+Migration.swift in Sources */, B50E175223517C6B004F033C /* Internals.DiffableDataUIDispatcher.Changeset.swift in Sources */, @@ -2315,6 +2322,7 @@ files = ( 82BA18B61C4BBD3F00A0916E /* DataStack+Querying.swift in Sources */, B5ECDBFB1CA804FD00C7F112 /* NSManagedObjectContext+ObjectiveC.swift in Sources */, + B5635D152356C39500B80E6B /* DiffableDataSource.CollectionView.swift in Sources */, B5CA2B091F7E5ACA004B1936 /* WhereClauseType.swift in Sources */, B5C976E81C6E3A5D00B1AF90 /* Internals.CoreStoreFetchedResultsController.swift in Sources */, B56923F61EB828BF007C4DC9 /* CSDynamicSchema.swift in Sources */, @@ -2539,6 +2547,7 @@ files = ( B5220E1E1D13080D009BC71E /* CSListMonitor.swift in Sources */, B5DBE2D01C9914A900B5CEFA /* CSCoreStore.swift in Sources */, + B5635D172356C39500B80E6B /* DiffableDataSource.CollectionView.swift in Sources */, B5CA2B0B1F7E5ACA004B1936 /* WhereClauseType.swift in Sources */, B56923F81EB828BF007C4DC9 /* CSDynamicSchema.swift in Sources */, B52DD1BE1BE1F94300949AFE /* Progress+Convenience.swift in Sources */, @@ -2763,6 +2772,7 @@ files = ( B56321A91BD65219006C9394 /* Progress+Convenience.swift in Sources */, B5ECDBFC1CA804FD00C7F112 /* NSManagedObjectContext+ObjectiveC.swift in Sources */, + B5635D162356C39500B80E6B /* DiffableDataSource.CollectionView.swift in Sources */, B5CA2B0A1F7E5ACA004B1936 /* WhereClauseType.swift in Sources */, B5C976E91C6E3A5E00B1AF90 /* Internals.CoreStoreFetchedResultsController.swift in Sources */, B56923F71EB828BF007C4DC9 /* CSDynamicSchema.swift in Sources */, diff --git a/CoreStoreDemo/CoreStoreDemo/List and Object Observers Demo/ListObserverDemoViewController.swift b/CoreStoreDemo/CoreStoreDemo/List and Object Observers Demo/ListObserverDemoViewController.swift index 2a5e1b6..a2fc66b 100644 --- a/CoreStoreDemo/CoreStoreDemo/List and Object Observers Demo/ListObserverDemoViewController.swift +++ b/CoreStoreDemo/CoreStoreDemo/List and Object Observers Demo/ListObserverDemoViewController.swift @@ -183,7 +183,7 @@ class ListObserverDemoViewController: UITableViewController { ColorsDemo.stack.perform( asynchronous: { (transaction) in - transaction.delete(palette?.object) + transaction.delete(palette) }, completion: { _ in } ) diff --git a/CoreStoreDemo/CoreStoreDemo/List and Object Observers Demo/ObjectObserverDemoViewController.swift b/CoreStoreDemo/CoreStoreDemo/List and Object Observers Demo/ObjectObserverDemoViewController.swift index 6f0d74b..b3ee95f 100644 --- a/CoreStoreDemo/CoreStoreDemo/List and Object Observers Demo/ObjectObserverDemoViewController.swift +++ b/CoreStoreDemo/CoreStoreDemo/List and Object Observers Demo/ObjectObserverDemoViewController.swift @@ -16,13 +16,13 @@ class ObjectObserverDemoViewController: UIViewController, ObjectObserver { func setPalette(_ newValue: O?) where O.ObjectType == Palette { - guard self.monitor?.cs_id() != newValue?.cs_id() else { + guard self.monitor?.objectID() != newValue?.objectID() else { return } if let newValue = newValue { - self.monitor = ColorsDemo.stack.monitorObject(newValue) + self.monitor = newValue.asObjectMonitor(in: ColorsDemo.stack) } else { diff --git a/CoreStoreDemo/CoreStoreDemo/SwiftUI Demo/SwiftUIView.swift b/CoreStoreDemo/CoreStoreDemo/SwiftUI Demo/SwiftUIView.swift index ccad57d..e18bc3b 100644 --- a/CoreStoreDemo/CoreStoreDemo/SwiftUI Demo/SwiftUIView.swift +++ b/CoreStoreDemo/CoreStoreDemo/SwiftUI Demo/SwiftUIView.swift @@ -48,7 +48,7 @@ struct SwiftUIView: View { ) } .onDelete { itemIndices in - let objectsToDelete = self.palettes[section: sectionID, itemIndices: itemIndices].map({ $0.object }) + let objectsToDelete = self.palettes[section: sectionID, itemIndices: itemIndices] self.dataStack.perform( asynchronous: { transaction in diff --git a/Sources/BaseDataTransaction.swift b/Sources/BaseDataTransaction.swift index 9353b8c..2d44fe4 100644 --- a/Sources/BaseDataTransaction.swift +++ b/Sources/BaseDataTransaction.swift @@ -183,8 +183,8 @@ public /*abstract*/ class BaseDataTransaction { ) let context = self.context objects.forEach { - - $0.cs_rawObject(in: context).map({ context.delete($0) }) + + $0.asEditable(in: self).map({ context.delete($0.cs_toRaw()) }) } } diff --git a/Sources/CoreStore+Observing.swift b/Sources/CoreStore+Observing.swift index 79f9188..8de1b06 100644 --- a/Sources/CoreStore+Observing.swift +++ b/Sources/CoreStore+Observing.swift @@ -39,7 +39,7 @@ extension CoreStore { - parameter object: the `ObjectRepresentation` to observe changes from - returns: a `ObjectMonitor` that monitors changes to `object` */ - public static func monitorObject(_ object: O) -> ObjectMonitor { + public static func monitorObject(_ object: O) -> ObjectMonitor { return Shared.defaultStack.monitorObject(object) } diff --git a/Sources/DataStack+Observing.swift b/Sources/DataStack+Observing.swift index 852b135..3eb7e70 100644 --- a/Sources/DataStack+Observing.swift +++ b/Sources/DataStack+Observing.swift @@ -38,13 +38,13 @@ extension DataStack { - parameter object: the `ObjectRepresentation` to observe changes from - returns: a `ObjectMonitor` that monitors changes to `object` */ - public func monitorObject(_ object: O) -> ObjectMonitor { + public func monitorObject(_ object: O) -> ObjectMonitor { Internals.assert( Thread.isMainThread, "Attempted to observe objects from \(Internals.typeName(self)) outside the main thread." ) - return ObjectMonitor(dataStack: self, object: object) + return .init(objectID: object.cs_id(), context: self.unsafeContext()) } /** diff --git a/Sources/DiffableDataSource.CollectionView.swift b/Sources/DiffableDataSource.CollectionView.swift new file mode 100644 index 0000000..3d89081 --- /dev/null +++ b/Sources/DiffableDataSource.CollectionView.swift @@ -0,0 +1,291 @@ +// +// DiffableDataSource.CollectionView.swift +// CoreStore +// +// Copyright © 2018 John Rommel Estropia +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in all +// copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +// SOFTWARE. +// + +#if canImport(UIKit) + +import UIKit +import CoreData + + +// MARK: - DiffableDataSource + +extension DiffableDataSource { + + // MARK: - CollectionView + + open class CollectionView: NSObject, UICollectionViewDataSource { + + // MARK: Public + + public typealias ObjectType = O + + @nonobjc + public init(collectionView: UICollectionView, dataStack: DataStack, cellProvider: @escaping (UICollectionView, IndexPath, ObjectType) -> UICollectionViewCell?, supplementaryViewProvider: @escaping (UICollectionView, String, IndexPath) -> UICollectionReusableView? = { _, _, _ in nil }) { + + self.collectionView = collectionView + self.cellProvider = cellProvider + self.supplementaryViewProvider = supplementaryViewProvider + self.dataStack = dataStack + + super.init() + +// if #available(iOS 13.0, tvOS 13.0, watchOS 6.0, macOS 10.15, *) { +// +// self.rawDataSource = UITableViewDiffableDataSource( +// tableView: tableView, +// cellProvider: { [weak self] (tableView, indexPath, objectID) -> UITableViewCell? in +// +// guard let self = self else { +// +// return nil +// } +// guard let object = self.dataStack.fetchExisting(objectID) as O? else { +// +// return nil +// } +// return self.cellProvider(tableView, indexPath, object) +// } +// ) +// } +// else { + + self.rawDataSource = Internals.DiffableDataUIDispatcher(dataStack: dataStack) +// } + + collectionView.dataSource = self + } + + public func apply(_ snapshot: ListSnapshot, animatingDifferences: Bool = true) { + + let diffableSnapshot = snapshot.diffableSnapshot +// if #available(iOS 13.0, tvOS 13.0, watchOS 6.0, macOS 10.15, *) { +// +// self.modernDataSource.apply( +// diffableSnapshot as! NSDiffableDataSourceSnapshot, +// animatingDifferences: animatingDifferences, +// completion: nil +// ) +// } +// else { + + self.legacyDataSource.apply( + diffableSnapshot as! Internals.DiffableDataSourceSnapshot, + view: self.collectionView, + animatingDifferences: animatingDifferences, + performUpdates: { collectionView, changeset, setSections in + + collectionView.reload( + using: changeset, + setData: setSections + ) + } + ) +// } + } + + public func itemIdentifier(for indexPath: IndexPath) -> O.ObjectID? { + +// if #available(iOS 13.0, tvOS 13.0, watchOS 6.0, macOS 10.15, *) { +// +// return self.modernDataSource.itemIdentifier(for: indexPath) +// } +// else { + + return self.legacyDataSource.itemIdentifier(for: indexPath) +// } + } + + public func indexPath(for itemIdentifier: O.ObjectID) -> IndexPath? { + +// if #available(iOS 13.0, tvOS 13.0, watchOS 6.0, macOS 10.15, *) { +// +// return self.modernDataSource.indexPath(for: itemIdentifier) +// } +// else { + + return self.legacyDataSource.indexPath(for: itemIdentifier) +// } + } + + + // MARK: - UICollectionViewDataSource + + @objc + public dynamic func numberOfSections(in collectionView: UICollectionView) -> Int { + +// if #available(iOS 13.0, tvOS 13.0, watchOS 6.0, macOS 10.15, *) { +// +// return self.modernDataSource.numberOfSections(in: tableView) +// } +// else { + + return self.legacyDataSource.numberOfSections() +// } + } + + @objc + public dynamic func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int { + +// if #available(iOS 13.0, tvOS 13.0, watchOS 6.0, macOS 10.15, *) { +// +// return self.modernDataSource.tableView(tableView, numberOfRowsInSection: section) +// } +// else { + + return self.legacyDataSource.numberOfItems(inSection: section) +// } + } + + @objc + open dynamic func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell { + +// if #available(iOS 13.0, tvOS 13.0, watchOS 6.0, macOS 10.15, *) { +// +// return self.modernDataSource.tableView(tableView, cellForRowAt: indexPath) +// } +// else { + + guard let objectID = self.legacyDataSource.itemIdentifier(for: indexPath) else { + + Internals.abort("Object at \(Internals.typeName(IndexPath.self)) \(indexPath) already removed from list") + } + guard let object = self.dataStack.fetchExisting(objectID) as O? else { + + Internals.abort("Object at \(Internals.typeName(IndexPath.self)) \(indexPath) has been deleted") + } + guard let cell = self.cellProvider(collectionView, indexPath, object) else { + + Internals.abort("\(Internals.typeName(UICollectionViewDataSource.self)) returned a `nil` cell for \(Internals.typeName(IndexPath.self)) \(indexPath)") + } + return cell +// } + } + + @objc + open dynamic func collectionView(_ collectionView: UICollectionView, viewForSupplementaryElementOfKind kind: String, at indexPath: IndexPath) -> UICollectionReusableView { + + guard let view = self.supplementaryViewProvider(collectionView, kind, indexPath) else { + + return UICollectionReusableView() + } + return view + } + + + // MARK: Private + + private weak var collectionView: UICollectionView? + + private let dataStack: DataStack + private let cellProvider: (UICollectionView, IndexPath, ObjectType) -> UICollectionViewCell? + private let supplementaryViewProvider: (UICollectionView, String, IndexPath) -> UICollectionReusableView? + private var rawDataSource: Any! + +// @available(iOS 13.0, tvOS 13.0, watchOS 6.0, macOS 10.15, *) +// private var modernDataSource: UITableViewDiffableDataSource { +// +// return self.rawDataSource as! UITableViewDiffableDataSource +// } + + private var legacyDataSource: Internals.DiffableDataUIDispatcher { + + return self.rawDataSource as! Internals.DiffableDataUIDispatcher + } + } +} + + +// MARK: - UICollectionView + +extension UICollectionView { + + // MARK: FilePrivate + + @nonobjc + fileprivate func reload( + using stagedChangeset: Internals.DiffableDataUIDispatcher.StagedChangeset, + interrupt: ((Internals.DiffableDataUIDispatcher.Changeset) -> Bool)? = nil, + setData: (C) -> Void + ) { + + if case .none = window, let data = stagedChangeset.last?.data { + + setData(data) + self.reloadData() + return + } + for changeset in stagedChangeset { + + if let interrupt = interrupt, interrupt(changeset), let data = stagedChangeset.last?.data { + + setData(data) + self.reloadData() + return + } + self.performBatchUpdates( + { + setData(changeset.data) + + if !changeset.sectionDeleted.isEmpty { + + self.deleteSections(IndexSet(changeset.sectionDeleted)) + } + if !changeset.sectionInserted.isEmpty { + + self.insertSections(IndexSet(changeset.sectionInserted)) + } + if !changeset.sectionUpdated.isEmpty { + + self.reloadSections(IndexSet(changeset.sectionUpdated)) + } + for (source, target) in changeset.sectionMoved { + + self.moveSection(source, toSection: target) + } + if !changeset.elementDeleted.isEmpty { + + self.deleteItems(at: changeset.elementDeleted.map { IndexPath(row: $0.element, section: $0.section) }) + } + if !changeset.elementInserted.isEmpty { + + self.insertItems(at: changeset.elementInserted.map { IndexPath(row: $0.element, section: $0.section) }) + } + if !changeset.elementUpdated.isEmpty { + + self.reloadItems(at: changeset.elementUpdated.map { IndexPath(row: $0.element, section: $0.section) }) + } + for (source, target) in changeset.elementMoved { + + self.moveItem(at: IndexPath(row: source.element, section: source.section), to: IndexPath(row: target.element, section: target.section)) + } + }, + completion: nil + ) + } + } +} + + +#endif diff --git a/Sources/LiveList.swift b/Sources/LiveList.swift index f1537b2..905b052 100644 --- a/Sources/LiveList.swift +++ b/Sources/LiveList.swift @@ -152,12 +152,12 @@ public final class LiveList: Hashable { public func section(containingItem item: LiveObject) -> SectionID? { - return self.snapshot.sectionIdentifier(containingItem: item.cs_id()) + return self.snapshot.sectionIdentifier(containingItem: item.objectID()) } public func indexOfItem(_ item: LiveObject) -> Int? { - return self.snapshot.indexOfItem(item.cs_id()) + return self.snapshot.indexOfItem(item.objectID()) } public func indexOfSection(_ identifier: SectionID) -> Int? { diff --git a/Sources/LiveObject.swift b/Sources/LiveObject.swift index 80d2cec..3ed1c10 100644 --- a/Sources/LiveObject.swift +++ b/Sources/LiveObject.swift @@ -101,7 +101,7 @@ public final class LiveObject: ObjectRepresentation, Hashable return self.lazySnapshot } - return .init(id: self.id, context: context) + return .init(objectID: self.id, context: context) } public func asSnapshot(in transaction: BaseDataTransaction) -> ObjectSnapshot? { @@ -111,7 +111,7 @@ public final class LiveObject: ObjectRepresentation, Hashable return self.lazySnapshot } - return .init(id: self.id, context: context) + return .init(objectID: self.id, context: context) } public func asObjectMonitor(in dataStack: DataStack) -> ObjectMonitor? { @@ -150,7 +150,7 @@ public final class LiveObject: ObjectRepresentation, Hashable self.init( objectID: objectID, context: context, - initializer: ObjectSnapshot.init(id:context:) + initializer: ObjectSnapshot.init(objectID:context:) ) } @@ -192,6 +192,11 @@ public final class LiveObject: ObjectRepresentation, Hashable } } + fileprivate var object: O { + + return self.context.fetchExisting(self.id)! + } + // MARK: Private diff --git a/Sources/ObjectMonitor.swift b/Sources/ObjectMonitor.swift index 0641123..8dc109f 100644 --- a/Sources/ObjectMonitor.swift +++ b/Sources/ObjectMonitor.swift @@ -40,7 +40,7 @@ import CoreData Observers registered via `addObserver(_:)` are not retained. `ObjectMonitor` only keeps a `weak` reference to all observers, thus keeping itself free from retain-cycles. */ @available(macOS 10.12, *) -public final class ObjectMonitor: ObjectRepresentation, Equatable { +public final class ObjectMonitor: ObjectRepresentation, Equatable { /** Returns the `DynamicObject` instance being observed, or `nil` if the object was already deleted. @@ -122,35 +122,35 @@ public final class ObjectMonitor: ObjectRepresentation, Equata // MARK: ObjectRepresentation - public func objectID() -> D.ObjectID { + public func objectID() -> O.ObjectID { return self.id } - public func asLiveObject(in dataStack: DataStack) -> LiveObject? { + public func asLiveObject(in dataStack: DataStack) -> LiveObject? { let context = dataStack.unsafeContext() return .init(objectID: self.id, context: context) } - public func asEditable(in transaction: BaseDataTransaction) -> D? { + public func asEditable(in transaction: BaseDataTransaction) -> O? { return self.context.fetchExisting(self.id) } - public func asSnapshot(in dataStack: DataStack) -> ObjectSnapshot? { + public func asSnapshot(in dataStack: DataStack) -> ObjectSnapshot? { let context = dataStack.unsafeContext() - return .init(id: self.id, context: context) + return .init(objectID: self.id, context: context) } - public func asSnapshot(in transaction: BaseDataTransaction) -> ObjectSnapshot? { + public func asSnapshot(in transaction: BaseDataTransaction) -> ObjectSnapshot? { let context = transaction.unsafeContext() - return .init(id: self.id, context: context) + return .init(objectID: self.id, context: context) } - public func asObjectMonitor(in dataStack: DataStack) -> ObjectMonitor? { + public func asObjectMonitor(in dataStack: DataStack) -> ObjectMonitor? { let context = dataStack.unsafeContext() if self.context == context { @@ -160,31 +160,6 @@ public final class ObjectMonitor: ObjectRepresentation, Equata return .init(objectID: self.id, context: dataStack.unsafeContext()) } - public typealias ObjectType = D - - public static func cs_fromRaw(object: NSManagedObject) -> Self { - - return self.init( - context: object.managedObjectContext!, - objectID: object.objectID - ) - } - - public func cs_id() -> ObjectType.ObjectID { - - return self.objectID - } - - public func cs_object() -> D? { - - return self.object - } - - public func cs_rawObject(in context: NSManagedObjectContext) -> NSManagedObject? { - - return context.fetchExisting(self.objectID) - } - // MARK: Equatable @@ -238,7 +213,7 @@ public final class ObjectMonitor: ObjectRepresentation, Equata let fetchedResultsControllerDelegate = Internals.FetchedResultsControllerDelegate() - self.objectID = objectID + self.id = objectID self.fetchedResultsController = fetchedResultsController self.fetchedResultsControllerDelegate = fetchedResultsControllerDelegate @@ -331,7 +306,7 @@ public final class ObjectMonitor: ObjectRepresentation, Equata // MARK: Private - private let objectID: ObjectType.ObjectID + private let id: O.ObjectID private let fetchedResultsController: Internals.CoreStoreFetchedResultsController private let fetchedResultsControllerDelegate: Internals.FetchedResultsControllerDelegate private var lastCommittedAttributes = [String: NSObject]() @@ -339,6 +314,11 @@ public final class ObjectMonitor: ObjectRepresentation, Equata private var willChangeObjectKey: Void? private var didDeleteObjectKey: Void? private var didUpdateObjectKey: Void? + + private var context: NSManagedObjectContext { + + return self.fetchedResultsController.managedObjectContext + } private func registerChangeNotification(_ notificationKey: UnsafeRawPointer, name: Notification.Name, toObserver observer: AnyObject, callback: @escaping (_ monitor: ObjectMonitor) -> Void) { diff --git a/Sources/ObjectRepresentation.swift b/Sources/ObjectRepresentation.swift index 0f118d4..f33899a 100644 --- a/Sources/ObjectRepresentation.swift +++ b/Sources/ObjectRepresentation.swift @@ -69,40 +69,50 @@ public protocol ObjectRepresentation { func asObjectMonitor(in dataStack: DataStack) -> ObjectMonitor? } -extension LiveObject { - - public static func cs_object(in context: NSManagedObjectContext) -> LiveObject? { - - return nil - } -} +extension NSManagedObject: ObjectRepresentation {} -extension ObjectMonitor { - - public static func cs_object(in context: NSManagedObjectContext) -> LiveObject? { - - return nil - } -} - -extension NSManagedObject: ObjectRepresentation { - - -} - -extension CoreStoreObject: ObjectRepresentation { - -} +extension CoreStoreObject: ObjectRepresentation {} extension DynamicObject where Self: ObjectRepresentation { - - public static func cs_object(in context: NSManagedObjectContext) -> LiveObject? { - - fatalError() + + // MARK: ObjectRepresentation + + public func objectID() -> Self.ObjectID { + + return self.cs_id() } - - public func cs_rawObject(in context: NSManagedObjectContext) -> NSManagedObject? { - + + public func asLiveObject(in dataStack: DataStack) -> LiveObject? { + + let context = dataStack.unsafeContext() + return .init(objectID: self.cs_id(), context: context) + } + + public func asEditable(in transaction: BaseDataTransaction) -> Self? { + + let context = transaction.unsafeContext() + if self.cs_toRaw().managedObjectContext == context { + + return self + } return context.fetchExisting(self.cs_id()) } + + public func asSnapshot(in dataStack: DataStack) -> ObjectSnapshot? { + + let context = dataStack.unsafeContext() + return .init(objectID: self.cs_id(), context: context) + } + + public func asSnapshot(in transaction: BaseDataTransaction) -> ObjectSnapshot? { + + let context = transaction.unsafeContext() + return .init(objectID: self.cs_id(), context: context) + } + + public func asObjectMonitor(in dataStack: DataStack) -> ObjectMonitor? { + + let context = dataStack.unsafeContext() + return .init(objectID: self.cs_id(), context: context) + } } diff --git a/Sources/ObjectSnapshot.swift b/Sources/ObjectSnapshot.swift index 765def5..279bb77 100644 --- a/Sources/ObjectSnapshot.swift +++ b/Sources/ObjectSnapshot.swift @@ -69,7 +69,7 @@ public struct ObjectSnapshot: SnapshotResult, ObjectRepresenta return self } - return .init(id: self.id, context: context) + return .init(objectID: self.id, context: context) } public func asSnapshot(in transaction: BaseDataTransaction) -> ObjectSnapshot? { @@ -79,7 +79,7 @@ public struct ObjectSnapshot: SnapshotResult, ObjectRepresenta return self } - return .init(id: self.id, context: context) + return .init(objectID: self.id, context: context) } public func asObjectMonitor(in dataStack: DataStack) -> ObjectMonitor? { @@ -108,9 +108,9 @@ public struct ObjectSnapshot: SnapshotResult, ObjectRepresenta // MARK: Internal - internal init(id: ID, context: NSManagedObjectContext) { + internal init(objectID: O.ObjectID, context: NSManagedObjectContext) { - self.id = id + self.id = objectID self.context = context self.values = O.cs_snapshotDictionary(id: id, context: context) as NSDictionary } diff --git a/Sources/UnsafeDataTransaction+Observing.swift b/Sources/UnsafeDataTransaction+Observing.swift index 7cedb7f..be8574d 100644 --- a/Sources/UnsafeDataTransaction+Observing.swift +++ b/Sources/UnsafeDataTransaction+Observing.swift @@ -38,12 +38,9 @@ extension UnsafeDataTransaction { - parameter object: the `ObjectRepresentation` to observe changes from - returns: a `ObjectMonitor` that monitors changes to `object` */ - public func monitorObject(_ object: O) -> ObjectMonitor { - - return ObjectMonitor( - unsafeTransaction: self, - object: object - ) + public func monitorObject(_ object: O) -> ObjectMonitor { + + return .init(objectID: object.cs_id(), context: self.unsafeContext()) } /**