remov stateIDs

This commit is contained in:
John Estropia
2019-10-12 07:20:09 +09:00
parent 81dfb8e3e5
commit 5af0d17de4
31 changed files with 456 additions and 291 deletions

View File

@@ -29,11 +29,10 @@ import CoreData
// MARK: - AttributeProtocol
internal protocol AttributeProtocol: AnyObject {
internal protocol AttributeProtocol: PropertyProtocol {
static var attributeType: NSAttributeType { get }
var keyPath: KeyPathString { get }
var isOptional: Bool { get }
var isTransient: Bool { get }
var allowsExternalBinaryDataStorage: Bool { get }

View File

@@ -13,7 +13,7 @@ import Combine
// MARK: - LiveList: ObservableObject
@available(iOS 13.0, tvOS 13.0, watchOS 6.0, macOS 15.0, *)
@available(iOS 13.0, tvOS 13.0, watchOS 6.0, macOS 10.15, *)
extension CoreStoreObject: ObservableObject {
// MARK: ObservableObject

View File

@@ -116,6 +116,27 @@ open /*abstract*/ class CoreStoreObject: DynamicObject, Hashable {
internal let rawObject: CoreStoreManagedObject?
internal let isMeta: Bool
internal class func metaProperties(includeSuperclasses: Bool) -> [PropertyProtocol] {
func keyPaths(_ allKeyPaths: inout [PropertyProtocol], for dynamicType: CoreStoreObject.Type) {
allKeyPaths.append(contentsOf: dynamicType.meta.propertyProtocolsByName())
guard
includeSuperclasses,
case let superType as CoreStoreObject.Type = (dynamicType as AnyClass).superclass(),
superType != CoreStoreObject.self
else {
return
}
keyPaths(&allKeyPaths, for: superType)
}
var allKeyPaths: [PropertyProtocol] = []
keyPaths(&allKeyPaths, for: self)
return allKeyPaths
}
// MARK: Private
@@ -144,6 +165,22 @@ open /*abstract*/ class CoreStoreObject: DynamicObject, Hashable {
}
}
}
private func propertyProtocolsByName() -> [PropertyProtocol] {
Internals.assert(self.isMeta, "'propertyProtocolsByName()' accessed from non-meta instance of \(Internals.typeName(self))")
let cacheKey = ObjectIdentifier(Self.self)
if let properties = Static.propertiesCache[cacheKey] {
return properties
}
let values: [PropertyProtocol] = Mirror(reflecting: self)
.children
.compactMap({ $0.value as? PropertyProtocol })
Static.propertiesCache[cacheKey] = values
return values
}
}
@@ -187,4 +224,5 @@ fileprivate enum Static {
// MARK: FilePrivate
fileprivate static var metaCache: [ObjectIdentifier: Any] = [:]
fileprivate static var propertiesCache: [ObjectIdentifier: [PropertyProtocol]] = [:]
}

View File

@@ -283,9 +283,9 @@ public final class CoreStoreSchema: DynamicSchema {
func createProperties(for type: CoreStoreObject.Type) -> [NSPropertyDescription] {
var propertyDescriptions: [NSPropertyDescription] = []
for child in Mirror(reflecting: type.meta).children {
for property in type.metaProperties(includeSuperclasses: false) {
switch child.value {
switch property {
case let attribute as AttributeProtocol:
Internals.assert(
@@ -378,9 +378,10 @@ public final class CoreStoreSchema: DynamicSchema {
for (entity, entityDescription) in entityDescriptionsByEntity {
let relationshipsByName = relationshipsByNameByEntity[entity]!
for child in Mirror(reflecting: (entity.type as! CoreStoreObject.Type).meta).children {
let entityType = entity.type as! CoreStoreObject.Type
for property in entityType.metaProperties(includeSuperclasses: false) {
switch child.value {
switch property {
case let relationship as RelationshipProtocol:
let (destinationType, destinationKeyPath) = relationship.inverse

View File

@@ -31,7 +31,7 @@ import CoreData
// MARK: - DataStack
@available(iOS 13.0, tvOS 13.0, watchOS 6.0, macOS 15.0, *)
@available(iOS 13.0, tvOS 13.0, watchOS 6.0, macOS 10.15, *)
extension DataStack {
public func liveList<D>(_ from: From<D>, _ fetchClauses: FetchClause...) -> LiveList<D> {

View File

@@ -48,7 +48,7 @@ import CoreData
// self.tableView = tableView
// self.cellProvider = cellProvider
//
// if #available(iOS 13.0, tvOS 13.0, watchOS 6.0, macOS 15.0, *) {
// if #available(iOS 13.0, tvOS 13.0, watchOS 6.0, macOS 10.15, *) {
//
// self.rawDataSource = UITableViewDiffableDataSource<String, D.ObjectID>(
// tableView: tableView,
@@ -71,7 +71,7 @@ import CoreData
// 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, *) {
// if #available(iOS 13.0, tvOS 13.0, watchOS 6.0, macOS 10.15, *) {
//
// self.rawDataSource! as! UITableViewDiffableDataSource<String, D>
//
@@ -95,7 +95,7 @@ import CoreData
// private let cellProvider: (UITableView, IndexPath, ObjectType) -> UITableViewCell?
// private let rawDataSource: Any?
//
// @available(iOS 13.0, tvOS 13.0, watchOS 6.0, macOS 15.0, *)
// @available(iOS 13.0, tvOS 13.0, watchOS 6.0, macOS 10.15, *)
// private var diffableDataSource: UITableViewDiffableDataSource<String, D.ObjectID> {
//
// return self.rawDataSource! as! UITableViewDiffableDataSource<String, D.ObjectID>

View File

@@ -0,0 +1,34 @@
//
// DiffableDataSourceSnapshotProtocol.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.
//
import Foundation
import CoreData
// MARK: - DiffableDataSourceSnapshotProtocol
internal protocol DiffableDataSourceSnapshotProtocol {
}

View File

@@ -74,10 +74,10 @@ extension DynamicObject {
// MARK: Internal
internal static func keyPathBuilder() -> DynamicObjectMeta<Never, Self> {
return .init(keyPathString: "SELF")
}
// internal static func keyPathBuilder() -> DynamicObjectMeta<Never, Self> {
//
// return .init(keyPathString: "SELF")
// }
internal func runtimeType() -> Self.Type {

View File

@@ -2,8 +2,25 @@
// EnvironmentKeys.swift
// CoreStore
//
// Created by John Rommel Estropia on 2019/10/05.
// Copyright © 2019 John Rommel Estropia. All rights reserved.
// 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(SwiftUI)
@@ -13,7 +30,7 @@ import SwiftUI
// MARK: - DataStackEnvironmentKey
@available(iOS 13.0, tvOS 13.0, watchOS 6.0, macOS 15.0, *)
@available(iOS 13.0, tvOS 13.0, watchOS 6.0, macOS 10.15, *)
public struct DataStackEnvironmentKey: EnvironmentKey {
// MARK: Public
@@ -27,7 +44,7 @@ public struct DataStackEnvironmentKey: EnvironmentKey {
// MARK: - EnvironmentValues
@available(iOS 13.0, tvOS 13.0, watchOS 6.0, macOS 15.0, *)
@available(iOS 13.0, tvOS 13.0, watchOS 6.0, macOS 10.15, *)
extension EnvironmentValues {
// MARK: Public

View File

@@ -48,18 +48,14 @@ extension Internals {
// MARK: Internal
internal let nextStateTag: UUID
init() {
self.structure = .init()
self.nextStateTag = .init()
}
init(sections: [NSFetchedResultsSectionInfo], previousStateTag: UUID, nextStateTag: UUID) {
init(sections: [NSFetchedResultsSectionInfo]) {
self.structure = .init(sections: sections, previousStateTag: previousStateTag)
self.nextStateTag = nextStateTag
self.structure = .init(sections: sections)
}
var numberOfItems: Int {
@@ -77,21 +73,11 @@ extension Internals {
return self.structure.allSectionIDs
}
var allSectionStateIDs: [SectionStateID] {
return self.structure.allSectionStateIDs
}
var allItemIDs: [NSManagedObjectID] {
return self.structure.allItemIDs
}
var allItemStateIDs: [ItemStateID] {
return self.structure.allItemStateIDs
}
func numberOfItems(inSection identifier: String) -> Int {
return self.itemIDs(inSection: identifier).count
@@ -102,21 +88,11 @@ extension Internals {
return self.structure.items(in: identifier)
}
func itemStateIDs(inSection identifier: String) -> [ItemStateID] {
return self.structure.itemStateIDs(in: identifier)
}
func sectionIDs(containingItem identifier: NSManagedObjectID) -> String? {
return self.structure.section(containing: identifier)
}
func sectionStateIDs(containingItem identifier: NSManagedObjectID) -> SectionStateID? {
return self.structure.sectionStateID(containing: identifier)
}
func indexOfItemID(_ identifier: NSManagedObjectID) -> Int? {
return self.structure.allItemIDs.firstIndex(of: identifier)
@@ -127,24 +103,19 @@ extension Internals {
return self.structure.allSectionIDs.firstIndex(of: identifier)
}
func itemIDs(where stateCondition: @escaping (UUID) -> Bool) -> [NSManagedObjectID] {
mutating func appendItems(_ identifiers: [NSManagedObjectID], toSection sectionIdentifier: String?) {
return self.structure.itemsIDs(where: stateCondition)
self.structure.append(itemIDs: identifiers, to: sectionIdentifier)
}
mutating func appendItems(_ identifiers: [NSManagedObjectID], toSection sectionIdentifier: String?, nextStateTag: UUID) {
mutating func insertItems(_ identifiers: [NSManagedObjectID], beforeItem beforeIdentifier: NSManagedObjectID) {
self.structure.append(itemIDs: identifiers, to: sectionIdentifier, nextStateTag: nextStateTag)
self.structure.insert(itemIDs: identifiers, before: beforeIdentifier)
}
mutating func insertItems(_ identifiers: [NSManagedObjectID], beforeItem beforeIdentifier: NSManagedObjectID, nextStateTag: UUID) {
mutating func insertItems(_ identifiers: [NSManagedObjectID], afterItem afterIdentifier: NSManagedObjectID) {
self.structure.insert(itemIDs: identifiers, before: beforeIdentifier, nextStateTag: nextStateTag)
}
mutating func insertItems(_ identifiers: [NSManagedObjectID], afterItem afterIdentifier: NSManagedObjectID, nextStateTag: UUID) {
self.structure.insert(itemIDs: identifiers, after: afterIdentifier, nextStateTag: nextStateTag)
self.structure.insert(itemIDs: identifiers, after: afterIdentifier)
}
mutating func deleteItems(_ identifiers: [NSManagedObjectID]) {
@@ -172,19 +143,19 @@ extension Internals {
self.structure.update(itemIDs: identifiers, nextStateTag: nextStateTag)
}
mutating func appendSections(_ identifiers: [String], nextStateTag: UUID) {
mutating func appendSections(_ identifiers: [String]) {
self.structure.append(sectionIDs: identifiers, nextStateTag: nextStateTag)
self.structure.append(sectionIDs: identifiers)
}
mutating func insertSections(_ identifiers: [String], beforeSection toIdentifier: String, nextStateTag: UUID) {
mutating func insertSections(_ identifiers: [String], beforeSection toIdentifier: String) {
self.structure.insert(sectionIDs: identifiers, before: toIdentifier, nextStateTag: nextStateTag)
self.structure.insert(sectionIDs: identifiers, before: toIdentifier)
}
mutating func insertSections(_ identifiers: [String], afterSection toIdentifier: String, nextStateTag: UUID) {
mutating func insertSections(_ identifiers: [String], afterSection toIdentifier: String) {
self.structure.insert(sectionIDs: identifiers, after: toIdentifier, nextStateTag: nextStateTag)
self.structure.insert(sectionIDs: identifiers, after: toIdentifier)
}
mutating func deleteSections(_ identifiers: [String]) {
@@ -271,7 +242,7 @@ extension Internals {
self.sections = []
}
init(sections: [NSFetchedResultsSectionInfo], previousStateTag: UUID) {
init(sections: [NSFetchedResultsSectionInfo]) {
self.sections = sections.map {
@@ -279,8 +250,7 @@ extension Internals {
id: $0.name,
items: $0.objects?
.compactMap({ ($0 as? NSManagedObject)?.objectID })
.map({ Item(id: $0, stateTag: previousStateTag) }) ?? [],
stateTag: previousStateTag
.map({ Item(id: $0) }) ?? []
)
}
}
@@ -290,21 +260,11 @@ extension Internals {
return self.sections.map({ $0.id })
}
var allSectionStateIDs: [SectionStateID] {
return self.sections.map({ $0.stateID })
}
var allItemIDs: [NSManagedObjectID] {
return self.sections.lazy.flatMap({ $0.elements }).map({ $0.id })
}
var allItemStateIDs: [ItemStateID] {
return self.sections.lazy.flatMap({ $0.elements }).map({ $0.stateID })
}
func items(in sectionID: String) -> [NSManagedObjectID] {
guard let sectionIndex = self.sectionIndex(of: sectionID) else {
@@ -314,33 +274,12 @@ extension Internals {
return self.sections[sectionIndex].elements.map({ $0.id })
}
func itemsIDs(where stateCondition: @escaping (UUID) -> Bool) -> [NSManagedObjectID] {
return self.sections.lazy
.flatMap({ $0.elements.filter({ stateCondition($0.stateTag) }) })
.map({ $0.id })
}
func itemStateIDs(in sectionID: String) -> [ItemStateID] {
guard let sectionIndex = self.sectionIndex(of: sectionID) else {
Internals.abort("Section \"\(sectionID)\" does not exist")
}
return self.sections[sectionIndex].elements.map({ $0.stateID })
}
func section(containing itemID: NSManagedObjectID) -> String? {
return self.itemPositionMap()[itemID]?.section.id
}
func sectionStateID(containing itemID: NSManagedObjectID) -> SectionStateID? {
return self.itemPositionMap()[itemID]?.section.stateID
}
mutating func append(itemIDs: [NSManagedObjectID], to sectionID: String?, nextStateTag: UUID) {
mutating func append(itemIDs: [NSManagedObjectID], to sectionID: String?) {
let index: Array<Section>.Index
if let sectionID = sectionID {
@@ -360,22 +299,22 @@ extension Internals {
}
index = section.index(before: section.endIndex)
}
let items = itemIDs.lazy.map({ Item(id: $0, stateTag: nextStateTag) })
let items = itemIDs.lazy.map({ Item(id: $0) })
self.sections[index].elements.append(contentsOf: items)
}
mutating func insert(itemIDs: [NSManagedObjectID], before beforeItemID: NSManagedObjectID, nextStateTag: UUID) {
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(id: $0, stateTag: nextStateTag) })
let items = itemIDs.lazy.map({ Item(id: $0) })
self.sections[itemPosition.sectionIndex].elements
.insert(contentsOf: items, at: itemPosition.itemRelativeIndex)
}
mutating func insert(itemIDs: [NSManagedObjectID], after afterItemID: NSManagedObjectID, nextStateTag: UUID) {
mutating func insert(itemIDs: [NSManagedObjectID], after afterItemID: NSManagedObjectID) {
guard let itemPosition = self.itemPositionMap()[afterItemID] else {
@@ -383,7 +322,7 @@ extension Internals {
}
let itemIndex = self.sections[itemPosition.sectionIndex].elements
.index(after: itemPosition.itemRelativeIndex)
let items = itemIDs.lazy.map({ Item(id: $0, stateTag: nextStateTag) })
let items = itemIDs.lazy.map({ Item(id: $0) })
self.sections[itemPosition.sectionIndex].elements
.insert(contentsOf: items, at: itemIndex)
}
@@ -459,34 +398,34 @@ extension Internals {
continue
}
self.sections[itemPosition.sectionIndex]
.elements[itemPosition.itemRelativeIndex].stateTag = nextStateTag
.elements[itemPosition.itemRelativeIndex].isReloaded = true
}
}
mutating func append(sectionIDs: [String], nextStateTag: UUID) {
mutating func append(sectionIDs: [String]) {
let newSections = sectionIDs.lazy.map({ Section(id: $0, stateTag: nextStateTag) })
let newSections = sectionIDs.lazy.map({ Section(id: $0) })
self.sections.append(contentsOf: newSections)
}
mutating func insert(sectionIDs: [String], before beforeSectionID: String, nextStateTag: UUID) {
mutating func insert(sectionIDs: [String], before beforeSectionID: String) {
guard let sectionIndex = self.sectionIndex(of: beforeSectionID) else {
Internals.abort("Section \"\(beforeSectionID)\" does not exist")
}
let newSections = sectionIDs.lazy.map({ Section(id: $0, stateTag: nextStateTag) })
let newSections = sectionIDs.lazy.map({ Section(id: $0) })
self.sections.insert(contentsOf: newSections, at: sectionIndex)
}
mutating func insert(sectionIDs: [String], after afterSectionID: String, nextStateTag: UUID) {
mutating func insert(sectionIDs: [String], after afterSectionID: String) {
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(id: $0, stateTag: nextStateTag) })
let newSections = sectionIDs.lazy.map({ Section(id: $0) })
self.sections.insert(contentsOf: newSections, at: sectionIndex)
}
@@ -533,7 +472,7 @@ extension Internals {
continue
}
self.sections[sectionIndex].stateTag = nextStateTag
self.sections[sectionIndex].isReloaded = true
}
}
@@ -589,22 +528,17 @@ extension Internals {
fileprivate struct Item: Identifiable, Equatable {
var stateTag: UUID
var isReloaded: Bool
init(id: NSManagedObjectID, stateTag: UUID) {
init(id: NSManagedObjectID, isReloaded: Bool = false) {
self.id = id
self.stateTag = stateTag
}
var stateID: ItemStateID {
return .init(id: self.id, stateTag: self.stateTag)
self.isReloaded = isReloaded
}
func isContentEqual(to source: Item) -> Bool {
return self.id == source.id && self.stateTag == source.stateTag
return !self.isReloaded && self.id == source.id
}
// MARK: Identifiable
@@ -618,27 +552,22 @@ extension Internals {
fileprivate struct Section: Identifiable, Equatable {
var elements: [Item] = []
var stateTag: UUID
var isReloaded: Bool
init(id: String, items: [Item] = [], stateTag: UUID) {
init(id: String, items: [Item] = [], isReloaded: Bool = false) {
self.id = id
self.elements = items
self.stateTag = stateTag
self.isReloaded = isReloaded
}
init<S: Sequence>(source: Section, elements: S) where S.Element == Item {
self.init(id: source.id, items: Array(elements), stateTag: source.stateTag)
}
var stateID: SectionStateID {
return .init(id: self.id, stateTag: self.stateTag)
self.init(id: source.id, items: Array(elements), isReloaded: source.isReloaded)
}
func isContentEqual(to source: Section) -> Bool {
return self.id == source.id && self.stateTag == source.stateTag
return !self.isReloaded && self.id == source.id
}
// MARK: Identifiable

View File

@@ -77,7 +77,7 @@ extension Internals {
// #if canImport(UIKit) || canImport(AppKit)
//
// if #available(iOS 13.0, tvOS 13.0, watchOS 6.0, macOS 15.0, *) {
// if #available(iOS 13.0, tvOS 13.0, watchOS 6.0, macOS 10.15, *) {
//
// return
// }
@@ -96,7 +96,7 @@ extension Internals {
// #if canImport(UIKit) || canImport(AppKit)
//
// @available(iOS 13.0, tvOS 13.0, watchOS 6.0, macOS 15.0, *)
// @available(iOS 13.0, tvOS 13.0, watchOS 6.0, macOS 10.15, *)
// @objc
// dynamic func controller(_ controller: NSFetchedResultsController<NSFetchRequestResult>, didChangeContentWith snapshot: NSDiffableDataSourceSnapshotReference) {
//
@@ -111,48 +111,12 @@ extension Internals {
@objc
dynamic func controllerDidChangeContent(_ controller: NSFetchedResultsController<NSFetchRequestResult>) {
let nextStateTag: UUID = .init()
var dataSourceSnapshot = Internals.DiffableDataSourceSnapshot(
sections: controller.sections ?? [],
previousStateTag: self.previousStateTag,
nextStateTag: nextStateTag
)
dataSourceSnapshot.reloadItems(self.reloadedItemIDs, nextStateTag: nextStateTag)
dataSourceSnapshot.reloadSections(self.reloadedSectionIDs, nextStateTag: nextStateTag)
self.handler?.controller(
controller,
didChangContentWith: dataSourceSnapshot
didChangContentWith: Internals.DiffableDataSourceSnapshot(
sections: controller.sections ?? []
)
)
self.previousStateTag = nextStateTag
}
@objc
dynamic func controller(_ controller: NSFetchedResultsController<NSFetchRequestResult>, didChange anObject: Any, at indexPath: IndexPath?, for type: NSFetchedResultsChangeType, newIndexPath: IndexPath?) {
let managedObject = anObject as! NSManagedObject
self.reloadedItemIDs.insert(managedObject.objectID)
}
@objc
dynamic func controller(_ controller: NSFetchedResultsController<NSFetchRequestResult>, didChange sectionInfo: NSFetchedResultsSectionInfo, atSectionIndex sectionIndex: Int, for type: NSFetchedResultsChangeType) {
self.reloadedSectionIDs.insert(sectionInfo.name)
}
// MARK: Private
private var previousStateTag: UUID = .init() {
didSet {
self.reloadedItemIDs = []
self.reloadedSectionIDs = []
}
}
private var reloadedItemIDs: Set<NSManagedObjectID> = []
private var reloadedSectionIDs: Set<String> = []
}
}

View File

@@ -128,17 +128,17 @@ public struct ListSnapshot<O: DynamicObject>: SnapshotResult, RandomAccessCollec
public mutating func appendItems(_ identifiers: [ItemID], toSection sectionIdentifier: SectionID? = nil) {
self.diffableSnapshot.appendItems(identifiers, toSection: sectionIdentifier, nextStateTag: .init())
self.diffableSnapshot.appendItems(identifiers, toSection: sectionIdentifier)
}
public mutating func insertItems(_ identifiers: [ItemID], beforeItem beforeIdentifier: ItemID) {
self.diffableSnapshot.insertItems(identifiers, beforeItem: beforeIdentifier, nextStateTag: .init())
self.diffableSnapshot.insertItems(identifiers, beforeItem: beforeIdentifier)
}
public mutating func insertItems(_ identifiers: [ItemID], afterItem afterIdentifier: ItemID) {
self.diffableSnapshot.insertItems(identifiers, afterItem: afterIdentifier, nextStateTag: .init())
self.diffableSnapshot.insertItems(identifiers, afterItem: afterIdentifier)
}
public mutating func deleteItems(_ identifiers: [ItemID]) {
@@ -168,17 +168,17 @@ public struct ListSnapshot<O: DynamicObject>: SnapshotResult, RandomAccessCollec
public mutating func appendSections(_ identifiers: [SectionID]) {
self.diffableSnapshot.appendSections(identifiers, nextStateTag: .init())
self.diffableSnapshot.appendSections(identifiers)
}
public mutating func insertSections(_ identifiers: [SectionID], beforeSection toIdentifier: SectionID) {
self.diffableSnapshot.insertSections(identifiers, beforeSection: toIdentifier, nextStateTag: .init())
self.diffableSnapshot.insertSections(identifiers, beforeSection: toIdentifier)
}
public mutating func insertSections(_ identifiers: [SectionID], afterSection toIdentifier: SectionID) {
self.diffableSnapshot.insertSections(identifiers, afterSection: toIdentifier, nextStateTag: .init())
self.diffableSnapshot.insertSections(identifiers, afterSection: toIdentifier)
}
public mutating func deleteSections(_ identifiers: [SectionID]) {
@@ -263,16 +263,6 @@ public struct ListSnapshot<O: DynamicObject>: SnapshotResult, RandomAccessCollec
self.diffableSnapshot = diffableSnapshot
self.context = context
}
internal var nextStateTag: UUID {
return self.diffableSnapshot.nextStateTag
}
internal func itemIDs(where stateCondition: @escaping (UUID) -> Bool) -> [ItemID] {
return self.diffableSnapshot.itemIDs(where: stateCondition)
}
// MARK: Private

View File

@@ -49,10 +49,7 @@ public final class LiveList<O: DynamicObject>: Hashable {
willSet {
if #available(iOS 13.0, tvOS 13.0, watchOS 6.0, macOS 15.0, *) {
self.willChange()
}
self.willChange()
}
}
@@ -267,7 +264,7 @@ public final class LiveList<O: DynamicObject>: Hashable {
applyFetchClauses: applyFetchClauses
)
if #available(iOS 13.0, tvOS 13.0, watchOS 6.0, macOS 15.0, *) {
if #available(iOS 13.0, tvOS 13.0, watchOS 6.0, macOS 10.15, *) {
#if canImport(Combine)
self.rawObjectWillChange = ObservableObjectPublisher()
@@ -318,20 +315,33 @@ extension LiveList: FetchedDiffableDataSourceSnapshotHandler {
#if canImport(Combine)
import Combine
@available(iOS 13.0, tvOS 13.0, watchOS 6.0, macOS 10.15, *)
extension LiveList: ObservableObject {}
#endif
// MARK: - LiveList: LiveResult
@available(iOS 13.0, tvOS 13.0, watchOS 6.0, macOS 15.0, *)
extension LiveList: LiveResult {
// MARK: ObservableObject
#if canImport(Combine)
@available(iOS 13.0, tvOS 13.0, watchOS 6.0, macOS 10.15, *)
public var objectWillChange: ObservableObjectPublisher {
return self.rawObjectWillChange! as! ObservableObjectPublisher
}
#endif
public func willChange() {
guard #available(iOS 13.0, tvOS 13.0, watchOS 6.0, macOS 10.15, *) else {
return
}
#if canImport(Combine)
#if canImport(SwiftUI)
@@ -340,11 +350,10 @@ extension LiveList: LiveResult {
self.objectWillChange.send()
}
#else
self.objectWillChange.send()
#endif
self.objectWillChange.send()
#endif
}
@@ -353,5 +362,3 @@ extension LiveList: LiveResult {
// TODO:
}
}
#endif

View File

@@ -100,7 +100,7 @@ public final class LiveObject<O: DynamicObject>: Identifiable, Hashable {
self.id = id
self.context = context
if #available(iOS 13.0, tvOS 13.0, watchOS 6.0, macOS 15.0, *) {
if #available(iOS 13.0, tvOS 13.0, watchOS 6.0, macOS 10.15, *) {
#if canImport(Combine)
self.rawObjectWillChange = ObservableObjectPublisher()
@@ -132,10 +132,7 @@ public final class LiveObject<O: DynamicObject>: Identifiable, Hashable {
return
}
self.$lazySnapshot.reset({ initializer(id, context) })
if #available(iOS 13.0, tvOS 13.0, watchOS 6.0, macOS 15.0, *) {
self.willChange()
}
self.willChange()
}
)
@@ -156,20 +153,33 @@ public final class LiveObject<O: DynamicObject>: Identifiable, Hashable {
#if canImport(Combine)
import Combine
@available(iOS 13.0, tvOS 13.0, watchOS 6.0, macOS 10.15, *)
extension LiveObject: ObservableObject {}
#endif
// MARK: - LiveObject: LiveResult
@available(iOS 13.0, tvOS 13.0, watchOS 6.0, macOS 15.0, *)
extension LiveObject: LiveResult {
// MARK: ObservableObject
#if canImport(Combine)
@available(iOS 13.0, tvOS 13.0, watchOS 6.0, macOS 10.15, *)
public var objectWillChange: ObservableObjectPublisher {
return self.rawObjectWillChange! as! ObservableObjectPublisher
}
#endif
public func willChange() {
guard #available(iOS 13.0, tvOS 13.0, watchOS 6.0, macOS 10.15, *) else {
return
}
#if canImport(Combine)
#if canImport(SwiftUI)
@@ -178,11 +188,10 @@ extension LiveObject: LiveResult {
self.objectWillChange.send()
}
#else
self.objectWillChange.send()
#endif
self.objectWillChange.send()
#endif
}
@@ -192,8 +201,6 @@ extension LiveObject: LiveResult {
}
}
#endif
// MARK: - LiveObject where O: NSManagedObject

View File

@@ -31,7 +31,7 @@
//
//
//#warning("TODO: autoupdating doesn't work yet")
//@available(iOS 13.0, tvOS 13.0, watchOS 6.0, macOS 15.0, *)
//@available(iOS 13.0, tvOS 13.0, watchOS 6.0, macOS 10.15, *)
//@propertyWrapper
//public struct LiveQuery<Result: LiveResult>: DynamicProperty {
//
@@ -143,7 +143,7 @@
//
//#if canImport(UIKit) || canImport(AppKit)
//
//@available(iOS 13.0, tvOS 13.0, watchOS 6.0, macOS 15.0, *)
//@available(iOS 13.0, tvOS 13.0, watchOS 6.0, macOS 10.15, *)
//extension LiveQuery {
//
// public init<D: DynamicObject>(liveList: LiveList<D>) where Result == LiveList<D> {

View File

@@ -36,8 +36,7 @@ import AppKit
// MARK: - LiveResult
@available(iOS 13.0, tvOS 13.0, watchOS 6.0, macOS 15.0, *)
public protocol LiveResult: ObservableObject {
public protocol LiveResult: AnyObject {
associatedtype ObjectType
associatedtype SnapshotType: SnapshotResult where SnapshotType.ObjectType == Self.ObjectType

View File

@@ -0,0 +1,9 @@
//
// ObjectRepresentation.swift
// CoreStore
//
// Created by John Estropia on 2019/10/11.
// Copyright © 2019 John Rommel Estropia. All rights reserved.
//
import Foundation

View File

@@ -0,0 +1,35 @@
//
// PropertyProtocol.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.
//
import Foundation
import CoreData
// MARK: - PropertyProtocol
internal protocol PropertyProtocol: AnyObject {
var keyPath: KeyPathString { get }
}

View File

@@ -249,11 +249,15 @@ public enum RelationshipContainer<O: CoreStoreObject> {
// MARK: RelationshipKeyPathStringConvertible
public typealias ReturnValueType = DestinationValueType?
// MARK: PropertyProtocol
internal let keyPath: KeyPathString
// MARK: RelationshipProtocol
internal let keyPath: KeyPathString
internal let isToMany = false
internal let isOrdered = false
internal let deleteRule: NSDeleteRule
@@ -540,11 +544,15 @@ public enum RelationshipContainer<O: CoreStoreObject> {
// MARK: RelationshipKeyPathStringConvertible
public typealias ReturnValueType = [DestinationValueType]
// MARK: PropertyProtocol
internal let keyPath: KeyPathString
// MARK: RelationshipProtocol
internal let keyPath: KeyPathString
internal let isToMany = true
internal let isOptional = true
internal let isOrdered = true
@@ -837,11 +845,15 @@ public enum RelationshipContainer<O: CoreStoreObject> {
// MARK: RelationshipKeyPathStringConvertible
public typealias ReturnValueType = Set<DestinationValueType>
// MARK: PropertyProtocol
internal let keyPath: KeyPathString
// MARK: RelationshipProtocol
internal let keyPath: KeyPathString
internal let isToMany = true
internal let isOptional = true
internal let isOrdered = false

View File

@@ -29,9 +29,8 @@ import CoreData
// MARK: - RelationshipProtocol
internal protocol RelationshipProtocol: AnyObject {
var keyPath: KeyPathString { get }
internal protocol RelationshipProtocol: PropertyProtocol {
var isToMany: Bool { get }
var isOrdered: Bool { get }
var deleteRule: NSDeleteRule { get }

View File

@@ -36,7 +36,6 @@ import AppKit
// MARK: - SnapshotResult
@available(iOS 13.0, tvOS 13.0, watchOS 6.0, macOS 15.0, *)
public protocol SnapshotResult {
associatedtype ObjectType: DynamicObject

View File

@@ -209,6 +209,11 @@ public enum TransformableContainer<O: CoreStoreObject> {
public typealias ReturnValueType = DestinationValueType
// MARK: PropertyProtocol
internal let keyPath: KeyPathString
// MARK: AttributeProtocol
internal static var attributeType: NSAttributeType {
@@ -216,7 +221,6 @@ public enum TransformableContainer<O: CoreStoreObject> {
return .transformableAttributeType
}
internal let keyPath: KeyPathString
internal let isOptional = false
internal let isTransient: Bool
internal let allowsExternalBinaryDataStorage: Bool
@@ -427,6 +431,11 @@ public enum TransformableContainer<O: CoreStoreObject> {
public typealias ReturnValueType = DestinationValueType?
// MARK: PropertyProtocol
internal let keyPath: KeyPathString
// MARK: AttributeProtocol
internal static var attributeType: NSAttributeType {
@@ -434,7 +443,6 @@ public enum TransformableContainer<O: CoreStoreObject> {
return .transformableAttributeType
}
internal let keyPath: KeyPathString
internal let isOptional = true
internal let isTransient: Bool
internal let allowsExternalBinaryDataStorage: Bool

View File

@@ -202,6 +202,11 @@ public enum ValueContainer<O: CoreStoreObject> {
// MARK: AttributeKeyPathStringConvertible
public typealias ReturnValueType = DestinationValueType
// MARK: PropertyProtocol
internal let keyPath: KeyPathString
// MARK: AttributeProtocol
@@ -210,8 +215,7 @@ public enum ValueContainer<O: CoreStoreObject> {
return V.cs_rawAttributeType
}
internal let keyPath: KeyPathString
internal let isOptional = false
internal let isTransient: Bool
internal let allowsExternalBinaryDataStorage = false
@@ -420,6 +424,11 @@ public enum ValueContainer<O: CoreStoreObject> {
// MARK: AttributeKeyPathStringConvertible
public typealias ReturnValueType = DestinationValueType?
// MARK: PropertyProtocol
internal let keyPath: KeyPathString
// MARK: AttributeProtocol
@@ -429,7 +438,6 @@ public enum ValueContainer<O: CoreStoreObject> {
return V.cs_rawAttributeType
}
internal let keyPath: KeyPathString
internal let isOptional = true
internal let isTransient: Bool
internal let allowsExternalBinaryDataStorage = false