From 998938490cb15fd5d1f5ae8a8e13ad338ad5cf7e Mon Sep 17 00:00:00 2001 From: John Estropia Date: Fri, 25 Oct 2019 19:16:38 +0900 Subject: [PATCH] Make ObjectPublishers even lighter by lazy-loading observers --- .../NSManagedObjectContext+CoreStore.swift | 6 +++ Sources/ObjectPublisher.swift | 41 +++++++++++-------- Sources/ObjectSnapshot.swift | 28 +++++++++---- 3 files changed, 49 insertions(+), 26 deletions(-) diff --git a/Sources/NSManagedObjectContext+CoreStore.swift b/Sources/NSManagedObjectContext+CoreStore.swift index 1e1b6d8..1e3a636 100644 --- a/Sources/NSManagedObjectContext+CoreStore.swift +++ b/Sources/NSManagedObjectContext+CoreStore.swift @@ -145,6 +145,12 @@ extension NSManagedObjectContext { ) } } + + @nonobjc + internal func objectsDidChangeObserver(remove: U) { + + _ = self.userInfo(for: .objectsChangeObserver(U.self), initialize: { nil as Any? }) + } // MARK: Private diff --git a/Sources/ObjectPublisher.swift b/Sources/ObjectPublisher.swift index be59366..98718f5 100644 --- a/Sources/ObjectPublisher.swift +++ b/Sources/ObjectPublisher.swift @@ -195,6 +195,7 @@ public final class ObjectPublisher: ObjectRepresentation, Hash deinit { + self.context.objectsDidChangeObserver(remove: self) self.observers.removeAllObjects() } @@ -221,30 +222,36 @@ public final class ObjectPublisher: ObjectRepresentation, Hash self.rawObjectWillChange = nil } - self.$lazySnapshot.initialize({ initializer(objectID, context) }) - - context.objectsDidChangeObserver(for: self).addObserver(self) { [weak self] (updatedIDs, deletedIDs) in + self.$lazySnapshot.initialize { [weak self] in guard let self = self else { - return + return initializer(objectID, context) } - if deletedIDs.contains(objectID) { + context.objectsDidChangeObserver(for: self).addObserver(self) { [weak self] (updatedIDs, deletedIDs) in - self.object = nil + guard let self = self else { - self.willChange() - self.$lazySnapshot.reset({ nil }) - self.didChange() - self.notifyObservers() - } - else if updatedIDs.contains(objectID) { - - self.willChange() - self.$lazySnapshot.reset({ initializer(objectID, context) }) - self.didChange() - self.notifyObservers() + return + } + if deletedIDs.contains(objectID) { + + self.object = nil + + self.willChange() + self.$lazySnapshot.reset({ nil }) + self.didChange() + self.notifyObservers() + } + else if updatedIDs.contains(objectID) { + + self.willChange() + self.$lazySnapshot.reset({ initializer(objectID, context) }) + self.didChange() + self.notifyObservers() + } } + return initializer(objectID, context) } } diff --git a/Sources/ObjectSnapshot.swift b/Sources/ObjectSnapshot.swift index 811cbda..92dd900 100644 --- a/Sources/ObjectSnapshot.swift +++ b/Sources/ObjectSnapshot.swift @@ -107,6 +107,7 @@ public struct ObjectSnapshot: ObjectRepresentation, Hashable { return nil } self.id = objectID + self.context = context self.values = values } @@ -114,6 +115,7 @@ public struct ObjectSnapshot: ObjectRepresentation, Hashable { // MARK: Private private let id: O.ObjectID + private let context: NSManagedObjectContext private var values: [String: Any] private var valuesRef: NSDictionary { @@ -214,51 +216,59 @@ extension ObjectSnapshot where O: CoreStoreObject { /** Returns the value for the property identified by a given key. */ - public subscript(dynamicMember member: KeyPath.ToOne>) -> D.ObjectID? { + public subscript(dynamicMember member: KeyPath.ToOne>) -> ObjectPublisher? { get { let key = String(keyPath: member) - return self.values[key] as! D.ObjectID? + guard let id = self.values[key] as! D.ObjectID? else { + + return nil + } + return self.context.objectPublisher(objectID: id) } set { let key = String(keyPath: member) - self.values[key] = newValue + self.values[key] = newValue?.objectID() } } /** Returns the value for the property identified by a given key. */ - public subscript(dynamicMember member: KeyPath.ToManyOrdered>) -> [D.ObjectID] { + public subscript(dynamicMember member: KeyPath.ToManyOrdered>) -> [ObjectPublisher] { get { let key = String(keyPath: member) - return self.values[key] as! [D.ObjectID] + let context = self.context + let ids = self.values[key] as! [D.ObjectID] + return ids.map(context.objectPublisher(objectID:)) } set { let key = String(keyPath: member) - self.values[key] = newValue + self.values[key] = newValue.map({ $0.objectID() }) } } /** Returns the value for the property identified by a given key. */ - public subscript(dynamicMember member: KeyPath.ToManyUnordered>) -> Set { + public subscript(dynamicMember member: KeyPath.ToManyUnordered>) -> Set> { get { let key = String(keyPath: member) - return self.values[key] as! Set + let context = self.context + let ids = self.values[key] as! Set + return Set(ids.map(context.objectPublisher(objectID:))) } set { let key = String(keyPath: member) - self.values[key] = newValue + self.values[key] = Set(newValue.map({ $0.objectID() })) } } }