Skip to content

Commit bd3c15e

Browse files
authored
Add a utility method for identifying which property changed for tracking events (#71223)
1 parent b847528 commit bd3c15e

File tree

2 files changed

+30
-20
lines changed

2 files changed

+30
-20
lines changed

stdlib/public/Observation/Sources/Observation/ObservationRegistrar.swift

Lines changed: 14 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -38,8 +38,8 @@ public struct ObservationRegistrar: Sendable {
3838

3939
private struct State: @unchecked Sendable {
4040
private enum ObservationKind {
41-
case willSetTracking(@Sendable () -> Void)
42-
case didSetTracking(@Sendable () -> Void)
41+
case willSetTracking(@Sendable (AnyKeyPath) -> Void)
42+
case didSetTracking(@Sendable (AnyKeyPath) -> Void)
4343
case computed(@Sendable (Any) -> Void)
4444
case values(ValuesObserver)
4545
}
@@ -53,7 +53,7 @@ public struct ObservationRegistrar: Sendable {
5353
self.properties = properties
5454
}
5555

56-
var willSetTracker: (@Sendable () -> Void)? {
56+
var willSetTracker: (@Sendable (AnyKeyPath) -> Void)? {
5757
switch kind {
5858
case .willSetTracking(let tracker):
5959
return tracker
@@ -62,7 +62,7 @@ public struct ObservationRegistrar: Sendable {
6262
}
6363
}
6464

65-
var didSetTracker: (@Sendable () -> Void)? {
65+
var didSetTracker: (@Sendable (AnyKeyPath) -> Void)? {
6666
switch kind {
6767
case .didSetTracking(let tracker):
6868
return tracker
@@ -117,7 +117,7 @@ public struct ObservationRegistrar: Sendable {
117117
return id
118118
}
119119

120-
internal mutating func registerTracking(for properties: Set<AnyKeyPath>, willSet observer: @Sendable @escaping () -> Void) -> Int {
120+
internal mutating func registerTracking(for properties: Set<AnyKeyPath>, willSet observer: @Sendable @escaping (AnyKeyPath) -> Void) -> Int {
121121
let id = generateId()
122122
observations[id] = Observation(kind: .willSetTracking(observer), properties: properties)
123123
for keyPath in properties {
@@ -126,7 +126,7 @@ public struct ObservationRegistrar: Sendable {
126126
return id
127127
}
128128

129-
internal mutating func registerTracking(for properties: Set<AnyKeyPath>, didSet observer: @Sendable @escaping () -> Void) -> Int {
129+
internal mutating func registerTracking(for properties: Set<AnyKeyPath>, didSet observer: @Sendable @escaping (AnyKeyPath) -> Void) -> Int {
130130
let id = generateId()
131131
observations[id] = Observation(kind: .didSetTracking(observer), properties: properties)
132132
for keyPath in properties {
@@ -184,8 +184,8 @@ public struct ObservationRegistrar: Sendable {
184184
lookups.removeAll()
185185
}
186186

187-
internal mutating func willSet(keyPath: AnyKeyPath) -> [@Sendable () -> Void] {
188-
var trackers = [@Sendable () -> Void]()
187+
internal mutating func willSet(keyPath: AnyKeyPath) -> [@Sendable (AnyKeyPath) -> Void] {
188+
var trackers = [@Sendable (AnyKeyPath) -> Void]()
189189
if let ids = lookups[keyPath] {
190190
for id in ids {
191191
if let tracker = observations[id]?.willSetTracker {
@@ -196,9 +196,9 @@ public struct ObservationRegistrar: Sendable {
196196
return trackers
197197
}
198198

199-
internal mutating func didSet<Subject: Observable, Member>(keyPath: KeyPath<Subject, Member>) -> ([@Sendable (Any) -> Void], [@Sendable () -> Void]) {
199+
internal mutating func didSet<Subject: Observable, Member>(keyPath: KeyPath<Subject, Member>) -> ([@Sendable (Any) -> Void], [@Sendable (AnyKeyPath) -> Void]) {
200200
var observers = [@Sendable (Any) -> Void]()
201-
var trackers = [@Sendable () -> Void]()
201+
var trackers = [@Sendable (AnyKeyPath) -> Void]()
202202
if let ids = lookups[keyPath] {
203203
for id in ids {
204204
if let observer = observations[id]?.observer {
@@ -227,11 +227,11 @@ public struct ObservationRegistrar: Sendable {
227227

228228
internal var id: ObjectIdentifier { state.id }
229229

230-
internal func registerTracking(for properties: Set<AnyKeyPath>, willSet observer: @Sendable @escaping () -> Void) -> Int {
230+
internal func registerTracking(for properties: Set<AnyKeyPath>, willSet observer: @Sendable @escaping (AnyKeyPath) -> Void) -> Int {
231231
state.withCriticalRegion { $0.registerTracking(for: properties, willSet: observer) }
232232
}
233233

234-
internal func registerTracking(for properties: Set<AnyKeyPath>, didSet observer: @Sendable @escaping () -> Void) -> Int {
234+
internal func registerTracking(for properties: Set<AnyKeyPath>, didSet observer: @Sendable @escaping (AnyKeyPath) -> Void) -> Int {
235235
state.withCriticalRegion { $0.registerTracking(for: properties, didSet: observer) }
236236
}
237237

@@ -257,7 +257,7 @@ public struct ObservationRegistrar: Sendable {
257257
) {
258258
let tracking = state.withCriticalRegion { $0.willSet(keyPath: keyPath) }
259259
for action in tracking {
260-
action()
260+
action(keyPath)
261261
}
262262
}
263263

@@ -271,7 +271,7 @@ public struct ObservationRegistrar: Sendable {
271271
state.withCriticalRegion { $0.emit(value, ids: ids) }
272272
}
273273
for action in tracking {
274-
action()
274+
action(keyPath)
275275
}
276276
for action in actions {
277277
action(subject)

stdlib/public/Observation/Sources/Observation/ObservationTracking.swift

Lines changed: 16 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -28,11 +28,11 @@ public struct ObservationTracking: Sendable {
2828
self.properties = properties
2929
}
3030

31-
func addWillSetObserver(_ changed: @Sendable @escaping () -> Void) -> Int {
31+
func addWillSetObserver(_ changed: @Sendable @escaping (AnyKeyPath) -> Void) -> Int {
3232
return context.registerTracking(for: properties, willSet: changed)
3333
}
3434

35-
func addDidSetObserver(_ changed: @Sendable @escaping () -> Void) -> Int {
35+
func addDidSetObserver(_ changed: @Sendable @escaping (AnyKeyPath) -> Void) -> Int {
3636
return context.registerTracking(for: properties, didSet: changed)
3737
}
3838

@@ -78,17 +78,21 @@ public struct ObservationTracking: Sendable {
7878
let values = tracking.list.entries.mapValues {
7979
switch (willSet, didSet) {
8080
case (.some(let willSetObserver), .some(let didSetObserver)):
81-
return Id.full($0.addWillSetObserver {
81+
return Id.full($0.addWillSetObserver { keyPath in
82+
tracking.state.withCriticalRegion { $0.changed = keyPath }
8283
willSetObserver(tracking)
83-
}, $0.addDidSetObserver {
84+
}, $0.addDidSetObserver { keyPath in
85+
tracking.state.withCriticalRegion { $0.changed = keyPath }
8486
didSetObserver(tracking)
8587
})
8688
case (.some(let willSetObserver), .none):
87-
return Id.willSet($0.addWillSetObserver {
89+
return Id.willSet($0.addWillSetObserver { keyPath in
90+
tracking.state.withCriticalRegion { $0.changed = keyPath }
8891
willSetObserver(tracking)
8992
})
9093
case (.none, .some(let didSetObserver)):
91-
return Id.didSet($0.addDidSetObserver {
94+
return Id.didSet($0.addDidSetObserver { keyPath in
95+
tracking.state.withCriticalRegion { $0.changed = keyPath }
9296
didSetObserver(tracking)
9397
})
9498
case (.none, .none):
@@ -114,6 +118,7 @@ public struct ObservationTracking: Sendable {
114118
struct State {
115119
var values = [ObjectIdentifier: ObservationTracking.Id]()
116120
var cancelled = false
121+
var changed: AnyKeyPath?
117122
}
118123

119124
private let state = _ManagedCriticalState(State())
@@ -151,6 +156,11 @@ public struct ObservationTracking: Sendable {
151156
}
152157
}
153158
}
159+
160+
@available(SwiftStdlib 5.11, *)
161+
public var changed: AnyKeyPath? {
162+
state.withCriticalRegion { $0.changed }
163+
}
154164
}
155165

156166
@available(SwiftStdlib 5.9, *)

0 commit comments

Comments
 (0)