Make ObjectPublishers even lighter by lazy-loading observers

This commit is contained in:
John Estropia
2019-10-25 19:16:38 +09:00
parent f3beca8769
commit 998938490c
3 changed files with 49 additions and 26 deletions

View File

@@ -146,6 +146,12 @@ extension NSManagedObjectContext {
} }
} }
@nonobjc
internal func objectsDidChangeObserver<U: AnyObject>(remove: U) {
_ = self.userInfo(for: .objectsChangeObserver(U.self), initialize: { nil as Any? })
}
// MARK: Private // MARK: Private

View File

@@ -195,6 +195,7 @@ public final class ObjectPublisher<O: DynamicObject>: ObjectRepresentation, Hash
deinit { deinit {
self.context.objectsDidChangeObserver(remove: self)
self.observers.removeAllObjects() self.observers.removeAllObjects()
} }
@@ -221,30 +222,36 @@ public final class ObjectPublisher<O: DynamicObject>: ObjectRepresentation, Hash
self.rawObjectWillChange = nil self.rawObjectWillChange = nil
} }
self.$lazySnapshot.initialize({ initializer(objectID, context) }) self.$lazySnapshot.initialize { [weak self] in
context.objectsDidChangeObserver(for: self).addObserver(self) { [weak self] (updatedIDs, deletedIDs) in
guard let self = self else { 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() return
self.$lazySnapshot.reset({ nil }) }
self.didChange() if deletedIDs.contains(objectID) {
self.notifyObservers()
} self.object = nil
else if updatedIDs.contains(objectID) {
self.willChange()
self.willChange() self.$lazySnapshot.reset({ nil })
self.$lazySnapshot.reset({ initializer(objectID, context) }) self.didChange()
self.didChange() self.notifyObservers()
self.notifyObservers() }
else if updatedIDs.contains(objectID) {
self.willChange()
self.$lazySnapshot.reset({ initializer(objectID, context) })
self.didChange()
self.notifyObservers()
}
} }
return initializer(objectID, context)
} }
} }

View File

@@ -107,6 +107,7 @@ public struct ObjectSnapshot<O: DynamicObject>: ObjectRepresentation, Hashable {
return nil return nil
} }
self.id = objectID self.id = objectID
self.context = context
self.values = values self.values = values
} }
@@ -114,6 +115,7 @@ public struct ObjectSnapshot<O: DynamicObject>: ObjectRepresentation, Hashable {
// MARK: Private // MARK: Private
private let id: O.ObjectID private let id: O.ObjectID
private let context: NSManagedObjectContext
private var values: [String: Any] private var values: [String: Any]
private var valuesRef: NSDictionary { private var valuesRef: NSDictionary {
@@ -214,51 +216,59 @@ extension ObjectSnapshot where O: CoreStoreObject {
/** /**
Returns the value for the property identified by a given key. Returns the value for the property identified by a given key.
*/ */
public subscript<OBase, D>(dynamicMember member: KeyPath<O, RelationshipContainer<OBase>.ToOne<D>>) -> D.ObjectID? { public subscript<OBase, D>(dynamicMember member: KeyPath<O, RelationshipContainer<OBase>.ToOne<D>>) -> ObjectPublisher<D>? {
get { get {
let key = String(keyPath: member) 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 { set {
let key = String(keyPath: member) 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. Returns the value for the property identified by a given key.
*/ */
public subscript<OBase, D>(dynamicMember member: KeyPath<O, RelationshipContainer<OBase>.ToManyOrdered<D>>) -> [D.ObjectID] { public subscript<OBase, D>(dynamicMember member: KeyPath<O, RelationshipContainer<OBase>.ToManyOrdered<D>>) -> [ObjectPublisher<D>] {
get { get {
let key = String(keyPath: member) 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 { set {
let key = String(keyPath: member) 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. Returns the value for the property identified by a given key.
*/ */
public subscript<OBase, D>(dynamicMember member: KeyPath<O, RelationshipContainer<OBase>.ToManyUnordered<D>>) -> Set<D.ObjectID> { public subscript<OBase, D>(dynamicMember member: KeyPath<O, RelationshipContainer<OBase>.ToManyUnordered<D>>) -> Set<ObjectPublisher<D>> {
get { get {
let key = String(keyPath: member) let key = String(keyPath: member)
return self.values[key] as! Set<D.ObjectID> let context = self.context
let ids = self.values[key] as! Set<D.ObjectID>
return Set(ids.map(context.objectPublisher(objectID:)))
} }
set { set {
let key = String(keyPath: member) let key = String(keyPath: member)
self.values[key] = newValue self.values[key] = Set(newValue.map({ $0.objectID() }))
} }
} }
} }