This commit is contained in:
John Estropia
2019-10-08 21:09:34 +09:00
parent b073b7e795
commit d5114fc4bc
13 changed files with 1393 additions and 225 deletions

View File

@@ -536,6 +536,22 @@
B5AEFAB61C9962AE00AD137F /* CoreStoreBridge.swift in Sources */ = {isa = PBXBuildFile; fileRef = B5AEFAB41C9962AE00AD137F /* CoreStoreBridge.swift */; };
B5AEFAB71C9962AE00AD137F /* CoreStoreBridge.swift in Sources */ = {isa = PBXBuildFile; fileRef = B5AEFAB41C9962AE00AD137F /* CoreStoreBridge.swift */; };
B5AEFAB81C9962AE00AD137F /* CoreStoreBridge.swift in Sources */ = {isa = PBXBuildFile; fileRef = B5AEFAB41C9962AE00AD137F /* CoreStoreBridge.swift */; };
B5BF7FAD234C41E90070E741 /* Internals.DiffableDataSourceSnapshot.swift in Sources */ = {isa = PBXBuildFile; fileRef = B5BF7FAC234C41E90070E741 /* Internals.DiffableDataSourceSnapshot.swift */; };
B5BF7FAE234C41E90070E741 /* Internals.DiffableDataSourceSnapshot.swift in Sources */ = {isa = PBXBuildFile; fileRef = B5BF7FAC234C41E90070E741 /* Internals.DiffableDataSourceSnapshot.swift */; };
B5BF7FAF234C41E90070E741 /* Internals.DiffableDataSourceSnapshot.swift in Sources */ = {isa = PBXBuildFile; fileRef = B5BF7FAC234C41E90070E741 /* Internals.DiffableDataSourceSnapshot.swift */; };
B5BF7FB0234C41E90070E741 /* Internals.DiffableDataSourceSnapshot.swift in Sources */ = {isa = PBXBuildFile; fileRef = B5BF7FAC234C41E90070E741 /* Internals.DiffableDataSourceSnapshot.swift */; };
B5BF7FB2234C97910070E741 /* DiffableDataSource.swift in Sources */ = {isa = PBXBuildFile; fileRef = B5BF7FB1234C97910070E741 /* DiffableDataSource.swift */; };
B5BF7FB3234C97910070E741 /* DiffableDataSource.swift in Sources */ = {isa = PBXBuildFile; fileRef = B5BF7FB1234C97910070E741 /* DiffableDataSource.swift */; };
B5BF7FB4234C97910070E741 /* DiffableDataSource.swift in Sources */ = {isa = PBXBuildFile; fileRef = B5BF7FB1234C97910070E741 /* DiffableDataSource.swift */; };
B5BF7FB5234C97910070E741 /* DiffableDataSource.swift in Sources */ = {isa = PBXBuildFile; fileRef = B5BF7FB1234C97910070E741 /* DiffableDataSource.swift */; };
B5BF7FB7234C97CE0070E741 /* DiffableDataSource.TableView.swift in Sources */ = {isa = PBXBuildFile; fileRef = B5BF7FB6234C97CE0070E741 /* DiffableDataSource.TableView.swift */; };
B5BF7FB8234C97CE0070E741 /* DiffableDataSource.TableView.swift in Sources */ = {isa = PBXBuildFile; fileRef = B5BF7FB6234C97CE0070E741 /* DiffableDataSource.TableView.swift */; };
B5BF7FB9234C97CE0070E741 /* DiffableDataSource.TableView.swift in Sources */ = {isa = PBXBuildFile; fileRef = B5BF7FB6234C97CE0070E741 /* DiffableDataSource.TableView.swift */; };
B5BF7FBA234C97CE0070E741 /* DiffableDataSource.TableView.swift in Sources */ = {isa = PBXBuildFile; fileRef = B5BF7FB6234C97CE0070E741 /* DiffableDataSource.TableView.swift */; };
B5BF7FBC234C99190070E741 /* Internals.FallbackDiffableDataUIDispatcher.swift in Sources */ = {isa = PBXBuildFile; fileRef = B5BF7FBB234C99190070E741 /* Internals.FallbackDiffableDataUIDispatcher.swift */; };
B5BF7FBD234C99190070E741 /* Internals.FallbackDiffableDataUIDispatcher.swift in Sources */ = {isa = PBXBuildFile; fileRef = B5BF7FBB234C99190070E741 /* Internals.FallbackDiffableDataUIDispatcher.swift */; };
B5BF7FBE234C99190070E741 /* Internals.FallbackDiffableDataUIDispatcher.swift in Sources */ = {isa = PBXBuildFile; fileRef = B5BF7FBB234C99190070E741 /* Internals.FallbackDiffableDataUIDispatcher.swift */; };
B5BF7FBF234C99190070E741 /* Internals.FallbackDiffableDataUIDispatcher.swift in Sources */ = {isa = PBXBuildFile; fileRef = B5BF7FBB234C99190070E741 /* Internals.FallbackDiffableDataUIDispatcher.swift */; };
B5C976E31C6C9F6A00B1AF90 /* UnsafeDataTransaction+Observing.swift in Sources */ = {isa = PBXBuildFile; fileRef = B5C976E21C6C9F6A00B1AF90 /* UnsafeDataTransaction+Observing.swift */; };
B5C976E41C6C9F9A00B1AF90 /* UnsafeDataTransaction+Observing.swift in Sources */ = {isa = PBXBuildFile; fileRef = B5C976E21C6C9F6A00B1AF90 /* UnsafeDataTransaction+Observing.swift */; };
B5C976E51C6C9F9B00B1AF90 /* UnsafeDataTransaction+Observing.swift in Sources */ = {isa = PBXBuildFile; fileRef = B5C976E21C6C9F6A00B1AF90 /* UnsafeDataTransaction+Observing.swift */; };
@@ -942,6 +958,10 @@
B5AD60CD1C90141E00F2B2E8 /* Package.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Package.swift; sourceTree = SOURCE_ROOT; };
B5AEFAB41C9962AE00AD137F /* CoreStoreBridge.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = CoreStoreBridge.swift; sourceTree = "<group>"; };
B5BDC9271C2024F2008147CD /* .travis.yml */ = {isa = PBXFileReference; lastKnownFileType = text; path = .travis.yml; sourceTree = SOURCE_ROOT; };
B5BF7FAC234C41E90070E741 /* Internals.DiffableDataSourceSnapshot.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Internals.DiffableDataSourceSnapshot.swift; sourceTree = "<group>"; };
B5BF7FB1234C97910070E741 /* DiffableDataSource.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DiffableDataSource.swift; sourceTree = "<group>"; };
B5BF7FB6234C97CE0070E741 /* DiffableDataSource.TableView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DiffableDataSource.TableView.swift; sourceTree = "<group>"; };
B5BF7FBB234C99190070E741 /* Internals.FallbackDiffableDataUIDispatcher.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Internals.FallbackDiffableDataUIDispatcher.swift; sourceTree = "<group>"; };
B5C976E21C6C9F6A00B1AF90 /* UnsafeDataTransaction+Observing.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "UnsafeDataTransaction+Observing.swift"; sourceTree = "<group>"; };
B5C976E61C6E3A5900B1AF90 /* Internals.CoreStoreFetchedResultsController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Internals.CoreStoreFetchedResultsController.swift; sourceTree = "<group>"; };
B5CA2B071F7E5ACA004B1936 /* WhereClauseType.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = WhereClauseType.swift; sourceTree = "<group>"; };
@@ -1513,6 +1533,8 @@
B5D8CA752346E7590055D7D1 /* DataStack+DataSources.swift */,
B5F335572348D75D00FD649F /* LiveResult.swift */,
B5E294DC2349F8E7003E5956 /* SnapshotResult.swift */,
B5BF7FB1234C97910070E741 /* DiffableDataSource.swift */,
B5BF7FB6234C97CE0070E741 /* DiffableDataSource.TableView.swift */,
);
name = DataSources;
sourceTree = "<group>";
@@ -1643,6 +1665,8 @@
B5C976E61C6E3A5900B1AF90 /* Internals.CoreStoreFetchedResultsController.swift */,
B5474D142227C08700B21FEC /* Internals.CoreStoreFetchRequest.swift */,
B51260921E9B28F100402229 /* Internals.EntityIdentifier.swift */,
B5BF7FAC234C41E90070E741 /* Internals.DiffableDataSourceSnapshot.swift */,
B5BF7FBB234C99190070E741 /* Internals.FallbackDiffableDataUIDispatcher.swift */,
B54A6A541BA15F2A007870FD /* Internals.FetchedResultsControllerDelegate.swift */,
B501322F2346B76E00FC238B /* Internals.FetchedDiffableDataSourceSnapshotDelegate.swift */,
B5FAD6AB1B51285300714891 /* Internals.MigrationManager.swift */,
@@ -2018,6 +2042,7 @@
B56007141B3F6C2800A9A8F9 /* SectionBy.swift in Sources */,
B5DE522B230BD7CC00A22534 /* Internals.swift in Sources */,
B5E84F371AFF85470064E85B /* NSManagedObjectContext+Transaction.swift in Sources */,
B5BF7FB7234C97CE0070E741 /* DiffableDataSource.TableView.swift in Sources */,
B5ECDC1D1CA81A2100C7F112 /* CSDataStack+Querying.swift in Sources */,
B5C976E31C6C9F6A00B1AF90 /* UnsafeDataTransaction+Observing.swift in Sources */,
B53FBA121CAB63CB00F0D40A /* Progress+ObjectiveC.swift in Sources */,
@@ -2051,6 +2076,7 @@
B51260931E9B28F100402229 /* Internals.EntityIdentifier.swift in Sources */,
B5DAFB482203D9F8003FCCD0 /* Where.Expression.swift in Sources */,
B5FE4DA21C8481E100FA6A91 /* StorageInterface.swift in Sources */,
B5BF7FAD234C41E90070E741 /* Internals.DiffableDataSourceSnapshot.swift in Sources */,
B53FB9FE1CAB2D2F00F0D40A /* CSMigrationResult.swift in Sources */,
B5DBE2D21C991B3E00B5CEFA /* CSDataStack.swift in Sources */,
B50392F91C478FF3009900CA /* NSManagedObject+Transaction.swift in Sources */,
@@ -2104,6 +2130,7 @@
B5E84F391AFF85470064E85B /* NSManagedObjectContext+Querying.swift in Sources */,
B56923E81EB827F5007C4DC9 /* InferredSchemaMappingProvider.swift in Sources */,
B53B275F1EE3B92E00E9B352 /* CoreStoreManagedObject.swift in Sources */,
B5BF7FBC234C99190070E741 /* Internals.FallbackDiffableDataUIDispatcher.swift in Sources */,
B5215CA41FA47DFD00139E3A /* FetchChainBuilder.swift in Sources */,
B5D33A011E96012400C880DE /* Relationship.swift in Sources */,
B5E84EE81AFF84610064E85B /* CoreStoreLogger.swift in Sources */,
@@ -2123,6 +2150,7 @@
B5E84EF81AFF846E0064E85B /* CoreStore+Transaction.swift in Sources */,
B5E84F301AFF849C0064E85B /* NSManagedObjectContext+CoreStore.swift in Sources */,
B5831B7A1F34ACBA00A9F647 /* Transformable.swift in Sources */,
B5BF7FB2234C97910070E741 /* DiffableDataSource.swift in Sources */,
B546F9691C9AF26D00D5AC55 /* CSInMemoryStore.swift in Sources */,
B549F65E1E569C7400FBAB2D /* QueryableAttributeType.swift in Sources */,
B5E84F211AFF84860064E85B /* CoreStore+Observing.swift in Sources */,
@@ -2203,6 +2231,7 @@
82BA18B21C4BBD3900A0916E /* ImportableObject.swift in Sources */,
82BA18AE1C4BBD3100A0916E /* DataStack+Transaction.swift in Sources */,
82BA18AB1C4BBD3100A0916E /* AsynchronousDataTransaction.swift in Sources */,
B5BF7FBD234C99190070E741 /* Internals.FallbackDiffableDataUIDispatcher.swift in Sources */,
B5D339D91E9489AB00C880DE /* CoreStoreObject.swift in Sources */,
82BA18CE1C4BBD7100A0916E /* Internals.FetchedResultsControllerDelegate.swift in Sources */,
B56923FB1EB82956007C4DC9 /* CSXcodeDataModelSchema.swift in Sources */,
@@ -2230,6 +2259,7 @@
B53FBA141CAB63CB00F0D40A /* Progress+ObjectiveC.swift in Sources */,
B5831B761F34AC7A00A9F647 /* RelationshipProtocol.swift in Sources */,
B5E5FA4F22D162F400330931 /* ObjectSnapshot.swift in Sources */,
B5BF7FB3234C97910070E741 /* DiffableDataSource.swift in Sources */,
B5E1B5AA1CAA49E2007FD580 /* CSDataStack+Migrating.swift in Sources */,
B5D339F21E94AF5800C880DE /* CoreStoreStrings.swift in Sources */,
B5E1B59F1CAA2568007FD580 /* CSDataStack+Observing.swift in Sources */,
@@ -2326,6 +2356,7 @@
82BA18B51C4BBD3F00A0916E /* BaseDataTransaction+Querying.swift in Sources */,
B5F335592348D76300FD649F /* LiveResult.swift in Sources */,
B501FDDF1CA8D05000BE22EF /* CSSectionBy.swift in Sources */,
B5BF7FAE234C41E90070E741 /* Internals.DiffableDataSourceSnapshot.swift in Sources */,
B538BA781D15B3E30003A766 /* CoreStoreBridge.m in Sources */,
B51260801E97A18000402229 /* CoreStoreObject+Convenience.swift in Sources */,
82BA18D31C4BBD7100A0916E /* NSManagedObjectContext+CoreStore.swift in Sources */,
@@ -2357,6 +2388,7 @@
B5ECDC0D1CA8161B00C7F112 /* CSGroupBy.swift in Sources */,
B5D339E81E9493A500C880DE /* Entity.swift in Sources */,
82BA18CC1C4BBD6400A0916E /* Progress+Convenience.swift in Sources */,
B5BF7FB8234C97CE0070E741 /* DiffableDataSource.TableView.swift in Sources */,
82BA18C01C4BBD5300A0916E /* DataStack+Observing.swift in Sources */,
82BA18A61C4BBD2900A0916E /* DefaultLogger.swift in Sources */,
);
@@ -2411,6 +2443,7 @@
B546F9761C9C553300D5AC55 /* SetupResult.swift in Sources */,
B53FBA161CAB63CB00F0D40A /* Progress+ObjectiveC.swift in Sources */,
B5ECDC271CA81A3900C7F112 /* CSCoreStore+Querying.swift in Sources */,
B5BF7FBF234C99190070E741 /* Internals.FallbackDiffableDataUIDispatcher.swift in Sources */,
B5D339DB1E9489AB00C880DE /* CoreStoreObject.swift in Sources */,
B52DD1951BE1F92500949AFE /* CoreStoreError.swift in Sources */,
B56923FD1EB82956007C4DC9 /* CSXcodeDataModelSchema.swift in Sources */,
@@ -2438,6 +2471,7 @@
B5831B781F34AC7A00A9F647 /* RelationshipProtocol.swift in Sources */,
B52DD1981BE1F92500949AFE /* CoreStore+Setup.swift in Sources */,
B5E5FA5122D162F400330931 /* ObjectSnapshot.swift in Sources */,
B5BF7FB5234C97910070E741 /* DiffableDataSource.swift in Sources */,
B5D339F41E94AF5800C880DE /* CoreStoreStrings.swift in Sources */,
B5220E241D13085E009BC71E /* NSFetchedResultsController+Convenience.swift in Sources */,
B559CD471CAA8B6300E4D58B /* CSSetupResult.swift in Sources */,
@@ -2534,6 +2568,7 @@
B5220E251D13088E009BC71E /* ListObserver.swift in Sources */,
B5F3355B2348D76500FD649F /* LiveResult.swift in Sources */,
B538BA7A1D15B3E30003A766 /* CoreStoreBridge.m in Sources */,
B5BF7FB0234C41E90070E741 /* Internals.DiffableDataSourceSnapshot.swift in Sources */,
B51260821E97A18000402229 /* CoreStoreObject+Convenience.swift in Sources */,
B52DD1A01BE1F92C00949AFE /* UnsafeDataTransaction.swift in Sources */,
B5ECDC331CA81CDC00C7F112 /* CSCoreStore+Transaction.swift in Sources */,
@@ -2565,6 +2600,7 @@
B598514B1C90289F00C99590 /* NSPersistentStoreCoordinator+Setup.swift in Sources */,
B5D339EA1E9493A500C880DE /* Entity.swift in Sources */,
B52DD1AA1BE1F93500949AFE /* TypeErasedClauses.swift in Sources */,
B5BF7FBA234C97CE0070E741 /* DiffableDataSource.TableView.swift in Sources */,
B53FBA021CAB2D2F00F0D40A /* CSMigrationResult.swift in Sources */,
B51FE5AF1CD4D00300E54258 /* CoreStore+CustomDebugStringConvertible.swift in Sources */,
);
@@ -2619,6 +2655,7 @@
B56321AD1BD6521C006C9394 /* Internals.MigrationManager.swift in Sources */,
B563219D1BD65216006C9394 /* DataStack+Observing.swift in Sources */,
B56321961BD65216006C9394 /* From.swift in Sources */,
B5BF7FBE234C99190070E741 /* Internals.FallbackDiffableDataUIDispatcher.swift in Sources */,
B5D339DA1E9489AB00C880DE /* CoreStoreObject.swift in Sources */,
B5ECDC021CA80CBA00C7F112 /* CSWhere.swift in Sources */,
B56923FC1EB82956007C4DC9 /* CSXcodeDataModelSchema.swift in Sources */,
@@ -2646,6 +2683,7 @@
B5E1B5AB1CAA49E2007FD580 /* CSDataStack+Migrating.swift in Sources */,
B5831B771F34AC7A00A9F647 /* RelationshipProtocol.swift in Sources */,
B5E5FA5022D162F400330931 /* ObjectSnapshot.swift in Sources */,
B5BF7FB4234C97910070E741 /* DiffableDataSource.swift in Sources */,
B5D339F31E94AF5800C880DE /* CoreStoreStrings.swift in Sources */,
B5E1B5A01CAA2568007FD580 /* CSDataStack+Observing.swift in Sources */,
B5ECDC261CA81A3900C7F112 /* CSCoreStore+Querying.swift in Sources */,
@@ -2742,6 +2780,7 @@
B56321921BD65216006C9394 /* BaseDataTransaction+Querying.swift in Sources */,
B5F3355A2348D76500FD649F /* LiveResult.swift in Sources */,
B501FDE01CA8D05000BE22EF /* CSSectionBy.swift in Sources */,
B5BF7FAF234C41E90070E741 /* Internals.DiffableDataSourceSnapshot.swift in Sources */,
B538BA791D15B3E30003A766 /* CoreStoreBridge.m in Sources */,
B51260811E97A18000402229 /* CoreStoreObject+Convenience.swift in Sources */,
B56321B11BD6521C006C9394 /* NSManagedObjectContext+CoreStore.swift in Sources */,
@@ -2773,6 +2812,7 @@
B5ECDC0E1CA8161B00C7F112 /* CSGroupBy.swift in Sources */,
B5D339E91E9493A500C880DE /* Entity.swift in Sources */,
B56321A41BD65216006C9394 /* CoreStore+Migration.swift in Sources */,
B5BF7FB9234C97CE0070E741 /* DiffableDataSource.TableView.swift in Sources */,
B56321A01BD65216006C9394 /* ObjectObserver.swift in Sources */,
B56321951BD65216006C9394 /* TypeErasedClauses.swift in Sources */,
);

View File

@@ -26,27 +26,32 @@ struct SwiftUIView: View {
var body: some View {
NavigationView {
List {
ForEach(palettes.snapshot, id: \.self) { palette in
NavigationLink(
destination: DetailView(palette: palette),
label: {
HStack {
Color(palette.color)
.frame(width: 30, height: 30, alignment: .leading)
Text(palette.colorText)
}
ForEach(palettes.snapshot.sectionIdentifiers, id: \.self) { (sectionID: String) in
Section(header: Text(sectionID)) {
ForEach(self.palettes.snapshot[section: sectionID], id: \.self) { palette in
NavigationLink(
destination: DetailView(palette: palette),
label: {
HStack {
Color(palette.color)
.cornerRadius(5)
.frame(width: 30, height: 30, alignment: .leading)
Text(palette.colorText)
}
}
)
}
)
}
.onDelete { indices in
let palettes = self.palettes.snapshot[indices]
self.dataStack.perform(
asynchronous: { transaction in
.onDelete { itemIndices in
let objectsToDelete = self.palettes.snapshot[section: sectionID, itemIndices: itemIndices]
self.dataStack.perform(
asynchronous: { transaction in
transaction.delete(palettes)
},
completion: { _ in }
)
transaction.delete(objectsToDelete)
},
completion: { _ in }
)
}
}
}
}
.navigationBarTitle(Text("SwiftUI"))
@@ -90,16 +95,36 @@ struct SwiftUIView: View {
@available(iOS 13.0.0, *)
struct DetailView: View {
@Environment(\.dataStack)
var dataStack: DataStack
@ObservedObject var palette: Palette
@State var hue: Float = 0
@State var saturation: Float = 0
@State var brightness: Float = 0
init(palette: Palette) {
self.palette = palette
self.hue = Float(palette.hue.value)
self.saturation = palette.saturation.value
self.brightness = palette.brightness.value
}
var body: some View {
ZStack {
Color(palette.color)
.cornerRadius(20)
.padding(20)
Text(palette.colorText)
.navigationBarTitle(Text("Color"))
VStack {
Text(palette.colorText)
.navigationBarTitle(Text("Color"))
Slider(value: $hue, in: 0.0 ... 359.0 as ClosedRange<Float>)
Slider(value: $saturation, in: 0.0 ... 1.0 as ClosedRange<Float>)
Slider(value: $brightness, in: 0.0 ... 0.1 as ClosedRange<Float>)
}
}
}
}

View File

@@ -0,0 +1,107 @@
//
// DiffableDataSource.TableView.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: - TableView
//
// public open class TableView<D: DynamicObject>: NSObject, UITableViewDataSource {
//
// // MARK: Public
//
// public typealias ObjectType = D
//
// public var defaultRowAnimation: UITableView.RowAnimation = .automatic
//
// public init(tableView: UITableView, cellProvider: @escaping (UITableView, IndexPath, ObjectType) -> UITableViewCell?) {
//
// self.tableView = tableView
// self.cellProvider = cellProvider
//
// if #available(iOS 13.0, tvOS 13.0, watchOS 6.0, macOS 15.0, *) {
//
// self.rawDataSource = UITableViewDiffableDataSource<String, D.ObjectID>(
// tableView: tableView,
// cellProvider: { (tableView, indexPath, managedObjectID) -> UITableViewCell? in
//
// cellProvider(
// }
// )
// }
// else {
//
// self.rawDataSource = nil
// }
//
// super.init()
//
// tableView.dataSource = self
// }
//
// public func apply(_ snapshot: ListSnapshot<ObjectType>, animatingDifferences: Bool = true) {
//
// let dataSource = UITableViewDiffableDataSource<String, D>.
// if #available(iOS 13.0, tvOS 13.0, watchOS 6.0, macOS 15.0, *) {
//
// self.rawDataSource! as! UITableViewDiffableDataSource<String, D>
//
// }
// else {
//
// }
// core.apply(
// snapshot,
// view: tableView,
// animatingDifferences: animatingDifferences,
// performUpdates: { tableView, changeset, setSections in
// tableView.reload(using: changeset, with: self.defaultRowAnimation, setData: setSections)
// })
// }
//
//
// // MARK: Private
//
// private weak var tableView: UITableView?
// private let cellProvider: (UITableView, IndexPath, ObjectType) -> UITableViewCell?
// private let rawDataSource: Any?
//
// @available(iOS 13.0, tvOS 13.0, watchOS 6.0, macOS 15.0, *)
// private var diffableDataSource: UITableViewDiffableDataSource<String, D.ObjectID> {
//
// return self.rawDataSource! as! UITableViewDiffableDataSource<String, D.ObjectID>
// }
// }
//}
#endif

View File

@@ -0,0 +1,29 @@
//
// File.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.
//
// MARK: - DiffableDataSource
public enum DiffableDataSource {}

View File

@@ -33,7 +33,12 @@ import CoreData
All CoreStore's utilities are designed around `DynamicObject` instances. `NSManagedObject` and `CoreStoreObject` instances all conform to `DynamicObject`.
*/
public protocol DynamicObject: AnyObject {
/**
The object ID for this instance
*/
typealias ObjectID = NSManagedObjectID
/**
Used internally by CoreStore. Do not call directly.
*/
@@ -52,7 +57,7 @@ public protocol DynamicObject: AnyObject {
/**
Used internally by CoreStore. Do not call directly.
*/
func cs_id() -> NSManagedObjectID
func cs_id() -> ObjectID
/**
Used internally by CoreStore. Do not call directly.
@@ -103,7 +108,7 @@ extension NSManagedObject: DynamicObject {
return object.isKind(of: self)
}
public func cs_id() -> NSManagedObjectID {
public func cs_id() -> ObjectID {
return self.objectID
}
@@ -166,7 +171,7 @@ extension CoreStoreObject {
return (self as AnyClass).isSubclass(of: type as AnyClass)
}
public func cs_id() -> NSManagedObjectID {
public func cs_id() -> ObjectID {
return self.rawObject!.objectID
}

View File

@@ -29,9 +29,9 @@ public struct DataStackEnvironmentKey: EnvironmentKey {
@available(iOS 13.0, tvOS 13.0, watchOS 6.0, macOS 15.0, *)
extension EnvironmentValues {
// MARK: Public
public var dataStack: DataStack {
get {
return self[DataStackEnvironmentKey.self]

View File

@@ -82,6 +82,11 @@ extension Internals {
try self.reapplyAffectedStores(self.typedFetchRequest, self.managedObjectContext)
try self.performFetch()
if case let delegate as FetchedDiffableDataSourceSnapshotDelegate = self.delegate {
delegate.initialFetch()
}
}
@nonobjc

View File

@@ -0,0 +1,606 @@
//
// Internals.DiffableDataSourceSnapshot.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) || canImport(AppKit)
import CoreData
#if canImport(UIKit)
import UIKit
#elseif canImport(AppKit)
import AppKit
#endif
// MARK: - Internals
extension Internals {
// MARK: Internal
internal typealias DiffableDataSourceSnapshot = _Internal_DiffableDataSourceSnapshot
// MARK: - FallbackDiffableDataSourceSnapshot
// Implementation based on https://github.com/ra1028/DiffableDataSources
internal struct FallbackDiffableDataSourceSnapshot: DiffableDataSourceSnapshot {
// MARK: Internal
init(sections: [NSFetchedResultsSectionInfo]) {
self.structure = .init(sections: sections)
}
// MARK: DiffableDataSourceSnapshot
init() {
self.structure = .init()
}
var numberOfItems: Int {
return self.itemIdentifiers.count
}
var numberOfSections: Int {
return self.sectionIdentifiers.count
}
var sectionIdentifiers: [NSString] {
return self.structure.allSectionIDs
}
var itemIdentifiers: [NSManagedObjectID] {
self.structure.allItemIDs
}
func numberOfItems(inSection identifier: NSString) -> Int {
return self.itemIdentifiers(inSection: identifier).count
}
func itemIdentifiers(inSection identifier: NSString) -> [NSManagedObjectID] {
return self.structure.items(in: identifier)
}
func sectionIdentifier(containingItem identifier: NSManagedObjectID) -> NSString? {
return self.structure.section(containing: identifier)
}
func indexOfItem(_ identifier: NSManagedObjectID) -> Int? {
return self.itemIdentifiers.firstIndex(of: identifier)
}
func indexOfSection(_ identifier: NSString) -> Int? {
return self.sectionIdentifiers.firstIndex(of: identifier)
}
mutating func appendItems(_ identifiers: [NSManagedObjectID], toSection sectionIdentifier: NSString?) {
self.structure.append(itemIDs: identifiers, to: sectionIdentifier)
}
mutating func insertItems(_ identifiers: [NSManagedObjectID], beforeItem beforeIdentifier: NSManagedObjectID) {
self.structure.insert(itemIDs: identifiers, before: beforeIdentifier)
}
mutating func insertItems(_ identifiers: [NSManagedObjectID], afterItem afterIdentifier: NSManagedObjectID) {
self.structure.insert(itemIDs: identifiers, after: afterIdentifier)
}
mutating func deleteItems(_ identifiers: [NSManagedObjectID]) {
self.structure.remove(itemIDs: identifiers)
}
mutating func deleteAllItems() {
self.structure.removeAllItems()
}
mutating func moveItem(_ identifier: NSManagedObjectID, beforeItem toIdentifier: NSManagedObjectID) {
self.structure.move(itemID: identifier, before: toIdentifier)
}
mutating func moveItem(_ identifier: NSManagedObjectID, afterItem toIdentifier: NSManagedObjectID) {
self.structure.move(itemID: identifier, after: toIdentifier)
}
mutating func reloadItems(_ identifiers: [NSManagedObjectID]) {
self.structure.update(itemIDs: identifiers)
}
mutating func appendSections(_ identifiers: [NSString]) {
self.structure.append(sectionIDs: identifiers)
}
mutating func insertSections(_ identifiers: [NSString], beforeSection toIdentifier: NSString) {
self.structure.insert(sectionIDs: identifiers, before: toIdentifier)
}
mutating func insertSections(_ identifiers: [NSString], afterSection toIdentifier: NSString) {
self.structure.insert(sectionIDs: identifiers, after: toIdentifier)
}
mutating func deleteSections(_ identifiers: [NSString]) {
self.structure.remove(sectionIDs: identifiers)
}
mutating func moveSection(_ identifier: NSString, beforeSection toIdentifier: NSString) {
self.structure.move(sectionID: identifier, before: toIdentifier)
}
mutating func moveSection(_ identifier: NSString, afterSection toIdentifier: NSString) {
self.structure.move(sectionID: identifier, after: toIdentifier)
}
mutating func reloadSections(_ identifiers: [NSString]) {
self.structure.update(sectionIDs: identifiers)
}
// MARK: Private
private var structure: BackingStructure
// MARK: - BackingStructure
internal struct BackingStructure {
// MARK: Internal
var sections: [Section]
init() {
self.sections = []
}
init(sections: [NSFetchedResultsSectionInfo]) {
self.sections = sections.map {
Section(
id: $0.name as NSString,
items: $0.objects?
.compactMap({ ($0 as? NSManagedObject)?.objectID })
.map(Item.init(id:)) ?? [],
isReloaded: false
)
}
}
var allSectionIDs: [NSString] {
return self.sections.map({ $0.id })
}
var allItemIDs: [NSManagedObjectID] {
return self.sections.lazy.flatMap({ $0.elements }).map({ $0.id })
}
func items(in sectionID: NSString) -> [NSManagedObjectID] {
guard let sectionIndex = self.sectionIndex(of: sectionID) else {
Internals.abort("Section \"\(sectionID)\" does not exist")
}
return self.sections[sectionIndex].elements.map({ $0.id })
}
func section(containing itemID: NSManagedObjectID) -> NSString? {
return self.itemPositionMap()[itemID]?.section.id
}
mutating func append(itemIDs: [NSManagedObjectID], to sectionID: NSString?) {
let index: Array<Section>.Index
if let sectionID = sectionID {
guard let sectionIndex = self.sectionIndex(of: sectionID) else {
Internals.abort("Section \"\(sectionID)\" does not exist")
}
index = sectionIndex
}
else {
let section = self.sections
guard !section.isEmpty else {
Internals.abort("No sections exist")
}
index = section.index(before: section.endIndex)
}
let items = itemIDs.lazy.map(Item.init)
self.sections[index].elements.append(contentsOf: items)
}
mutating func insert(itemIDs: [NSManagedObjectID], before beforeItemID: NSManagedObjectID) {
guard let itemPosition = self.itemPositionMap()[beforeItemID] else {
Internals.abort("Item \(beforeItemID) does not exist")
}
let items = itemIDs.lazy.map(Item.init)
self.sections[itemPosition.sectionIndex].elements
.insert(contentsOf: items, at: itemPosition.itemRelativeIndex)
}
mutating func insert(itemIDs: [NSManagedObjectID], after afterItemID: NSManagedObjectID) {
guard let itemPosition = self.itemPositionMap()[afterItemID] else {
Internals.abort("Item \(afterItemID) does not exist")
}
let itemIndex = self.sections[itemPosition.sectionIndex].elements
.index(after: itemPosition.itemRelativeIndex)
let items = itemIDs.lazy.map(Item.init)
self.sections[itemPosition.sectionIndex].elements
.insert(contentsOf: items, at: itemIndex)
}
mutating func remove(itemIDs: [NSManagedObjectID]) {
let itemPositionMap = self.itemPositionMap()
var removeIndexSetMap: [Int: IndexSet] = [:]
for itemID in itemIDs {
guard let itemPosition = itemPositionMap[itemID] else {
continue
}
removeIndexSetMap[itemPosition.sectionIndex, default: []]
.insert(itemPosition.itemRelativeIndex)
}
for (sectionIndex, removeIndexSet) in removeIndexSetMap {
for range in removeIndexSet.rangeView.reversed() {
self.sections[sectionIndex].elements.removeSubrange(range)
}
}
}
mutating func removeAllItems() {
for sectionIndex in self.sections.indices {
self.sections[sectionIndex].elements.removeAll()
}
}
mutating func move(itemID: NSManagedObjectID, before beforeItemID: NSManagedObjectID) {
guard let removed = self.remove(itemID: itemID) else {
Internals.abort("Item \(itemID) does not exist")
}
guard let itemPosition = self.itemPositionMap()[beforeItemID] else {
Internals.abort("Item \(beforeItemID) does not exist")
}
self.sections[itemPosition.sectionIndex].elements
.insert(removed, at: itemPosition.itemRelativeIndex)
}
mutating func move(itemID: NSManagedObjectID, after afterItemID: NSManagedObjectID) {
guard let removed = self.remove(itemID: itemID) else {
Internals.abort("Item \(itemID) does not exist")
}
guard let itemPosition = self.itemPositionMap()[afterItemID] else {
Internals.abort("Item \(afterItemID) does not exist")
}
let itemIndex = self.sections[itemPosition.sectionIndex].elements
.index(after: itemPosition.itemRelativeIndex)
self.sections[itemPosition.sectionIndex].elements
.insert(removed, at: itemIndex)
}
mutating func update(itemIDs: [NSManagedObjectID]) {
let itemPositionMap = self.itemPositionMap()
for itemID in itemIDs {
guard let itemPosition = itemPositionMap[itemID] else {
Internals.abort("Item \(itemID) does not exist")
}
self.sections[itemPosition.sectionIndex].elements[itemPosition.itemRelativeIndex].isReloaded = true
}
}
mutating func append(sectionIDs: [NSString]) {
let newSections = sectionIDs.lazy.map(Section.init)
self.sections.append(contentsOf: newSections)
}
mutating func insert(sectionIDs: [NSString], before beforeSectionID: NSString) {
guard let sectionIndex = self.sectionIndex(of: beforeSectionID) else {
Internals.abort("Section \"\(beforeSectionID)\" does not exist")
}
let newSections = sectionIDs.lazy.map(Section.init)
self.sections.insert(contentsOf: newSections, at: sectionIndex)
}
mutating func insert(sectionIDs: [NSString], after afterSectionID: NSString) {
guard let beforeIndex = self.sectionIndex(of: afterSectionID) else {
Internals.abort("Section \"\(afterSectionID)\" does not exist")
}
let sectionIndex = self.sections.index(after: beforeIndex)
let newSections = sectionIDs.lazy.map(Section.init)
self.sections.insert(contentsOf: newSections, at: sectionIndex)
}
mutating func remove(sectionIDs: [NSString]) {
for sectionID in sectionIDs {
self.remove(sectionID: sectionID)
}
}
mutating func move(sectionID: NSString, before beforeSectionID: NSString) {
guard let removed = self.remove(sectionID: sectionID) else {
Internals.abort("Section \"\(sectionID)\" does not exist")
}
guard let sectionIndex = self.sectionIndex(of: beforeSectionID) else {
Internals.abort("Section \"\(beforeSectionID)\" does not exist")
}
self.sections.insert(removed, at: sectionIndex)
}
mutating func move(sectionID: NSString, after afterSectionID: NSString) {
guard let removed = self.remove(sectionID: sectionID) else {
Internals.abort("Section \"\(sectionID)\" does not exist")
}
guard let beforeIndex = self.sectionIndex(of: afterSectionID) else {
Internals.abort("Section \"\(afterSectionID)\" does not exist")
}
let sectionIndex = self.sections.index(after: beforeIndex)
self.sections.insert(removed, at: sectionIndex)
}
mutating func update(sectionIDs: [NSString]) {
for sectionID in sectionIDs {
guard let sectionIndex = self.sectionIndex(of: sectionID) else {
continue
}
self.sections[sectionIndex].isReloaded = true
}
}
// MARK: Private
private func sectionIndex(of sectionID: NSString) -> Array<Section>.Index? {
return self.sections.firstIndex(where: { $0.id == sectionID })
}
@discardableResult
private mutating func remove(itemID: NSManagedObjectID) -> Item? {
guard let itemPosition = self.itemPositionMap()[itemID] else {
return nil
}
return self.sections[itemPosition.sectionIndex].elements
.remove(at: itemPosition.itemRelativeIndex)
}
@discardableResult
private mutating func remove(sectionID: NSString) -> Section? {
guard let sectionIndex = self.sectionIndex(of: sectionID) else {
return nil
}
return self.sections.remove(at: sectionIndex)
}
private func itemPositionMap() -> [NSManagedObjectID: ItemPosition] {
return self.sections.enumerated().reduce(into: [:]) { result, section in
for (itemRelativeIndex, item) in section.element.elements.enumerated() {
result[item.id] = ItemPosition(
item: item,
itemRelativeIndex: itemRelativeIndex,
section: section.element,
sectionIndex: section.offset
)
}
}
}
// MARK: - Item
internal struct Item: Identifiable, Equatable {
var isReloaded: Bool
init(id: NSManagedObjectID, isReloaded: Bool) {
self.id = id
self.isReloaded = isReloaded
}
init(id: NSManagedObjectID) {
self.init(id: id, isReloaded: false)
}
func isContentEqual(to source: Item) -> Bool {
return !self.isReloaded && self.id == source.id
}
// MARK: Identifiable
var id: NSManagedObjectID
}
// MARK: - Section
internal struct Section: Identifiable, Equatable {
var elements: [Item] = []
var isReloaded: Bool
init(id: NSString, items: [Item], isReloaded: Bool) {
self.id = id
self.elements = items
self.isReloaded = isReloaded
}
init(id: NSString) {
self.init(id: id, items: [], isReloaded: false)
}
init<S: Sequence>(source: Section, elements: S) where S.Element == Item {
self.init(id: source.id, items: Array(elements), isReloaded: source.isReloaded)
}
func isContentEqual(to source: Section) -> Bool {
return !self.isReloaded && self.id == source.id
}
// MARK: Identifiable
var id: NSString
}
// MARK: - ItemPosition
fileprivate struct ItemPosition {
var item: Item
var itemRelativeIndex: Int
var section: Section
var sectionIndex: Int
}
}
}
}
// MARK: - NSDiffableDataSourceSnapshot: Internals.DiffableDataSourceSnapshot
@available(iOS 13.0, tvOS 13.0, watchOS 6.0, macOS 15.0, *)
extension NSDiffableDataSourceSnapshot: Internals.DiffableDataSourceSnapshot where SectionIdentifierType == NSString, ItemIdentifierType == NSManagedObjectID {}
// MARK: - Internals.DiffableDataSourceSnapshot
internal protocol _Internal_DiffableDataSourceSnapshot {
init()
var numberOfItems: Int { get }
var numberOfSections: Int { get }
var sectionIdentifiers: [NSString] { get }
var itemIdentifiers: [NSManagedObjectID] { get }
func numberOfItems(inSection identifier: NSString) -> Int
func itemIdentifiers(inSection identifier: NSString) -> [NSManagedObjectID]
func sectionIdentifier(containingItem identifier: NSManagedObjectID) -> NSString?
func indexOfItem(_ identifier: NSManagedObjectID) -> Int?
func indexOfSection(_ identifier: NSString) -> Int?
mutating func appendItems(_ identifiers: [NSManagedObjectID], toSection sectionIdentifier: NSString?)
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: [NSString])
mutating func insertSections(_ identifiers: [NSString], beforeSection toIdentifier: NSString)
mutating func insertSections(_ identifiers: [NSString], afterSection toIdentifier: NSString)
mutating func deleteSections(_ identifiers: [NSString])
mutating func moveSection(_ identifier: NSString, beforeSection toIdentifier: NSString)
mutating func moveSection(_ identifier: NSString, afterSection toIdentifier: NSString)
mutating func reloadSections(_ identifiers: [NSString])
}
#endif

View File

@@ -0,0 +1,157 @@
//
// Internals.FallbackDiffableDataUIDispatcher.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) || canImport(AppKit)
import CoreData
#if canImport(QuartzCore)
import QuartzCore
#endif
// MARK: - Internals
extension Internals {
// MARK: Internal
// // Implementation based on https://github.com/ra1028/DiffableDataSources
// internal final class FallbackDiffableDataUIDispatcher {
//
// // MARK: Internal
//
// internal func apply() {
//
// }
//
// func snapshot() -> DiffableDataSourceSnapshot<SectionIdentifierType, ItemIdentifierType> {
// var snapshot = DiffableDataSourceSnapshot<SectionIdentifierType, ItemIdentifierType>()
// snapshot.structure.sections = currentSnapshot.structure.sections
// return snapshot
// }
//
// func itemIdentifier(for indexPath: IndexPath) -> ItemIdentifierType? {
// guard 0..<sections.endIndex ~= indexPath.section else {
// return nil
// }
//
// let items = sections[indexPath.section].elements
//
// guard 0..<items.endIndex ~= indexPath.item else {
// return nil
// }
//
// return items[indexPath.item].differenceIdentifier
// }
//
// func unsafeItemIdentifier(for indexPath: IndexPath, file: StaticString = #file, line: UInt = #line) -> ItemIdentifierType {
// guard let itemIdentifier = itemIdentifier(for: indexPath) else {
// universalError("Item not found at the specified index path(\(indexPath)).")
// }
//
// return itemIdentifier
// }
//
// func indexPath(for itemIdentifier: ItemIdentifierType) -> IndexPath? {
// let indexPathMap: [ItemIdentifierType: IndexPath] = sections.enumerated()
// .reduce(into: [:]) { result, section in
// for (itemIndex, item) in section.element.elements.enumerated() {
// result[item.differenceIdentifier] = IndexPath(
// item: itemIndex,
// section: section.offset
// )
// }
// }
// return indexPathMap[itemIdentifier]
// }
//
// func numberOfSections() -> Int {
// return sections.count
// }
//
// func numberOfItems(inSection section: Int) -> Int {
// return sections[section].elements.count
// }
//
//
//
// // MARK: Private
//
// private let dispatcher: MainThreadSerialDispatcher = .init()
//
// private var currentSnapshot: Internals.DiffableDataSourceSnapshot = FallbackDiffableDataSourceSnapshot()
// private var sections: [FallbackDiffableDataSourceSnapshot.BackingStructure.Section] = []
//
//
// // MARK: - MainThreadSerialDispatcher
//
// fileprivate final class MainThreadSerialDispatcher {
//
// // MARK: FilePrivate
//
// fileprivate init() {
//
// self.executingCount.initialize(to: 0)
// }
//
// deinit {
//
// self.executingCount.deinitialize(count: 1)
// self.executingCount.deallocate()
// }
//
// fileprivate func dispatch(_ action: @escaping () -> Void) {
//
// let count = OSAtomicIncrement32(self.executingCount)
// if Thread.isMainThread && count == 1 {
//
// action()
// OSAtomicDecrement32(executingCount)
// }
// else {
//
// DispatchQueue.main.async { [weak self] in
//
// guard let self = self else {
//
// return
// }
// action()
// OSAtomicDecrement32(self.executingCount)
// }
// }
// }
//
//
// // MARK: Private
//
// private let executingCount: UnsafeMutablePointer<Int32> = .allocate(capacity: 1)
// }
// }
}
#endif

View File

@@ -23,8 +23,6 @@
// SOFTWARE.
//
#if canImport(UIKit) || canImport(AppKit)
import Foundation
import CoreData
@@ -41,10 +39,9 @@ import AppKit
// MARK: - FetchedDiffableDataSourceSnapshot
@available(iOS 13.0, tvOS 13.0, watchOS 6.0, macOS 15.0, *)
internal protocol FetchedDiffableDataSourceSnapshotHandler: AnyObject {
func controller(_ controller: NSFetchedResultsController<NSFetchRequestResult>, didChangContentWith snapshot: NSDiffableDataSourceSnapshotReference)
func controller(_ controller: NSFetchedResultsController<NSFetchRequestResult>, didChangContentWith snapshot: Internals.DiffableDataSourceSnapshot)
}
@@ -54,7 +51,6 @@ extension Internals {
// MARK: - FetchedDiffableDataSourceSnapshotDelegate
@available(iOS 13.0, tvOS 13.0, watchOS 6.0, macOS 15.0, *)
internal final class FetchedDiffableDataSourceSnapshotDelegate: NSObject, NSFetchedResultsControllerDelegate {
// MARK: Internal
@@ -77,18 +73,71 @@ extension Internals {
self.fetchedResultsController?.delegate = nil
}
internal func initialFetch() {
#if canImport(UIKit) || canImport(AppKit)
if #available(iOS 13.0, tvOS 13.0, watchOS 6.0, macOS 15.0, *) {
return
}
#endif
guard let fetchedResultsController = self.fetchedResultsController else {
return
}
self.controllerDidChangeContent(fetchedResultsController.dynamicCast())
}
// MARK: NSFetchedResultsControllerDelegate
#if canImport(UIKit) || canImport(AppKit)
@available(iOS 13.0, tvOS 13.0, watchOS 6.0, macOS 15.0, *)
@objc
dynamic func controller(_ controller: NSFetchedResultsController<NSFetchRequestResult>, didChangeContentWith snapshot: NSDiffableDataSourceSnapshotReference) {
self.handler?.controller(
controller,
didChangContentWith: snapshot
didChangContentWith: snapshot as NSDiffableDataSourceSnapshot<NSString, NSManagedObjectID>
)
}
#endif
@objc
dynamic func controllerWillChangeContent(_ controller: NSFetchedResultsController<NSFetchRequestResult>) {
self.reloadedIDs = []
}
@objc
dynamic func controllerDidChangeContent(_ controller: NSFetchedResultsController<NSFetchRequestResult>) {
self.handler?.controller(
controller,
didChangContentWith: FallbackDiffableDataSourceSnapshot(
sections: controller.sections ?? []
)
)
self.reloadedIDs = []
}
// @objc
// dynamic func controller(_ controller: NSFetchedResultsController<NSFetchRequestResult>, didChange anObject: Any, at indexPath: IndexPath?, for type: NSFetchedResultsChangeType, newIndexPath: IndexPath?) {
//
//
//// [1].difference(from: <#T##BidirectionalCollection#>)
// let managedObject = anObject as! NSManagedObject
// self.reloadedIDs.insert(managedObject.objectID)
// }
// MARK: Private
private var reloadedIDs: Set<NSManagedObjectID> = []
}
}
#endif

View File

@@ -23,8 +23,6 @@
// SOFTWARE.
//
#if canImport(UIKit) || canImport(AppKit)
import CoreData
#if canImport(UIKit)
@@ -38,21 +36,170 @@ import AppKit
// MARK: - LiveList
@available(iOS 13.0, tvOS 13.0, watchOS 6.0, macOS 15.0, *)
public struct ListSnapshot<D: DynamicObject>: SnapshotResult, RandomAccessCollection, Hashable {
// MARK: Public
public subscript<S: Sequence>(indices: S) -> [ObjectType] where S.Element == Index {
public typealias SectionID = String
public typealias ItemID = D.ObjectID
public subscript<S: Sequence>(indices indices: S) -> [ObjectType] where S.Element == Index {
let context = self.context!
let objectIDs = self.snapshotStruct.itemIdentifiers
let objectIDs = self.diffableSnapshot.itemIdentifiers
return indices.map { position in
let objectID = objectIDs[position]
return context.fetchExisting(objectID)!
}
}
public subscript(section sectionID: SectionID) -> [ObjectType] {
let context = self.context!
let objectIDs = self.itemIdentifiers(inSection: sectionID)
return objectIDs.map {
return context.fetchExisting($0)!
}
}
public subscript<S: Sequence>(section sectionID: SectionID, itemIndices itemIndices: S) -> [ObjectType] where S.Element == Int {
let context = self.context!
let objectIDs = self.itemIdentifiers(inSection: sectionID)
return itemIndices.map { position in
let objectID = objectIDs[position]
return context.fetchExisting(objectID)!
}
}
public var numberOfItems: Int {
return self.diffableSnapshot.numberOfItems
}
public var numberOfSections: Int {
return self.diffableSnapshot.numberOfSections
}
public var sectionIdentifiers: [String] {
return self.diffableSnapshot.sectionIdentifiers as [String]
}
public var itemIdentifiers: [ItemID] {
return self.diffableSnapshot.itemIdentifiers as [ItemID]
}
public func numberOfItems(inSection identifier: SectionID) -> Int {
return self.diffableSnapshot.numberOfItems(inSection: identifier as NSString)
}
public func itemIdentifiers(inSection identifier: SectionID) -> [ItemID] {
return self.diffableSnapshot.itemIdentifiers(inSection: identifier as NSString)
}
public func itemIdentifiers(inSection identifier: SectionID, atIndices indices: IndexSet) -> [ItemID] {
let itemIDs = self.itemIdentifiers(inSection: identifier)
return indices.map({ itemIDs[$0] })
}
public func sectionIdentifier(containingItem identifier: ItemID) -> SectionID? {
return self.diffableSnapshot.sectionIdentifier(containingItem: identifier) as SectionID?
}
public func indexOfItem(_ identifier: ItemID) -> Index? {
return self.diffableSnapshot.indexOfItem(identifier)
}
public func indexOfSection(_ identifier: SectionID) -> Int? {
return self.diffableSnapshot.indexOfSection(identifier as NSString)
}
public mutating func appendItems(_ identifiers: [ItemID], toSection sectionIdentifier: SectionID? = nil) {
self.diffableSnapshot.appendItems(identifiers, toSection: sectionIdentifier as NSString?)
}
public mutating func insertItems(_ identifiers: [ItemID], beforeItem beforeIdentifier: ItemID) {
self.diffableSnapshot.insertItems(identifiers, beforeItem: beforeIdentifier)
}
public mutating func insertItems(_ identifiers: [ItemID], afterItem afterIdentifier: ItemID) {
self.diffableSnapshot.insertItems(identifiers, afterItem: afterIdentifier)
}
public mutating func deleteItems(_ identifiers: [ItemID]) {
self.diffableSnapshot.deleteItems(identifiers)
}
public mutating func deleteAllItems() {
self.diffableSnapshot.deleteAllItems()
}
public mutating func moveItem(_ identifier: ItemID, beforeItem toIdentifier: ItemID) {
self.diffableSnapshot.moveItem(identifier, beforeItem: toIdentifier)
}
public mutating func moveItem(_ identifier: ItemID, afterItem toIdentifier: ItemID) {
self.diffableSnapshot.moveItem(identifier, afterItem: toIdentifier)
}
public mutating func reloadItems(_ identifiers: [ItemID]) {
self.diffableSnapshot.reloadItems(identifiers)
}
public mutating func appendSections(_ identifiers: [SectionID]) {
self.diffableSnapshot.appendSections(identifiers as [NSString])
}
public mutating func insertSections(_ identifiers: [SectionID], beforeSection toIdentifier: SectionID) {
self.diffableSnapshot.insertSections(identifiers as [NSString], beforeSection: toIdentifier as NSString)
}
public mutating func insertSections(_ identifiers: [SectionID], afterSection toIdentifier: SectionID) {
self.diffableSnapshot.insertSections(identifiers as [NSString], afterSection: toIdentifier as NSString)
}
public mutating func deleteSections(_ identifiers: [SectionID]) {
self.diffableSnapshot.deleteSections(identifiers as [NSString])
}
public mutating func moveSection(_ identifier: SectionID, beforeSection toIdentifier: SectionID) {
self.diffableSnapshot.moveSection(identifier as NSString, beforeSection: toIdentifier as NSString)
}
public mutating func moveSection(_ identifier: SectionID, afterSection toIdentifier: SectionID) {
self.diffableSnapshot.moveSection(identifier as NSString, afterSection: toIdentifier as NSString)
}
public mutating func reloadSections(_ identifiers: [SectionID]) {
self.diffableSnapshot.reloadSections(identifiers as [NSString])
}
// MARK: SnapshotResult
@@ -64,18 +211,18 @@ public struct ListSnapshot<D: DynamicObject>: SnapshotResult, RandomAccessCollec
public var startIndex: Index {
return 0
return self.diffableSnapshot.itemIdentifiers.startIndex
}
public var endIndex: Index {
return self.snapshotStruct.numberOfItems
return self.diffableSnapshot.itemIdentifiers.endIndex
}
public subscript(position: Index) -> ObjectType {
let context = self.context!
let objectID = self.snapshotStruct.itemIdentifiers[position]
let objectID = self.diffableSnapshot.itemIdentifiers[position]
return context.fetchExisting(objectID)!
}
@@ -106,16 +253,14 @@ public struct ListSnapshot<D: DynamicObject>: SnapshotResult, RandomAccessCollec
// MARK: Internal
internal init() {
self.snapshotReference = .init()
self.snapshotStruct = self.snapshotReference as NSDiffableDataSourceSnapshot<NSString, NSManagedObjectID>
self.diffableSnapshot = Internals.FallbackDiffableDataSourceSnapshot()
self.context = nil
}
internal init(snapshotReference: NSDiffableDataSourceSnapshotReference, context: NSManagedObjectContext) {
self.snapshotReference = snapshotReference
self.snapshotStruct = snapshotReference as NSDiffableDataSourceSnapshot<NSString, NSManagedObjectID>
internal init(diffableSnapshot: Internals.DiffableDataSourceSnapshot, context: NSManagedObjectContext) {
self.diffableSnapshot = diffableSnapshot
self.context = context
}
@@ -123,9 +268,6 @@ public struct ListSnapshot<D: DynamicObject>: SnapshotResult, RandomAccessCollec
// MARK: Private
private let id: UUID = .init()
private let snapshotReference: NSDiffableDataSourceSnapshotReference
private let snapshotStruct: NSDiffableDataSourceSnapshot<NSString, NSManagedObjectID>
private let context: NSManagedObjectContext?
private var diffableSnapshot: Internals.DiffableDataSourceSnapshot
}
#endif

View File

@@ -23,18 +23,8 @@
// SOFTWARE.
//
#if canImport(UIKit) || canImport(AppKit)
import CoreData
#if canImport(UIKit)
import UIKit
#elseif canImport(AppKit)
import AppKit
#endif
#if canImport(Combine)
import Combine
@@ -48,7 +38,6 @@ import SwiftUI
// MARK: - LiveList
@available(iOS 13.0, tvOS 13.0, watchOS 6.0, macOS 15.0, *)
public final class LiveList<D: DynamicObject> {
// MARK: Public
@@ -57,23 +46,22 @@ public final class LiveList<D: DynamicObject> {
willSet {
#if canImport(Combine)
let oldValue = self.snapshot
guard newValue != oldValue else {
guard #available(iOS 13.0, tvOS 13.0, watchOS 6.0, macOS 15.0, *) else {
return
}
#if canImport(Combine)
#if canImport(SwiftUI)
withAnimation {
self.objectWillChange.send()
}
#else
self.objectWillChange.send()
#endif
#endif
}
}
@@ -182,13 +170,20 @@ public final class LiveList<D: DynamicObject> {
applyFetchClauses: applyFetchClauses
)
#if canImport(Combine)
self.rawObjectWillChange = ObservableObjectPublisher()
if #available(iOS 13.0, tvOS 13.0, watchOS 6.0, macOS 15.0, *) {
#else
self.rawObjectWillChange = nil
#if canImport(Combine)
self.rawObjectWillChange = ObservableObjectPublisher()
#endif
#else
self.rawObjectWillChange = nil
#endif
}
else {
self.rawObjectWillChange = nil
}
// if let sectionIndexTransformer = sectionBy?.sectionIndexTransformer {
@@ -278,14 +273,16 @@ public final class LiveList<D: DynamicObject> {
// MARK: - LiveList: FetchedDiffableDataSourceSnapshotHandler
@available(iOS 13.0, tvOS 13.0, watchOS 6.0, macOS 15.0, *)
extension LiveList: FetchedDiffableDataSourceSnapshotHandler {
// MARK: FetchedDiffableDataSourceSnapshotHandler
internal func controller(_ controller: NSFetchedResultsController<NSFetchRequestResult>, didChangContentWith snapshot: NSDiffableDataSourceSnapshotReference) {
internal func controller(_ controller: NSFetchedResultsController<NSFetchRequestResult>, didChangContentWith snapshot: Internals.DiffableDataSourceSnapshot) {
self.snapshot = .init(snapshotReference: snapshot, context: controller.managedObjectContext)
self.snapshot = .init(
diffableSnapshot: snapshot,
context: controller.managedObjectContext
)
}
}
@@ -307,5 +304,3 @@ extension LiveList: LiveResult {
}
#endif
#endif

View File

@@ -23,143 +23,151 @@
// SOFTWARE.
//
#if canImport(SwiftUI) && canImport(Combine)
import CoreData
import Combine
import SwiftUI
#warning("TODO: autoupdating doesn't work yet")
@available(iOS 13.0, tvOS 13.0, watchOS 6.0, macOS 15.0, *)
@propertyWrapper
public struct LiveQuery<Result: LiveResult>: DynamicProperty {
// MARK: Public
@Environment(\.dataStack)
public var dataStack: DataStack
public typealias ObjectType = Result.ObjectType
// MARK: @propertyWrapper
public fileprivate(set) var wrappedValue: Result {
get {
return self.nonMutatingWrappedValue.wrappedValue
}
set {
self.nonMutatingWrappedValue = LazyNonmutating { newValue }
}
}
public var projectedValue: Result {
return self.wrappedValue
}
// MARK: DynamicProperty
public mutating func update() {
SwiftUI.withAnimation {
let dataStack = self.dataStack
if self.set(dataStack: dataStack) {
return
}
self.wrappedValue = self.newWrappedValue(dataStack)
}
}
// MARK: FilePrivate
fileprivate let newWrappedValue: (DataStack) -> Result
fileprivate init(newWrappedValue: @escaping (DataStack) -> Result) {
self.newWrappedValue = newWrappedValue
}
// MARK: Private
private var nonMutatingWrappedValue: LazyNonmutating<Result> = .init { fatalError() }
private var currentDataStack: DataStack?
private mutating func set(dataStack: DataStack) -> Bool {
guard self.currentDataStack != dataStack else {
return false
}
self.currentDataStack = dataStack
let newWrappedValue = self.newWrappedValue
self.nonMutatingWrappedValue = LazyNonmutating<Result> {
newWrappedValue(dataStack)
}
return true
}
// MARK: - LazyNonmutating
fileprivate final class LazyNonmutating<Value> {
// MARK: FilePrivate
lazy var wrappedValue: Value = self.initializer()
init(_ initializer: @escaping () -> Value) {
self.initializer = initializer
}
// MARK: Private
private var initializer: () -> Value
}
}
#if canImport(UIKit) || canImport(AppKit)
@available(iOS 13.0, tvOS 13.0, watchOS 6.0, macOS 15.0, *)
extension LiveQuery {
public init<D: DynamicObject>(liveList: LiveList<D>) where Result == LiveList<D> {
self.init(
newWrappedValue: { _ in liveList }
)
}
public init<D: DynamicObject>(_ clauseChain: FetchChainBuilder<D>) where Result == LiveList<D> {
self.init(
newWrappedValue: { $0.liveList(clauseChain) }
)
}
public init<D: DynamicObject>(_ clauseChain: SectionMonitorChainBuilder<D>) where Result == LiveList<D> {
self.init(
newWrappedValue: { $0.liveList(clauseChain) }
)
}
}
#endif
#endif
//#if canImport(SwiftUI) && canImport(Combine)
//
//import CoreData
//import Combine
//import SwiftUI
//
//
//#warning("TODO: autoupdating doesn't work yet")
//@available(iOS 13.0, tvOS 13.0, watchOS 6.0, macOS 15.0, *)
//@propertyWrapper
//public struct LiveQuery<Result: LiveResult>: DynamicProperty {
//
// // MARK: Public
//
// @Environment(\.dataStack)
// public var dataStack: DataStack
//
// public typealias ObjectType = Result.ObjectType
//
//
// // MARK: @propertyWrapper
//
// public var wrappedValue: Result {
//
// get {
//
// return self.backingWrapper!.wrappedValue
// }
// set {
//
// self.backingWrapper!.wrappedValue = newValue
// }
// }
//
// public var projectedValue: ObservedObject<Result>.Wrapper {
//
// return self.backingWrapper!.projectedValue
// }
//
//
// // MARK: DynamicProperty
//
// public mutating func update() {
//
// SwiftUI.withAnimation {
//
// let dataStack = self.dataStack
//
// if self.backingWrapper == nil {
//
// self.backingWrapper = ObservedObject(wrappedValue: self.newLiveResult(dataStack))
// }
// else {
//
// self.backingWrapper!.wrappedValue = self.newLiveResult(dataStack)
// }
// self.backingWrapper!.update()
// }
// }
//
//
// // MARK: FilePrivate
//
// fileprivate let newLiveResult: (DataStack) -> Result
//
// fileprivate init(newLiveResult: @escaping (DataStack) -> Result) {
//
// self.newLiveResult = newLiveResult
// }
//
//
// // MARK: Private
//
//// private var nonMutatingWrappedValue: LazyNonmutating<Result> = .init { fatalError() }
//
// private var currentDataStack: DataStack?
// private var backingWrapper: ObservedObject<Result>?
//
// private mutating func set(dataStack: DataStack) -> Bool {
//
// guard self.currentDataStack != dataStack else {
//
// return false
// }
// self.currentDataStack = dataStack
// if self.backingWrapper == nil {
//
// self.backingWrapper = ObservedObject(wrappedValue: self.newLiveResult(dataStack))
// }
// else {
//
// self.backingWrapper?.wrappedValue = self.newLiveResult(dataStack)
// }
// return true
// }
//
//
// // MARK: - LazyNonmutating
//
// fileprivate final class LazyNonmutating<Value> {
//
// // MARK: FilePrivate
//
// lazy var wrappedValue: Value = self.initializer()
//
// init(_ initializer: @escaping () -> Value) {
//
// self.initializer = initializer
// }
//
//
// // MARK: Private
//
// private var initializer: () -> Value
// }
//}
//
//
//#if canImport(UIKit) || canImport(AppKit)
//
//@available(iOS 13.0, tvOS 13.0, watchOS 6.0, macOS 15.0, *)
//extension LiveQuery {
//
// public init<D: DynamicObject>(liveList: LiveList<D>) where Result == LiveList<D> {
//
// self.init(
// newLiveResult: { _ in liveList }
// )
// }
//
// public init<D: DynamicObject>(_ clauseChain: FetchChainBuilder<D>) where Result == LiveList<D> {
//
// self.init(
// newLiveResult: { $0.liveList(clauseChain) }
// )
// }
//
// public init<D: DynamicObject>(_ clauseChain: SectionMonitorChainBuilder<D>) where Result == LiveList<D> {
//
// self.init(
// newLiveResult: { $0.liveList(clauseChain) }
// )
// }
//}
//
//#endif
//
//#endif