Ensure LazilyDecoding runs on the managed object context's thread

Maybe fix the crash in KeyPath machinery?
This commit is contained in:
Shadowfacts 2023-11-10 14:16:16 -05:00
parent bc7500bde9
commit b40d815274
1 changed files with 42 additions and 27 deletions

View File

@ -7,12 +7,13 @@
//
import Foundation
import CoreData
private let decoder = PropertyListDecoder()
private let encoder = PropertyListEncoder()
@propertyWrapper
public struct LazilyDecoding<Enclosing: NSObject, Value: Codable> {
public struct LazilyDecoding<Enclosing: NSManagedObject, Value: Codable> {
private let keyPath: ReferenceWritableKeyPath<Enclosing, Data?>
private let fallback: Value
@ -32,6 +33,7 @@ public struct LazilyDecoding<Enclosing: NSObject, Value: Codable> {
public static subscript(_enclosingInstance instance: Enclosing, wrapped wrappedKeyPath: ReferenceWritableKeyPath<Enclosing, Value>, storage storageKeyPath: ReferenceWritableKeyPath<Enclosing, Self>) -> Value {
get {
instance.performOnContext {
var wrapper = instance[keyPath: storageKeyPath]
if let value = wrapper.value {
return value
@ -56,7 +58,9 @@ public struct LazilyDecoding<Enclosing: NSObject, Value: Codable> {
}
}
}
}
set {
instance.performOnContext {
var wrapper = instance[keyPath: storageKeyPath]
wrapper.value = newValue
wrapper.skipClearingOnNextUpdate = true
@ -65,6 +69,7 @@ public struct LazilyDecoding<Enclosing: NSObject, Value: Codable> {
instance[keyPath: wrapper.keyPath] = newData
}
}
}
mutating func removeCachedValue() {
value = nil
@ -73,6 +78,16 @@ public struct LazilyDecoding<Enclosing: NSObject, Value: Codable> {
}
extension NSManagedObject {
fileprivate func performOnContext<V>(_ f: () -> V) -> V {
if let managedObjectContext {
managedObjectContext.performAndWait(f)
} else {
f()
}
}
}
extension LazilyDecoding {
init<T>(arrayFrom keyPath: ReferenceWritableKeyPath<Enclosing, Data?>) where Value == [T] {
self.init(from: keyPath, fallback: [])