mirror of
https://github.com/JohnEstropia/CoreStore.git
synced 2026-02-19 06:07:47 +01:00
Improve handling in LiveObject and ObjectSnapshot when objects are deleted
This commit is contained in:
@@ -75,24 +75,6 @@ extension Palette {
|
||||
}
|
||||
}
|
||||
|
||||
extension LiveObject where ObjectType == Palette {
|
||||
|
||||
var color: UIColor {
|
||||
|
||||
return UIColor(
|
||||
hue: CGFloat(self.hue) / 360.0,
|
||||
saturation: CGFloat(self.saturation),
|
||||
brightness: CGFloat(self.brightness),
|
||||
alpha: 1.0
|
||||
)
|
||||
}
|
||||
|
||||
var colorText: String {
|
||||
|
||||
return "H: \(self.hue)˚, S: \(round(self.saturation * 100.0))%, B: \(round(self.brightness * 100.0))%"
|
||||
}
|
||||
}
|
||||
|
||||
extension Palette {
|
||||
|
||||
func setInitialValues(in transaction: BaseDataTransaction) {
|
||||
|
||||
@@ -116,10 +116,10 @@ struct ColorCell: View {
|
||||
|
||||
var body: some View {
|
||||
HStack {
|
||||
Color(palette.color)
|
||||
Color(palette.color ?? UIColor.clear)
|
||||
.cornerRadius(5)
|
||||
.frame(width: 30, height: 30, alignment: .leading)
|
||||
Text(palette.colorText)
|
||||
Text(palette.colorText ?? "<Deleted>")
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -140,18 +140,18 @@ struct DetailView: View {
|
||||
init(palette: LiveObject<Palette>) {
|
||||
|
||||
self.palette = palette
|
||||
self.hue = Float(palette.hue)
|
||||
self.saturation = palette.saturation
|
||||
self.brightness = palette.brightness
|
||||
self.hue = Float(palette.hue ?? 0)
|
||||
self.saturation = palette.saturation ?? 0
|
||||
self.brightness = palette.brightness ?? 0
|
||||
}
|
||||
|
||||
var body: some View {
|
||||
ZStack {
|
||||
Color(palette.color)
|
||||
Color(palette.color ?? UIColor.clear)
|
||||
.cornerRadius(20)
|
||||
.padding(20)
|
||||
VStack {
|
||||
Text(palette.colorText)
|
||||
Text(palette.colorText ?? "<Deleted>")
|
||||
.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>)
|
||||
|
||||
@@ -292,22 +292,32 @@ class DynamicModelTests: BaseTestDataTestCase {
|
||||
XCTAssertEqual(person.name.value, "John")
|
||||
XCTAssertEqual(person.displayName.value, "Mr. John") // Custom getter
|
||||
|
||||
let personSnapshot1 = person.asSnapshot(in: transaction)
|
||||
XCTAssertEqual(person.name.value, personSnapshot1?.name)
|
||||
XCTAssertEqual(person.title.value, personSnapshot1?.title)
|
||||
XCTAssertEqual(person.displayName.value, personSnapshot1?.displayName)
|
||||
let personSnapshot1 = person.asSnapshot(in: transaction)!
|
||||
XCTAssertEqual(person.name.value, personSnapshot1.name)
|
||||
XCTAssertEqual(person.title.value, personSnapshot1.title)
|
||||
XCTAssertEqual(person.displayName.value, personSnapshot1.displayName)
|
||||
|
||||
person.title .= "Sir"
|
||||
XCTAssertEqual(person.displayName.value, "Sir John")
|
||||
|
||||
XCTAssertEqual(personSnapshot1?.name, "John")
|
||||
XCTAssertEqual(personSnapshot1?.title, "Mr.")
|
||||
XCTAssertEqual(personSnapshot1?.displayName, "Mr. John")
|
||||
XCTAssertEqual(personSnapshot1.name, "John")
|
||||
XCTAssertEqual(personSnapshot1.title, "Mr.")
|
||||
XCTAssertEqual(personSnapshot1.displayName, "Mr. John")
|
||||
|
||||
let personSnapshot2 = person.asSnapshot(in: transaction)
|
||||
XCTAssertEqual(person.name.value, personSnapshot2?.name)
|
||||
XCTAssertEqual(person.title.value, personSnapshot2?.title)
|
||||
XCTAssertEqual(person.displayName.value, personSnapshot2?.displayName)
|
||||
let personSnapshot2 = person.asSnapshot(in: transaction)!
|
||||
XCTAssertEqual(person.name.value, personSnapshot2.name)
|
||||
XCTAssertEqual(person.title.value, personSnapshot2.title)
|
||||
XCTAssertEqual(person.displayName.value, personSnapshot2.displayName)
|
||||
|
||||
var personSnapshot3 = personSnapshot2
|
||||
personSnapshot3.name = "James"
|
||||
XCTAssertEqual(personSnapshot1.name, "John")
|
||||
XCTAssertEqual(personSnapshot1.displayName, "Mr. John")
|
||||
XCTAssertEqual(personSnapshot2.name, "John")
|
||||
XCTAssertEqual(personSnapshot2.displayName, "Sir John")
|
||||
XCTAssertEqual(personSnapshot3.name, "James")
|
||||
XCTAssertEqual(personSnapshot3.displayName, "Sir John")
|
||||
|
||||
|
||||
person.pets.value.insert(dog)
|
||||
XCTAssertEqual(person.pets.count, 1)
|
||||
|
||||
@@ -46,7 +46,7 @@ public protocol DynamicObject: AnyObject {
|
||||
/**
|
||||
Used internally by CoreStore. Do not call directly.
|
||||
*/
|
||||
static func cs_snapshotDictionary(id: ObjectID, context: NSManagedObjectContext) -> [String: Any]
|
||||
static func cs_snapshotDictionary(id: ObjectID, context: NSManagedObjectContext) -> [String: Any]?
|
||||
|
||||
/**
|
||||
Used internally by CoreStore. Do not call directly.
|
||||
@@ -97,11 +97,19 @@ extension NSManagedObject: DynamicObject {
|
||||
return object
|
||||
}
|
||||
|
||||
public class func cs_snapshotDictionary(id: ObjectID, context: NSManagedObjectContext) -> [String: Any] {
|
||||
public class func cs_snapshotDictionary(id: ObjectID, context: NSManagedObjectContext) -> [String: Any]? {
|
||||
|
||||
let object = context.fetchExisting(id)! as Self
|
||||
guard let object = context.fetchExisting(id) as NSManagedObject? else {
|
||||
|
||||
return nil
|
||||
}
|
||||
let rawObject = object.cs_toRaw()
|
||||
return rawObject.dictionaryWithValues(forKeys: rawObject.entity.properties.map({ $0.name }))
|
||||
var dictionary = rawObject.dictionaryWithValues(forKeys: Array(rawObject.entity.attributesByName.keys))
|
||||
for case (let key, let target as NSManagedObject) in rawObject.dictionaryWithValues(forKeys: Array(rawObject.entity.relationshipsByName.keys)) {
|
||||
|
||||
dictionary[key] = target.objectID
|
||||
}
|
||||
return dictionary
|
||||
}
|
||||
|
||||
public class func cs_fromRaw(object: NSManagedObject) -> Self {
|
||||
@@ -143,7 +151,7 @@ extension CoreStoreObject {
|
||||
return self.cs_fromRaw(object: object)
|
||||
}
|
||||
|
||||
public class func cs_snapshotDictionary(id: ObjectID, context: NSManagedObjectContext) -> [String: Any] {
|
||||
public class func cs_snapshotDictionary(id: ObjectID, context: NSManagedObjectContext) -> [String: Any]? {
|
||||
|
||||
func initializeAttributes(mirror: Mirror, object: Self, into attributes: inout [KeyPathString: Any]) {
|
||||
|
||||
@@ -170,11 +178,14 @@ extension CoreStoreObject {
|
||||
}
|
||||
}
|
||||
}
|
||||
let object = context.fetchExisting(id)! as Self
|
||||
guard let object = context.fetchExisting(id) as CoreStoreObject? else {
|
||||
|
||||
return nil
|
||||
}
|
||||
var values: [KeyPathString: Any] = [:]
|
||||
initializeAttributes(
|
||||
mirror: Mirror(reflecting: object),
|
||||
object: object,
|
||||
object: object as! Self,
|
||||
into: &values
|
||||
)
|
||||
return values
|
||||
|
||||
@@ -46,10 +46,12 @@ public final class LiveObject<O: DynamicObject>: ObjectRepresentation, Hashable
|
||||
public typealias SectionID = String
|
||||
public typealias ItemID = O.ObjectID
|
||||
|
||||
public var snapshot: SnapshotType {
|
||||
public var snapshot: ObjectSnapshot<O>? {
|
||||
|
||||
return self.lazySnapshot
|
||||
}
|
||||
|
||||
public lazy var object: O? = self.context.fetchExisting(self.id)
|
||||
|
||||
public func addObserver<T: AnyObject>(_ observer: T, _ callback: @escaping (LiveObject<O>) -> Void) {
|
||||
|
||||
@@ -79,7 +81,7 @@ public final class LiveObject<O: DynamicObject>: ObjectRepresentation, Hashable
|
||||
return self.id
|
||||
}
|
||||
|
||||
public func asLiveObject(in dataStack: DataStack) -> LiveObject<O>? {
|
||||
public func asLiveObject(in dataStack: DataStack) -> LiveObject<O> {
|
||||
|
||||
let context = dataStack.unsafeContext()
|
||||
if self.context == context {
|
||||
@@ -106,7 +108,7 @@ public final class LiveObject<O: DynamicObject>: ObjectRepresentation, Hashable
|
||||
|
||||
return self.lazySnapshot
|
||||
}
|
||||
return .init(objectID: self.id, context: context)
|
||||
return ObjectSnapshot<O>(objectID: self.id, context: context)
|
||||
}
|
||||
|
||||
public func asSnapshot(in transaction: BaseDataTransaction) -> ObjectSnapshot<O>? {
|
||||
@@ -116,7 +118,7 @@ public final class LiveObject<O: DynamicObject>: ObjectRepresentation, Hashable
|
||||
|
||||
return self.lazySnapshot
|
||||
}
|
||||
return .init(objectID: self.id, context: context)
|
||||
return ObjectSnapshot<O>(objectID: self.id, context: context)
|
||||
}
|
||||
|
||||
|
||||
@@ -159,7 +161,7 @@ public final class LiveObject<O: DynamicObject>: ObjectRepresentation, Hashable
|
||||
|
||||
fileprivate let rawObjectWillChange: Any?
|
||||
|
||||
fileprivate init(objectID: O.ObjectID, context: NSManagedObjectContext, initializer: @escaping (NSManagedObjectID, NSManagedObjectContext) -> ObjectSnapshot<O>) {
|
||||
fileprivate init(objectID: O.ObjectID, context: NSManagedObjectContext, initializer: @escaping (NSManagedObjectID, NSManagedObjectContext) -> ObjectSnapshot<O>?) {
|
||||
|
||||
self.id = objectID
|
||||
self.context = context
|
||||
@@ -179,24 +181,31 @@ public final class LiveObject<O: DynamicObject>: ObjectRepresentation, Hashable
|
||||
}
|
||||
self.$lazySnapshot.initialize({ initializer(objectID, context) })
|
||||
|
||||
context.objectsDidChangeObserver(for: self).addObserver(self) { [weak self] (objectIDs) in
|
||||
context.objectsDidChangeObserver(for: self).addObserver(self) { [weak self] (updatedIDs, deletedIDs) in
|
||||
|
||||
guard let self = self else {
|
||||
|
||||
return
|
||||
}
|
||||
self.willChange()
|
||||
self.$lazySnapshot.reset({ initializer(objectID, context) })
|
||||
self.notifyObservers()
|
||||
self.didChange()
|
||||
if deletedIDs.contains(objectID) {
|
||||
|
||||
self.object = nil
|
||||
|
||||
self.willChange()
|
||||
self.$lazySnapshot.reset({ nil })
|
||||
self.notifyObservers()
|
||||
self.didChange()
|
||||
}
|
||||
else if updatedIDs.contains(objectID) {
|
||||
|
||||
self.willChange()
|
||||
self.$lazySnapshot.reset({ initializer(objectID, context) })
|
||||
self.notifyObservers()
|
||||
self.didChange()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fileprivate var object: O {
|
||||
|
||||
return self.context.fetchExisting(self.id)!
|
||||
}
|
||||
|
||||
|
||||
// MARK: Private
|
||||
|
||||
@@ -204,7 +213,7 @@ public final class LiveObject<O: DynamicObject>: ObjectRepresentation, Hashable
|
||||
private let context: NSManagedObjectContext
|
||||
|
||||
@Internals.LazyNonmutating(uninitialized: ())
|
||||
private var lazySnapshot: ObjectSnapshot<O>
|
||||
private var lazySnapshot: ObjectSnapshot<O>?
|
||||
|
||||
private lazy var observers: NSMapTable<AnyObject, Internals.Closure<LiveObject<O>, Void>> = .weakToStrongObjects()
|
||||
|
||||
@@ -302,9 +311,9 @@ extension LiveObject where O: CoreStoreObject {
|
||||
/**
|
||||
Returns the value for the property identified by a given key.
|
||||
*/
|
||||
public subscript<V>(dynamicMember member: KeyPath<O, ValueContainer<O>.Required<V>>) -> V {
|
||||
public subscript<V>(dynamicMember member: KeyPath<O, ValueContainer<O>.Required<V>>) -> V? {
|
||||
|
||||
return self.snapshot[dynamicMember: member]
|
||||
return self.object?[keyPath: member].value
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -312,15 +321,15 @@ extension LiveObject where O: CoreStoreObject {
|
||||
*/
|
||||
public subscript<V>(dynamicMember member: KeyPath<O, ValueContainer<O>.Optional<V>>) -> V? {
|
||||
|
||||
return self.snapshot[dynamicMember: member]
|
||||
return self.object?[keyPath: member].value
|
||||
}
|
||||
|
||||
/**
|
||||
Returns the value for the property identified by a given key.
|
||||
*/
|
||||
public subscript<V>(dynamicMember member: KeyPath<O, TransformableContainer<O>.Required<V>>) -> V {
|
||||
public subscript<V>(dynamicMember member: KeyPath<O, TransformableContainer<O>.Required<V>>) -> V? {
|
||||
|
||||
return self.snapshot[dynamicMember: member]
|
||||
return self.object?[keyPath: member].value
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -328,7 +337,7 @@ extension LiveObject where O: CoreStoreObject {
|
||||
*/
|
||||
public subscript<V>(dynamicMember member: KeyPath<O, TransformableContainer<O>.Optional<V>>) -> V? {
|
||||
|
||||
return self.snapshot[dynamicMember: member]
|
||||
return self.object?[keyPath: member].value
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -336,22 +345,30 @@ extension LiveObject where O: CoreStoreObject {
|
||||
*/
|
||||
public subscript<D>(dynamicMember member: KeyPath<O, RelationshipContainer<O>.ToOne<D>>) -> D? {
|
||||
|
||||
return self.snapshot[dynamicMember: member]
|
||||
return self.object?[keyPath: member].value
|
||||
}
|
||||
|
||||
/**
|
||||
Returns the value for the property identified by a given key.
|
||||
*/
|
||||
public subscript<D>(dynamicMember member: KeyPath<O, RelationshipContainer<O>.ToManyOrdered<D>>) -> [D] {
|
||||
public subscript<D>(dynamicMember member: KeyPath<O, RelationshipContainer<O>.ToManyOrdered<D>>) -> [D]? {
|
||||
|
||||
return self.snapshot[dynamicMember: member]
|
||||
return self.object?[keyPath: member].value
|
||||
}
|
||||
|
||||
/**
|
||||
Returns the value for the property identified by a given key.
|
||||
*/
|
||||
public subscript<D>(dynamicMember member: KeyPath<O, RelationshipContainer<O>.ToManyUnordered<D>>) -> Set<D> {
|
||||
public subscript<D>(dynamicMember member: KeyPath<O, RelationshipContainer<O>.ToManyUnordered<D>>) -> Set<D>? {
|
||||
|
||||
return self.snapshot[dynamicMember: member]
|
||||
return self.object?[keyPath: member].value
|
||||
}
|
||||
|
||||
/**
|
||||
Returns the value for the property identified by a given key.
|
||||
*/
|
||||
public subscript<V>(dynamicMember member: KeyPath<O, V>) -> V? {
|
||||
|
||||
return self.object?[keyPath: member]
|
||||
}
|
||||
}
|
||||
|
||||
@@ -106,7 +106,7 @@ extension NSManagedObjectContext {
|
||||
}
|
||||
|
||||
@nonobjc
|
||||
internal func objectsDidChangeObserver<U: AnyObject>(for observer: U) -> Internals.SharedNotificationObserver<Set<NSManagedObjectID>> {
|
||||
internal func objectsDidChangeObserver<U: AnyObject>(for observer: U) -> Internals.SharedNotificationObserver<(updated: Set<NSManagedObjectID>, deleted: Set<NSManagedObjectID>)> {
|
||||
|
||||
return self.userInfo(for: .objectsChangeObserver(U.self)) { [unowned self] in
|
||||
|
||||
@@ -114,11 +114,11 @@ extension NSManagedObjectContext {
|
||||
notificationName: .NSManagedObjectContextObjectsDidChange,
|
||||
object: self,
|
||||
queue: .main,
|
||||
sharedValue: { (notification) -> Set<NSManagedObjectID> in
|
||||
sharedValue: { (notification) -> (updated: Set<NSManagedObjectID>, deleted: Set<NSManagedObjectID>) in
|
||||
|
||||
guard let userInfo = notification.userInfo else {
|
||||
|
||||
return []
|
||||
return (updated: [], deleted: [])
|
||||
}
|
||||
var updatedObjectIDs: Set<NSManagedObjectID> = []
|
||||
if let updatedObjects = userInfo[NSUpdatedObjectsKey] as? Set<NSManagedObjectID> {
|
||||
@@ -129,7 +129,8 @@ extension NSManagedObjectContext {
|
||||
|
||||
updatedObjectIDs.formUnion(mergedObjects)
|
||||
}
|
||||
return updatedObjectIDs
|
||||
let deletedObjectIDs: Set<NSManagedObjectID> = (userInfo[NSDeletedObjectsKey] as? Set<NSManagedObjectID>) ?? []
|
||||
return (updated: updatedObjectIDs, deleted: deletedObjectIDs)
|
||||
}
|
||||
)
|
||||
}
|
||||
|
||||
@@ -46,7 +46,7 @@ public protocol ObjectRepresentation {
|
||||
/**
|
||||
An instance that may be observed for object changes.
|
||||
*/
|
||||
func asLiveObject(in dataStack: DataStack) -> LiveObject<ObjectType>?
|
||||
func asLiveObject(in dataStack: DataStack) -> LiveObject<ObjectType>
|
||||
|
||||
/**
|
||||
A read-only instance in the `DataStack`.
|
||||
@@ -82,10 +82,10 @@ extension DynamicObject where Self: ObjectRepresentation {
|
||||
return self.cs_id()
|
||||
}
|
||||
|
||||
public func asLiveObject(in dataStack: DataStack) -> LiveObject<Self>? {
|
||||
public func asLiveObject(in dataStack: DataStack) -> LiveObject<Self> {
|
||||
|
||||
let context = dataStack.unsafeContext()
|
||||
return .init(objectID: self.cs_id(), context: context)
|
||||
return LiveObject<Self>(objectID: self.cs_id(), context: context)
|
||||
}
|
||||
|
||||
public func asReadOnly(in dataStack: DataStack) -> Self? {
|
||||
@@ -111,12 +111,12 @@ extension DynamicObject where Self: ObjectRepresentation {
|
||||
public func asSnapshot(in dataStack: DataStack) -> ObjectSnapshot<Self>? {
|
||||
|
||||
let context = dataStack.unsafeContext()
|
||||
return .init(objectID: self.cs_id(), context: context)
|
||||
return ObjectSnapshot<Self>(objectID: self.cs_id(), context: context)
|
||||
}
|
||||
|
||||
public func asSnapshot(in transaction: BaseDataTransaction) -> ObjectSnapshot<Self>? {
|
||||
|
||||
let context = transaction.unsafeContext()
|
||||
return .init(objectID: self.cs_id(), context: context)
|
||||
return ObjectSnapshot<Self>(objectID: self.cs_id(), context: context)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -51,10 +51,10 @@ public struct ObjectSnapshot<O: DynamicObject>: SnapshotResult, ObjectRepresenta
|
||||
return self.id
|
||||
}
|
||||
|
||||
public func asLiveObject(in dataStack: DataStack) -> LiveObject<O>? {
|
||||
public func asLiveObject(in dataStack: DataStack) -> LiveObject<O> {
|
||||
|
||||
let context = dataStack.unsafeContext()
|
||||
return .init(objectID: self.id, context: context)
|
||||
return LiveObject<O>(objectID: self.id, context: context)
|
||||
}
|
||||
|
||||
public func asReadOnly(in dataStack: DataStack) -> O? {
|
||||
@@ -70,21 +70,13 @@ public struct ObjectSnapshot<O: DynamicObject>: SnapshotResult, ObjectRepresenta
|
||||
public func asSnapshot(in dataStack: DataStack) -> ObjectSnapshot<O>? {
|
||||
|
||||
let context = dataStack.unsafeContext()
|
||||
if self.context == context {
|
||||
|
||||
return self
|
||||
}
|
||||
return .init(objectID: self.id, context: context)
|
||||
return ObjectSnapshot<O>(objectID: self.id, context: context)
|
||||
}
|
||||
|
||||
public func asSnapshot(in transaction: BaseDataTransaction) -> ObjectSnapshot<O>? {
|
||||
|
||||
let context = transaction.unsafeContext()
|
||||
if self.context == context {
|
||||
|
||||
return self
|
||||
}
|
||||
return .init(objectID: self.id, context: context)
|
||||
return ObjectSnapshot<O>(objectID: self.id, context: context)
|
||||
}
|
||||
|
||||
|
||||
@@ -93,7 +85,7 @@ public struct ObjectSnapshot<O: DynamicObject>: SnapshotResult, ObjectRepresenta
|
||||
public static func == (_ lhs: Self, _ rhs: Self) -> Bool {
|
||||
|
||||
return lhs.id == rhs.id
|
||||
&& lhs.values == rhs.values
|
||||
&& lhs.valuesRef == rhs.valuesRef
|
||||
}
|
||||
|
||||
|
||||
@@ -102,25 +94,32 @@ public struct ObjectSnapshot<O: DynamicObject>: SnapshotResult, ObjectRepresenta
|
||||
public func hash(into hasher: inout Hasher) {
|
||||
|
||||
hasher.combine(self.id)
|
||||
hasher.combine(self.values)
|
||||
hasher.combine(self.valuesRef)
|
||||
}
|
||||
|
||||
|
||||
// MARK: Internal
|
||||
|
||||
internal init(objectID: O.ObjectID, context: NSManagedObjectContext) {
|
||||
internal init?(objectID: O.ObjectID, context: NSManagedObjectContext) {
|
||||
|
||||
guard let values = O.cs_snapshotDictionary(id: objectID, context: context) else {
|
||||
|
||||
return nil
|
||||
}
|
||||
self.id = objectID
|
||||
self.context = context
|
||||
self.values = O.cs_snapshotDictionary(id: objectID, context: context) as NSDictionary
|
||||
self.values = values
|
||||
}
|
||||
|
||||
|
||||
// MARK: Private
|
||||
|
||||
private let id: O.ObjectID
|
||||
private let context: NSManagedObjectContext
|
||||
private let values: NSDictionary
|
||||
private var values: [String: Any]
|
||||
|
||||
private var valuesRef: NSDictionary {
|
||||
|
||||
return self.values as NSDictionary
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -149,8 +148,16 @@ extension ObjectSnapshot where O: CoreStoreObject {
|
||||
*/
|
||||
public subscript<V>(dynamicMember member: KeyPath<O, ValueContainer<O>.Required<V>>) -> V {
|
||||
|
||||
let key = String(keyPath: member)
|
||||
return self.values[key] as! V
|
||||
get {
|
||||
|
||||
let key = String(keyPath: member)
|
||||
return self.values[key] as! V
|
||||
}
|
||||
set {
|
||||
|
||||
let key = String(keyPath: member)
|
||||
self.values[key] = newValue
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -158,8 +165,16 @@ extension ObjectSnapshot where O: CoreStoreObject {
|
||||
*/
|
||||
public subscript<V>(dynamicMember member: KeyPath<O, ValueContainer<O>.Optional<V>>) -> V? {
|
||||
|
||||
let key = String(keyPath: member)
|
||||
return self.values[key] as! V?
|
||||
get {
|
||||
|
||||
let key = String(keyPath: member)
|
||||
return self.values[key] as! V?
|
||||
}
|
||||
set {
|
||||
|
||||
let key = String(keyPath: member)
|
||||
self.values[key] = newValue
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -167,8 +182,16 @@ extension ObjectSnapshot where O: CoreStoreObject {
|
||||
*/
|
||||
public subscript<V>(dynamicMember member: KeyPath<O, TransformableContainer<O>.Required<V>>) -> V {
|
||||
|
||||
let key = String(keyPath: member)
|
||||
return self.values[key] as! V
|
||||
get {
|
||||
|
||||
let key = String(keyPath: member)
|
||||
return self.values[key] as! V
|
||||
}
|
||||
set {
|
||||
|
||||
let key = String(keyPath: member)
|
||||
self.values[key] = newValue
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -176,34 +199,66 @@ extension ObjectSnapshot where O: CoreStoreObject {
|
||||
*/
|
||||
public subscript<V>(dynamicMember member: KeyPath<O, TransformableContainer<O>.Optional<V>>) -> V? {
|
||||
|
||||
let key = String(keyPath: member)
|
||||
return self.values[key] as! V?
|
||||
get {
|
||||
|
||||
let key = String(keyPath: member)
|
||||
return self.values[key] as! V?
|
||||
}
|
||||
set {
|
||||
|
||||
let key = String(keyPath: member)
|
||||
self.values[key] = newValue
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
Returns the value for the property identified by a given key.
|
||||
*/
|
||||
public subscript<D>(dynamicMember member: KeyPath<O, RelationshipContainer<O>.ToOne<D>>) -> D? {
|
||||
public subscript<D>(dynamicMember member: KeyPath<O, RelationshipContainer<O>.ToOne<D>>) -> D.ObjectID? {
|
||||
|
||||
let key = String(keyPath: member)
|
||||
return self.values[key] as! D?
|
||||
get {
|
||||
|
||||
let key = String(keyPath: member)
|
||||
return self.values[key] as! D.ObjectID?
|
||||
}
|
||||
set {
|
||||
|
||||
let key = String(keyPath: member)
|
||||
self.values[key] = newValue
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
Returns the value for the property identified by a given key.
|
||||
*/
|
||||
public subscript<D>(dynamicMember member: KeyPath<O, RelationshipContainer<O>.ToManyOrdered<D>>) -> [D] {
|
||||
public subscript<D>(dynamicMember member: KeyPath<O, RelationshipContainer<O>.ToManyOrdered<D>>) -> [D.ObjectID] {
|
||||
|
||||
let key = String(keyPath: member)
|
||||
return self.values[key] as! [D]
|
||||
get {
|
||||
|
||||
let key = String(keyPath: member)
|
||||
return self.values[key] as! [D.ObjectID]
|
||||
}
|
||||
set {
|
||||
|
||||
let key = String(keyPath: member)
|
||||
self.values[key] = newValue
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
Returns the value for the property identified by a given key.
|
||||
*/
|
||||
public subscript<D>(dynamicMember member: KeyPath<O, RelationshipContainer<O>.ToManyUnordered<D>>) -> Set<D> {
|
||||
public subscript<D>(dynamicMember member: KeyPath<O, RelationshipContainer<O>.ToManyUnordered<D>>) -> Set<D.ObjectID> {
|
||||
|
||||
let key = String(keyPath: member)
|
||||
return self.values[key] as! Set<D>
|
||||
get {
|
||||
|
||||
let key = String(keyPath: member)
|
||||
return self.values[key] as! Set<D.ObjectID>
|
||||
}
|
||||
set {
|
||||
|
||||
let key = String(keyPath: member)
|
||||
self.values[key] = newValue
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -315,7 +315,7 @@ public enum RelationshipContainer<O: CoreStoreObject> {
|
||||
|
||||
internal var valueForSnapshot: Any {
|
||||
|
||||
return self.value as Any
|
||||
return self.value?.objectID() as Any
|
||||
}
|
||||
|
||||
|
||||
@@ -611,7 +611,7 @@ public enum RelationshipContainer<O: CoreStoreObject> {
|
||||
|
||||
internal var valueForSnapshot: Any {
|
||||
|
||||
return self.value as Any
|
||||
return self.value.map({ $0.objectID() }) as Any
|
||||
}
|
||||
|
||||
|
||||
@@ -912,7 +912,7 @@ public enum RelationshipContainer<O: CoreStoreObject> {
|
||||
|
||||
internal var valueForSnapshot: Any {
|
||||
|
||||
return self.value as Any
|
||||
return Set(self.value.map({ $0.objectID() })) as Any
|
||||
}
|
||||
|
||||
|
||||
|
||||
Reference in New Issue
Block a user