fix tests

This commit is contained in:
John Estropia
2026-07-15 19:54:47 +09:00
parent 890e150b95
commit 1ea9ad7c4a
12 changed files with 109 additions and 58 deletions
+2 -2
View File
@@ -3047,7 +3047,7 @@
SWIFT_COMPILATION_MODE = singlefile; SWIFT_COMPILATION_MODE = singlefile;
SWIFT_OPTIMIZATION_LEVEL = "-Onone"; SWIFT_OPTIMIZATION_LEVEL = "-Onone";
SWIFT_SWIFT3_OBJC_INFERENCE = Off; SWIFT_SWIFT3_OBJC_INFERENCE = Off;
SWIFT_VERSION = 5.0; SWIFT_VERSION = 6.0;
TARGETED_DEVICE_FAMILY = "1,2"; TARGETED_DEVICE_FAMILY = "1,2";
TVOS_DEPLOYMENT_TARGET = 17.0; TVOS_DEPLOYMENT_TARGET = 17.0;
VERSIONING_SYSTEM = "apple-generic"; VERSIONING_SYSTEM = "apple-generic";
@@ -3112,7 +3112,7 @@
SWIFT_COMPILATION_MODE = wholemodule; SWIFT_COMPILATION_MODE = wholemodule;
SWIFT_OPTIMIZATION_LEVEL = "-O"; SWIFT_OPTIMIZATION_LEVEL = "-O";
SWIFT_SWIFT3_OBJC_INFERENCE = Off; SWIFT_SWIFT3_OBJC_INFERENCE = Off;
SWIFT_VERSION = 5.0; SWIFT_VERSION = 6.0;
TARGETED_DEVICE_FAMILY = "1,2"; TARGETED_DEVICE_FAMILY = "1,2";
TVOS_DEPLOYMENT_TARGET = 17.0; TVOS_DEPLOYMENT_TARGET = 17.0;
VALIDATE_PRODUCT = YES; VALIDATE_PRODUCT = YES;
@@ -50,11 +50,11 @@ extension Advanced.EvolutionDemo {
} }
self.mutateItemAtIndex = { index in self.mutateItemAtIndex = { index in
let object = listPublisher.snapshot[index] let persistentID = listPublisher.snapshot[index].persistentID()
dataStack.perform( dataStack.perform(
asynchronous: { transaction in asynchronous: { transaction in
object persistentID
.asEditable(in: transaction)? .asEditable(in: transaction)?
.mutate(in: transaction) .mutate(in: transaction)
}, },
@@ -26,7 +26,7 @@ extension Classic.ColorsDemo {
/** /**
Sample 2: We can end monitoring updates anytime. `removeObserver()` was called here for illustration purposes only. `ListMonitor`s safely remove deallocated observers automatically. Sample 2: We can end monitoring updates anytime. `removeObserver()` was called here for illustration purposes only. `ListMonitor`s safely remove deallocated observers automatically.
*/ */
deinit { isolated deinit {
self.listMonitor.removeObserver(self) self.listMonitor.removeObserver(self)
} }
@@ -40,60 +40,87 @@ extension Classic.ColorsDemo {
typealias ListEntityType = Classic.ColorsDemo.Palette typealias ListEntityType = Classic.ColorsDemo.Palette
func listMonitorWillChange(_ monitor: ListMonitor<Classic.ColorsDemo.Palette>) { nonisolated func listMonitorWillChange(_ monitor: ListMonitor<Classic.ColorsDemo.Palette>) {
MainActor.assumeIsolated {
self.tableView.beginUpdates() self.tableView.beginUpdates()
} }
}
func listMonitorDidChange(_ monitor: ListMonitor<Classic.ColorsDemo.Palette>) { nonisolated func listMonitorDidChange(_ monitor: ListMonitor<Classic.ColorsDemo.Palette>) {
MainActor.assumeIsolated {
self.tableView.endUpdates() self.tableView.endUpdates()
} }
}
func listMonitorDidRefetch(_ monitor: ListMonitor<Classic.ColorsDemo.Palette>) { nonisolated func listMonitorDidRefetch(_ monitor: ListMonitor<Classic.ColorsDemo.Palette>) {
MainActor.assumeIsolated {
self.tableView.reloadData() self.tableView.reloadData()
} }
}
// MARK: ListObjectObserver // MARK: ListObjectObserver
func listMonitor(_ monitor: ListMonitor<ListEntityType>, didInsertObject object: ListEntityType, toIndexPath indexPath: IndexPath) { nonisolated func listMonitor(_ monitor: ListMonitor<ListEntityType>, didInsertObject object: ListEntityType, toIndexPath indexPath: IndexPath) {
MainActor.assumeIsolated {
self.tableView.insertRows(at: [indexPath], with: .automatic) self.tableView.insertRows(at: [indexPath], with: .automatic)
} }
}
func listMonitor(_ monitor: ListMonitor<ListEntityType>, didDeleteObject object: ListEntityType, fromIndexPath indexPath: IndexPath) { nonisolated func listMonitor(_ monitor: ListMonitor<ListEntityType>, didDeleteObject object: ListEntityType, fromIndexPath indexPath: IndexPath) {
MainActor.assumeIsolated {
self.tableView.deleteRows(at: [indexPath], with: .automatic) self.tableView.deleteRows(at: [indexPath], with: .automatic)
} }
}
func listMonitor(_ monitor: ListMonitor<ListEntityType>, didUpdateObject object: ListEntityType, atIndexPath indexPath: IndexPath) { nonisolated func listMonitor(_ monitor: ListMonitor<ListEntityType>, didUpdateObject object: sending ListEntityType, atIndexPath indexPath: IndexPath) {
MainActor.assumeIsolated {
if case let cell as Classic.ColorsDemo.ItemCell = self.tableView.cellForRow(at: indexPath) { if case let cell as Classic.ColorsDemo.ItemCell = self.tableView.cellForRow(at: indexPath) {
cell.setPalette(object) cell.setPalette(object)
} }
} }
}
func listMonitor(_ monitor: ListMonitor<ListEntityType>, didMoveObject object: ListEntityType, fromIndexPath: IndexPath, toIndexPath: IndexPath) { nonisolated func listMonitor(_ monitor: ListMonitor<ListEntityType>, didMoveObject object: ListEntityType, fromIndexPath: IndexPath, toIndexPath: IndexPath) {
MainActor.assumeIsolated {
self.tableView.deleteRows(at: [fromIndexPath], with: .automatic) self.tableView.deleteRows(at: [fromIndexPath], with: .automatic)
self.tableView.insertRows(at: [toIndexPath], with: .automatic) self.tableView.insertRows(at: [toIndexPath], with: .automatic)
} }
}
// MARK: ListSectionObserver // MARK: ListSectionObserver
func listMonitor(_ monitor: ListMonitor<ListEntityType>, didInsertSection sectionInfo: NSFetchedResultsSectionInfo, toSectionIndex sectionIndex: Int) { nonisolated func listMonitor(_ monitor: ListMonitor<ListEntityType>, didInsertSection sectionInfo: NSFetchedResultsSectionInfo, toSectionIndex sectionIndex: Int) {
MainActor.assumeIsolated {
self.tableView.insertSections(IndexSet(integer: sectionIndex), with: .automatic) self.tableView.insertSections(IndexSet(integer: sectionIndex), with: .automatic)
} }
}
func listMonitor(_ monitor: ListMonitor<ListEntityType>, didDeleteSection sectionInfo: NSFetchedResultsSectionInfo, fromSectionIndex sectionIndex: Int) { nonisolated func listMonitor(_ monitor: ListMonitor<ListEntityType>, didDeleteSection sectionInfo: NSFetchedResultsSectionInfo, fromSectionIndex sectionIndex: Int) {
MainActor.assumeIsolated {
self.tableView.deleteSections(IndexSet(integer: sectionIndex), with: .automatic) self.tableView.deleteSections(IndexSet(integer: sectionIndex), with: .automatic)
} }
}
// MARK: UITableViewDataSource // MARK: UITableViewDataSource
@@ -131,11 +158,11 @@ extension Classic.ColorsDemo {
switch editingStyle { switch editingStyle {
case .delete: case .delete:
let object = self.listMonitor[indexPath] let persistentID = self.listMonitor[indexPath].persistentID()
Classic.ColorsDemo.dataStack.perform( Classic.ColorsDemo.dataStack.perform(
asynchronous: { (transaction) in asynchronous: { (transaction) in
transaction.delete(object) transaction.delete(persistentID)
}, },
completion: { _ in } completion: { _ in }
) )
-2
View File
@@ -65,7 +65,6 @@ open /*abstract*/ class CoreStoreObject: DynamicObject, Hashable {
Do not call this directly. This is exposed as public only as a required initializer. Do not call this directly. This is exposed as public only as a required initializer.
- Important: subclasses that need a custom initializer should override both `init(rawObject:)` and `init(asMeta:)`, and to call their corresponding super implementations. - Important: subclasses that need a custom initializer should override both `init(rawObject:)` and `init(asMeta:)`, and to call their corresponding super implementations.
*/ */
@_spi(Internals)
public required init(rawObject: NSManagedObject) { public required init(rawObject: NSManagedObject) {
self.isMeta = false self.isMeta = false
@@ -85,7 +84,6 @@ open /*abstract*/ class CoreStoreObject: DynamicObject, Hashable {
Do not call this directly. This is exposed as public only as a required initializer. Do not call this directly. This is exposed as public only as a required initializer.
- Important: subclasses that need a custom initializer should override both `init(rawObject:)` and `init(asMeta:)`, and to call their corresponding super implementations. - Important: subclasses that need a custom initializer should override both `init(rawObject:)` and `init(asMeta:)`, and to call their corresponding super implementations.
*/ */
@_spi(Internals)
public required init(asMeta: Void) { public required init(asMeta: Void) {
self.isMeta = true self.isMeta = true
+1 -1
View File
@@ -46,7 +46,7 @@ extension DataStack {
Thread.isMainThread, Thread.isMainThread,
"Attempted to observe objects from \(Internals.typeName(self)) outside the main thread." "Attempted to observe objects from \(Internals.typeName(self)) outside the main thread."
) )
return .init(objectID: object.cs_id(), context: self.unsafeContext()) return .init(managedObjectID: object.cs_id(), context: self.unsafeContext())
} }
/** /**
-8
View File
@@ -91,14 +91,6 @@ public nonisolated protocol DynamicObject: AnyObject, SendableMetatype {
extension DynamicObject { extension DynamicObject {
// MARK: Public
public func persistentID() -> DynamicObjectID<Self> {
return .init(managedObjectID: self.cs_id())
}
// MARK: Internal // MARK: Internal
internal func runtimeType() -> Self.Type { internal func runtimeType() -> Self.Type {
+5
View File
@@ -95,6 +95,11 @@ public struct DynamicObjectID<O: DynamicObject>: Hashable, ObjectRepresentation,
public typealias ObjectType = O public typealias ObjectType = O
public func persistentID() -> ObjectType.ObjectID {
return self
}
public func asPublisher(in dataStack: DataStack) -> ObjectPublisher<ObjectType> { public func asPublisher(in dataStack: DataStack) -> ObjectPublisher<ObjectType> {
let context = dataStack.unsafeContext() let context = dataStack.unsafeContext()
+17 -12
View File
@@ -170,7 +170,7 @@ public final class ObjectMonitor<O: DynamicObject>: Hashable, ObjectRepresentati
@_spi(Internals) @_spi(Internals)
public func cs_id() -> NSManagedObjectID { public func cs_id() -> NSManagedObjectID {
return self.id return self.managedObjectID
} }
@_spi(Internals) @_spi(Internals)
@@ -184,43 +184,48 @@ public final class ObjectMonitor<O: DynamicObject>: Hashable, ObjectRepresentati
public typealias ObjectType = O public typealias ObjectType = O
public func persistentID() -> O.ObjectID {
return .init(managedObjectID: self.managedObjectID)
}
public func asPublisher(in dataStack: DataStack) -> ObjectPublisher<O> { public func asPublisher(in dataStack: DataStack) -> ObjectPublisher<O> {
return dataStack.unsafeContext().objectPublisher(managedObjectID: self.id) return dataStack.unsafeContext().objectPublisher(managedObjectID: self.managedObjectID)
} }
public func asReadOnly(in dataStack: DataStack) -> O? { public func asReadOnly(in dataStack: DataStack) -> O? {
return dataStack.unsafeContext().fetchExisting(self.id) return dataStack.unsafeContext().fetchExisting(self.managedObjectID)
} }
public func asEditable(in transaction: BaseDataTransaction) -> O? { public func asEditable(in transaction: BaseDataTransaction) -> O? {
return transaction.unsafeContext().fetchExisting(self.id) return transaction.unsafeContext().fetchExisting(self.managedObjectID)
} }
public func asSnapshot(in dataStack: DataStack) -> ObjectSnapshot<O>? { public func asSnapshot(in dataStack: DataStack) -> ObjectSnapshot<O>? {
let context = dataStack.unsafeContext() let context = dataStack.unsafeContext()
return ObjectSnapshot<O>(managedObjectID: self.id, context: context) return ObjectSnapshot<O>(managedObjectID: self.managedObjectID, context: context)
} }
public func asSnapshot(in transaction: BaseDataTransaction) -> ObjectSnapshot<O>? { public func asSnapshot(in transaction: BaseDataTransaction) -> ObjectSnapshot<O>? {
let context = transaction.unsafeContext() let context = transaction.unsafeContext()
return ObjectSnapshot<O>(managedObjectID: self.id, context: context) return ObjectSnapshot<O>(managedObjectID: self.managedObjectID, context: context)
} }
// MARK: Internal // MARK: Internal
internal init( internal init(
objectID: NSManagedObjectID, managedObjectID: NSManagedObjectID,
context: NSManagedObjectContext context: NSManagedObjectContext
) { ) {
let fetchRequest = Internals.CoreStoreFetchRequest<NSManagedObject>() let fetchRequest = Internals.CoreStoreFetchRequest<NSManagedObject>()
fetchRequest.entity = objectID.entity fetchRequest.entity = managedObjectID.entity
fetchRequest.fetchLimit = 0 fetchRequest.fetchLimit = 0
fetchRequest.resultType = .managedObjectResultType fetchRequest.resultType = .managedObjectResultType
fetchRequest.sortDescriptors = [] fetchRequest.sortDescriptors = []
@@ -230,13 +235,13 @@ public final class ObjectMonitor<O: DynamicObject>: Hashable, ObjectRepresentati
let fetchedResultsController = Internals.CoreStoreFetchedResultsController( let fetchedResultsController = Internals.CoreStoreFetchedResultsController(
context: context, context: context,
fetchRequest: fetchRequest, fetchRequest: fetchRequest,
from: From<O>([objectID.persistentStore?.configurationName]), from: From<O>([managedObjectID.persistentStore?.configurationName]),
applyFetchClauses: Where<O>("SELF", isEqualTo: objectID).applyToFetchRequest applyFetchClauses: Where<O>("SELF", isEqualTo: managedObjectID).applyToFetchRequest
) )
let fetchedResultsControllerDelegate = Internals.FetchedResultsControllerDelegate() let fetchedResultsControllerDelegate = Internals.FetchedResultsControllerDelegate()
self.id = objectID self.managedObjectID = managedObjectID
self.fetchedResultsController = fetchedResultsController self.fetchedResultsController = fetchedResultsController
self.fetchedResultsControllerDelegate = fetchedResultsControllerDelegate self.fetchedResultsControllerDelegate = fetchedResultsControllerDelegate
@@ -355,7 +360,7 @@ public final class ObjectMonitor<O: DynamicObject>: Hashable, ObjectRepresentati
// MARK: Private // MARK: Private
private let id: NSManagedObjectID private let managedObjectID: NSManagedObjectID
private let fetchedResultsController: Internals.CoreStoreFetchedResultsController private let fetchedResultsController: Internals.CoreStoreFetchedResultsController
private let fetchedResultsControllerDelegate: Internals.FetchedResultsControllerDelegate private let fetchedResultsControllerDelegate: Internals.FetchedResultsControllerDelegate
private let lastCommittedAttributes: Internals.Mutex<[String: NSObject]> = .init([:]) private let lastCommittedAttributes: Internals.Mutex<[String: NSObject]> = .init([:])
+5
View File
@@ -177,6 +177,11 @@ public final class ObjectPublisher<O: DynamicObject>: ObjectRepresentation, Hash
public typealias ObjectType = O public typealias ObjectType = O
public func persistentID() -> O.ObjectID {
return .init(managedObjectID: self.managedObjectID)
}
public func asPublisher(in dataStack: DataStack) -> ObjectPublisher<O> { public func asPublisher(in dataStack: DataStack) -> ObjectPublisher<O> {
let context = dataStack.unsafeContext() let context = dataStack.unsafeContext()
+14
View File
@@ -59,6 +59,11 @@ public protocol ObjectRepresentation: AnyObjectRepresentation {
*/ */
associatedtype ObjectType: DynamicObject associatedtype ObjectType: DynamicObject
/**
The `Sendable` ID to use for referencing the object between isolation contexts.
*/
func persistentID() -> ObjectType.ObjectID
/** /**
An instance that may be observed for object changes. An instance that may be observed for object changes.
*/ */
@@ -85,6 +90,7 @@ public protocol ObjectRepresentation: AnyObjectRepresentation {
func asSnapshot(in transaction: BaseDataTransaction) -> ObjectSnapshot<ObjectType>? func asSnapshot(in transaction: BaseDataTransaction) -> ObjectSnapshot<ObjectType>?
} }
extension NSManagedObject: ObjectRepresentation {} extension NSManagedObject: ObjectRepresentation {}
extension CoreStoreObject: ObjectRepresentation {} extension CoreStoreObject: ObjectRepresentation {}
@@ -93,6 +99,14 @@ extension DynamicObject where Self: ObjectRepresentation {
// MARK: Public // MARK: Public
/**
The `Sendable` ID to use for referencing the object between isolation contexts.
*/
public func persistentID() -> Self.ObjectID {
return .init(managedObjectID: self.cs_id())
}
/** /**
An `ObjectPublisher` wrapper for the exact same object An `ObjectPublisher` wrapper for the exact same object
*/ */
+5
View File
@@ -69,6 +69,11 @@ public struct ObjectSnapshot<O: DynamicObject>: ObjectRepresentation, Hashable,
public typealias ObjectType = O public typealias ObjectType = O
public func persistentID() -> ObjectType.ObjectID {
return .init(managedObjectID: self.managedObjectID)
}
public func asPublisher(in dataStack: DataStack) -> ObjectPublisher<O> { public func asPublisher(in dataStack: DataStack) -> ObjectPublisher<O> {
let context = dataStack.unsafeContext() let context = dataStack.unsafeContext()
@@ -41,7 +41,7 @@ extension UnsafeDataTransaction {
_ object: O _ object: O
) -> ObjectMonitor<O> { ) -> ObjectMonitor<O> {
return .init(objectID: object.cs_id(), context: self.unsafeContext()) return .init(managedObjectID: object.cs_id(), context: self.unsafeContext())
} }
/** /**