This commit is contained in:
John Estropia committed 2026-10-02 15:12:03 +09:00
1 parent 838637f29f
commit 10ac228867
8 files changed
+84 -40

No files matched your search

+36 -1
View File
@@ -33,7 +33,42 @@ import CoreStore
// MARK: - ConvenienceTests
class ConvenienceTests: BaseTestCase {
@objc
dynamic func test_ThatUserInfoLazyInitializer_CanReadAnotherKey() {
let keys = UnsafeMutableRawPointer.allocate(byteCount: 2, alignment: 1)
defer { keys.deallocate() }
let userInfo = UserInfo()
let value = userInfo[UnsafeRawPointer(keys), lazyInit: {
let nested = userInfo[
UnsafeRawPointer(keys.advanced(by: 1)),
lazyInit: { "nested" }
] as! String
return "outer \(nested)"
}]
XCTAssertEqual(value as? String, "outer nested")
}
func test_ThatUndoManagerIsReadyWhenUnsafeTransactionStartsOffMain() async {
let hasUndoManager = await Task.detached {
let parent = NSManagedObjectContext(concurrencyType: .privateQueueConcurrencyType)
let transaction = UnsafeDataTransaction(
mainContext: parent,
queue: DispatchQueue(label: "com.corestore.tests.unsafeTransactionQueue"),
supportsUndo: true,
sourceIdentifier: nil
)
let context = transaction.context
return context.performAndWait { context.undoManager != nil }
}.value
XCTAssertTrue(hasUndoManager)
}
@objc
@MainActor
dynamic func test_ThatDataStacks_CanCreateFetchedResultsControllers() {
@@ -52,21 +52,22 @@ extension Classic.ColorsDemo {
.toolbar {
ToolbarItemGroup(placement: .topBarLeading) {
EditButton()
Button("Clear") {
.labelStyle(.iconOnly)
Button("Clear", systemImage: "trash") {
self.clearColors()
}
}
ToolbarItemGroup(placement: .topBarTrailing) {
Button(self.filter.rawValue) {
Button(self.filter.rawValue, systemImage: "line.3.horizontal.decrease.circle") {
self.changeFilter()
}
Button("Shuffle") {
Button("Shuffle", systemImage: "shuffle") {
self.shuffleColors()
}
Button("Add") {
Button("Add", systemImage: "plus") {
self.addColor()
}
@@ -55,7 +55,8 @@ extension Modern.ColorsDemo {
ToolbarItemGroup(placement: .topBarLeading) {
EditButton()
Button("Clear") {
.labelStyle(.iconOnly)
Button("Clear", systemImage: "trash") {
self.clearColors()
}
@@ -63,15 +64,15 @@ extension Modern.ColorsDemo {
ToolbarItemGroup(placement: .topBarTrailing) {
Button(self.filter.rawValue) {
Button(self.filter.rawValue, systemImage: "line.3.horizontal.decrease.circle") {
self.changeFilter()
}
Button("Shuffle") {
Button("Shuffle", systemImage: "shuffle") {
self.shuffleColors()
}
Button("Add") {
Button("Add", systemImage: "plus") {
self.addColor()
}
@@ -109,7 +109,12 @@ extension Modern.PlacemarksDemo {
return
}
let geocoded = await self.geocoder.geocode(place: place)
guard self.place?.persistentID() == place.persistentID() else {
guard
!Task.isCancelled,
self.place?.persistentID() == place.persistentID(),
self.place?.$latitude == place.$latitude,
self.place?.$longitude == place.$longitude
else {
return
}
@@ -126,7 +131,7 @@ extension Modern.PlacemarksDemo {
.navigationTitle("Placemarks")
.toolbar {
Button("Random") {
Button("Random", systemImage: "dice") {
self.demoSynchronousTransaction()
}
@@ -195,7 +195,7 @@ extension Modern.PokedexDemo {
if let species = details.$species?.snapshot {
self.fetchFormsIfNeeded(
key: String(species.$id),
key: pokedexEntry.$id,
detailsPersistentID: details.persistentID(),
species: species
)
@@ -219,7 +219,6 @@ extension Modern.PokedexDemo {
self.detailTasks.removeValue(forKey: key)
}
await self.fetchSpecies(
key: key,
detailsPersistentID: detailsPersistentID,
speciesURL: speciesURL
)
@@ -288,7 +287,6 @@ extension Modern.PokedexDemo {
}
private func fetchSpecies(
key: String,
detailsPersistentID: PersistentID<Modern.PokedexDemo.Details>,
speciesURL: URL
) async {
+11 -4
View File
@@ -554,11 +554,18 @@ public /*abstract*/ class BaseDataTransaction {
context.undoManager = nil
}
else if context.undoManager == nil {
Internals.mainActorImmediate {
context.undoManager = UndoManager()
let undoManager: UndoManager
if Thread.isMainThread {
undoManager = MainActor.assumeIsolated { UndoManager() }
}
else {
undoManager = DispatchQueue.main.sync {
MainActor.assumeIsolated { UndoManager() }
}
}
context.undoManager = undoManager
}
}
+3 -4
View File
@@ -38,7 +38,7 @@ extension ListSnapshot {
public let sectionID: SectionID
public let itemIDs: [NSManagedObjectID]
public let itemIDs: [ItemID]
// MARK: RandomAccessCollection
@@ -79,7 +79,7 @@ extension ListSnapshot {
public subscript(position: Int) -> ObjectPublisher<O> {
let itemID = self.itemIDs[position]
return self.context.objectPublisher(managedObjectID: itemID)
return self.context.objectPublisher(managedObjectID: itemID.managedObjectID)
}
public func index(_ i: Index, offsetBy distance: Int) -> Index {
@@ -100,7 +100,7 @@ extension ListSnapshot {
public subscript(bounds: Range<Index>) -> ArraySlice<Element> {
let itemIDs = self.itemIDs[bounds]
return ArraySlice(itemIDs.map(self.context.objectPublisher(managedObjectID:)))
return ArraySlice(itemIDs.map({ self.context.objectPublisher(managedObjectID: $0.managedObjectID) }))
}
@@ -126,7 +126,6 @@ extension ListSnapshot {
}
self.sectionID = sectionID
self.itemIDs = listSnapshot.itemIDs(inSectionWithID: sectionID)
.map({ $0.managedObjectID })
self.context = context
}
}
+16 -18
View File
@@ -38,7 +38,7 @@ import Foundation
```
- Important: Do not use this class to store thread-sensitive data.
*/
public final class UserInfo: Sendable {
public final class UserInfo: @unchecked Sendable {
/**
Allows external libraries to store custom data. App code should rarely have a need for this.
@@ -55,17 +55,15 @@ public final class UserInfo: Sendable {
get {
return self.data.withLock { (info: inout _) in
return info[key]
}
self.lock.lock()
defer { self.lock.unlock() }
return self.data[key]
}
set {
return self.data.withLock { (info: inout _) in
info[key] = newValue
}
self.lock.lock()
defer { self.lock.unlock() }
self.data[key] = newValue
}
}
@@ -84,16 +82,15 @@ public final class UserInfo: Sendable {
*/
public subscript(key: UnsafeRawPointer, lazyInit closure: () -> any Sendable) -> any Sendable {
return self.data.withLock { (info: inout _) in
if let value = info[key] {
return value
}
let value = closure()
info[key] = value
self.lock.lock()
defer { self.lock.unlock() }
if let value = self.data[key] {
return value
}
let value = closure()
self.data[key] = value
return value
}
@@ -104,5 +101,6 @@ public final class UserInfo: Sendable {
// MARK: Private
private let data: Internals.Mutex<[UnsafeRawPointer: any Sendable]> = .init([:])
private var data: [UnsafeRawPointer: any Sendable] = [:]
private let lock = NSRecursiveLock()
}