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

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

View File

@@ -195,6 +195,7 @@ public final class ObjectPublisher<O: DynamicObject>: ObjectRepresentation, Hash
deinit {
self.context.objectsDidChangeObserver(remove: self)
self.observers.removeAllObjects()
}
@@ -221,30 +222,36 @@ public final class ObjectPublisher<O: DynamicObject>: 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)
}
}

View File

@@ -107,6 +107,7 @@ public struct ObjectSnapshot<O: DynamicObject>: ObjectRepresentation, Hashable {
return nil
}
self.id = objectID
self.context = context
self.values = values
}
@@ -114,6 +115,7 @@ public struct ObjectSnapshot<O: DynamicObject>: 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<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 {
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<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 {
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<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 {
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 {
let key = String(keyPath: member)
self.values[key] = newValue
self.values[key] = Set(newValue.map({ $0.objectID() }))
}
}
}