From 773cfb88d460821ebf91d652c1b8301996977fe3 Mon Sep 17 00:00:00 2001 From: pjechris Date: Sat, 3 Aug 2024 15:52:29 +0200 Subject: [PATCH 1/5] introduce ObjectKey --- .../CohesionKit/Observer/ObserverRegistry.swift | 16 +++++++++++++--- 1 file changed, 13 insertions(+), 3 deletions(-) diff --git a/Sources/CohesionKit/Observer/ObserverRegistry.swift b/Sources/CohesionKit/Observer/ObserverRegistry.swift index dcbc53a..f8d6090 100644 --- a/Sources/CohesionKit/Observer/ObserverRegistry.swift +++ b/Sources/CohesionKit/Observer/ObserverRegistry.swift @@ -1,15 +1,25 @@ import Foundation +/// a unique hash identifying an object +typealias ObjectKey = Int + +extension ObjectKey { + init(of type: T.Type, id: Any) { + let key = "\(type)-\(id)" + + self.init(key.hashValue) + } +} + /// Registers observers associated to an ``EntityNode``. /// The registry will handle notifying observers when a node is marked as changed class ObserverRegistry { - private typealias Hash = Int let queue: DispatchQueue /// registered observer handlers - private var handlers: [Hash: Set] = [:] + private var handlers: [ObjectKey: Set] = [:] /// nodes waiting for notifiying their observes about changes - private var pendingChanges: [Hash: AnyWeak] = [:] + private var pendingChanges: [ObjectKey: AnyWeak] = [:] init(queue: DispatchQueue? = nil) { self.queue = queue ?? DispatchQueue.main From 97db6f5cc0d952a06c83de42bd652dcb942b48ab Mon Sep 17 00:00:00 2001 From: pjechris Date: Sat, 3 Aug 2024 16:05:58 +0200 Subject: [PATCH 2/5] [registry] allow passing key as parameter --- .../Observer/ObserverRegistry.swift | 24 +++++++++++++------ 1 file changed, 17 insertions(+), 7 deletions(-) diff --git a/Sources/CohesionKit/Observer/ObserverRegistry.swift b/Sources/CohesionKit/Observer/ObserverRegistry.swift index f8d6090..8453bdc 100644 --- a/Sources/CohesionKit/Observer/ObserverRegistry.swift +++ b/Sources/CohesionKit/Observer/ObserverRegistry.swift @@ -41,7 +41,7 @@ class ObserverRegistry { } } - return subscribeHandler(handler, for: node) + return subscribeHandler(handler, for: node, key: node.hashValue) } /// Add an observer handler to multiple nodes. @@ -63,7 +63,7 @@ class ObserverRegistry { } } - let subscriptions = nodes.map { node in subscribeHandler(handler, for: node) } + let subscriptions = nodes.map { node in subscribeHandler(handler, for: node, key: node.hashValue) } return Subscription { subscriptions.forEach { $0.unsubscribe() } @@ -72,11 +72,19 @@ class ObserverRegistry { /// Mark a node as changed. Observers won't be notified of the change until ``postChanges`` is called func enqueueChange(for node: EntityNode) { - pendingChanges[node.hashValue] = Weak(value: node) + enqueueChange(for: node, key: node.hashValue) + } + + func enqueueChange(for node: EntityNode, key: ObjectKey) { + pendingChanges[key] = Weak(value: node) } func hasPendingChange(for node: EntityNode) -> Bool { - pendingChanges[node.hashValue] != nil + hasPendingChange(for: node.hashValue) + } + + func hasPendingChange(for key: ObjectKey) -> Bool { + pendingChanges[key] != nil } /// Notify observers of all queued changes. Once notified pending changes are cleared out. @@ -107,12 +115,14 @@ class ObserverRegistry { } } - private func subscribeHandler(_ handler: Handler, for node: EntityNode) -> Subscription { - handlers[node.hashValue, default: []].insert(handler) + private func subscribeHandler(_ handler: Handler, for node: EntityNode, key: ObjectKey) -> Subscription { + handlers[key, default: []].insert(handler) // subscription keeps a strong ref to node, avoiding it from being released somehow while suscription is running return Subscription { [node] in - self.handlers[node.hashValue]?.remove(handler) + withExtendedLifetime(node) { } + + self.handlers[key]?.remove(handler) } } } From 21668ef49291003b77ade4b2acc7ec9021351ce7 Mon Sep 17 00:00:00 2001 From: pjechris Date: Sun, 4 Aug 2024 20:35:22 +0200 Subject: [PATCH 3/5] use ObjectKey --- Sources/CohesionKit/Observer/ObserverRegistry.swift | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/Sources/CohesionKit/Observer/ObserverRegistry.swift b/Sources/CohesionKit/Observer/ObserverRegistry.swift index 8453bdc..4bae0e6 100644 --- a/Sources/CohesionKit/Observer/ObserverRegistry.swift +++ b/Sources/CohesionKit/Observer/ObserverRegistry.swift @@ -9,6 +9,10 @@ extension ObjectKey { self.init(key.hashValue) } + + init(_ node: EntityNode) { + self.init(of: T.self, id: node.hashValue) + } } /// Registers observers associated to an ``EntityNode``. @@ -41,7 +45,7 @@ class ObserverRegistry { } } - return subscribeHandler(handler, for: node, key: node.hashValue) + return subscribeHandler(handler, for: node, key: ObjectKey(node)) } /// Add an observer handler to multiple nodes. @@ -63,7 +67,7 @@ class ObserverRegistry { } } - let subscriptions = nodes.map { node in subscribeHandler(handler, for: node, key: node.hashValue) } + let subscriptions = nodes.map { node in subscribeHandler(handler, for: node, key: ObjectKey(node)) } return Subscription { subscriptions.forEach { $0.unsubscribe() } @@ -72,7 +76,7 @@ class ObserverRegistry { /// Mark a node as changed. Observers won't be notified of the change until ``postChanges`` is called func enqueueChange(for node: EntityNode) { - enqueueChange(for: node, key: node.hashValue) + enqueueChange(for: node, key: ObjectKey(node)) } func enqueueChange(for node: EntityNode, key: ObjectKey) { @@ -80,7 +84,7 @@ class ObserverRegistry { } func hasPendingChange(for node: EntityNode) -> Bool { - hasPendingChange(for: node.hashValue) + hasPendingChange(for: ObjectKey(node)) } func hasPendingChange(for key: ObjectKey) -> Bool { From bf4429be6531c736281a2dfe1673e8b11378de63 Mon Sep 17 00:00:00 2001 From: pjechris Date: Sun, 4 Aug 2024 20:48:11 +0200 Subject: [PATCH 4/5] add key to `addObserver` --- Sources/CohesionKit/Observer/ObserverRegistry.swift | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/Sources/CohesionKit/Observer/ObserverRegistry.swift b/Sources/CohesionKit/Observer/ObserverRegistry.swift index 4bae0e6..fe8bd44 100644 --- a/Sources/CohesionKit/Observer/ObserverRegistry.swift +++ b/Sources/CohesionKit/Observer/ObserverRegistry.swift @@ -29,9 +29,13 @@ class ObserverRegistry { self.queue = queue ?? DispatchQueue.main } + func addObserver(node: EntityNode, initial: Bool = false, onChange: @escaping (T) -> Void) -> Subscription { + addObserver(node: node, key: ObjectKey(node), initial: initial, onChange: onChange) + } + /// register an observer to observe changes on an entity node. Everytime `ObserverRegistry` is notified about changes /// to this node `onChange` will be called. - func addObserver(node: EntityNode, initial: Bool = false, onChange: @escaping (T) -> Void) -> Subscription { + func addObserver(node: EntityNode, key: ObjectKey, initial: Bool = false, onChange: @escaping (T) -> Void) -> Subscription { let handler = Handler { onChange($0.ref.value) } if initial { @@ -45,7 +49,7 @@ class ObserverRegistry { } } - return subscribeHandler(handler, for: node, key: ObjectKey(node)) + return subscribeHandler(handler, for: node, key: key) } /// Add an observer handler to multiple nodes. From 50d89ca0fc209708d7ff70d1adcffbe212cb3ae8 Mon Sep 17 00:00:00 2001 From: pjechris Date: Sat, 10 Aug 2024 18:15:36 +0200 Subject: [PATCH 5/5] [ci] change destination --- fastlane/Fastfile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/fastlane/Fastfile b/fastlane/Fastfile index d06b43f..21fff87 100644 --- a/fastlane/Fastfile +++ b/fastlane/Fastfile @@ -28,7 +28,7 @@ platform :ios do scheme: "Example", configuration: "Debug", build: true, - destination: "platform=iOS Simulator,name=iPhone SE (2nd generation)" + destination: "platform=iOS Simulator,name=iPhone SE (3rd generation)" ) end end