@@ -55,9 +55,10 @@ import ConcurrencyExtras
5555 /// - apply: A closure that contains properties to track.
5656 /// - Returns: A token that keeps the subscription alive. Observation is cancelled when the token
5757 /// is deallocated.
58+ @inlinable
5859 public func observe(
5960 isolation: ( any Actor ) ? = #isolation,
60- @ _inheritActorContext _ apply: @escaping @Sendable ( ) -> Void
61+ _ apply: @escaping @Sendable ( ) -> Void
6162 ) -> ObserveToken {
6263 observe ( isolation: isolation) { _ in apply ( ) }
6364 }
@@ -116,10 +117,11 @@ import ConcurrencyExtras
116117 /// - onChange: A closure that is triggered after some tracked property has changed
117118 /// - Returns: A token that keeps the subscription alive. Observation is cancelled when the token
118119 /// is deallocated.
120+ @inlinable
119121 public func observe(
120122 isolation: ( any Actor ) ? = #isolation,
121- @ _inheritActorContext _ tracking: @escaping @Sendable ( ) -> Void ,
122- @ _inheritActorContext onChange apply: @escaping @Sendable ( ) -> Void
123+ _ tracking: @escaping @Sendable ( ) -> Void ,
124+ onChange apply: @escaping @Sendable ( ) -> Void
123125 ) -> ObserveToken {
124126 observe (
125127 isolation: isolation,
@@ -137,43 +139,63 @@ import ConcurrencyExtras
137139 /// - apply: A closure that contains properties to track.
138140 /// - Returns: A token that keeps the subscription alive. Observation is cancelled when the token
139141 /// is deallocated.
142+ @inlinable
140143 public func observe(
141144 isolation: ( any Actor ) ? = #isolation,
142- @ _inheritActorContext _ apply: @escaping @Sendable ( _ transaction: UITransaction ) -> Void
145+ _ apply: @escaping @Sendable ( _ transaction: UITransaction ) -> Void
143146 ) -> ObserveToken {
144- let actor = ActorProxy ( base: isolation)
145147 return observe (
148+ isolation: isolation,
146149 apply,
147- task: { transaction, operation in
148- Task {
149- await actor . perform {
150- operation ( )
151- }
152- }
153- }
150+ onChange: apply
154151 )
155152 }
156153
157154
158- /// Tracks access to properties of an observable model.
159- ///
160- /// A version of ``observe(isolation:_:)`` that is handed the current ``UITransaction``.
161- ///
162- /// - Parameters:
163- /// - isolation: The isolation of the observation.
164- /// - tracking: A closure that contains properties to track.
165- /// - onChange: A closure that is triggered after some tracked property has changed
166- /// - Returns: A token that keeps the subscription alive. Observation is cancelled when the token
167- /// is deallocated.
155+ /// Tracks access to properties of an observable model.
156+ ///
157+ /// A version of ``observe(isolation:_:)`` that is handed the current ``UITransaction``.
158+ ///
159+ /// - Parameters:
160+ /// - isolation: The isolation of the observation.
161+ /// - tracking: A closure that contains properties to track.
162+ /// - onChange: A closure that is triggered after some tracked property has changed
163+ /// - Returns: A token that keeps the subscription alive. Observation is cancelled when the token
164+ /// is deallocated.
168165 public func observe(
169166 isolation: ( any Actor ) ? = #isolation,
170- @_inheritActorContext _ tracking: @escaping @Sendable ( UITransaction ) -> Void ,
171- @_inheritActorContext onChange apply: @escaping @Sendable ( _ transaction: UITransaction ) -> Void
167+ _ context: @escaping @Sendable ( UITransaction ) -> Void ,
168+ onChange apply: @escaping @Sendable ( _ transaction: UITransaction ) -> Void
169+ ) -> ObserveToken {
170+ apply ( . current)
171+
172+ return onChange (
173+ isolation: isolation,
174+ of: context,
175+ perform: apply
176+ )
177+ }
178+
179+ /// Tracks access to properties of an observable model.
180+ ///
181+ /// A version of ``observe(isolation:_:onChange:)`` that is handed the current ``UITransaction``
182+ /// that doesn't have initial application of the operation. Operation block is only called on observed context change.
183+ ///
184+ /// - Parameters:
185+ /// - isolation: The isolation of the observation.
186+ /// - tracking: A closure that contains properties to track.
187+ /// - onChange: A closure that is triggered after some tracked property has changed
188+ /// - Returns: A token that keeps the subscription alive. Observation is cancelled when the token
189+ /// is deallocated.
190+ public func onChange(
191+ isolation: ( any Actor ) ? = #isolation,
192+ of context: @escaping @Sendable ( UITransaction ) -> Void ,
193+ perform operation: @escaping @Sendable ( _ transaction: UITransaction ) -> Void
172194 ) -> ObserveToken {
173195 let actor = ActorProxy ( base: isolation)
174- return observe (
175- tracking ,
176- onChange : apply ,
196+ return onChange (
197+ of : context ,
198+ perform : operation ,
177199 task: { transaction, operation in
178200 Task {
179201 await actor . perform {
@@ -207,57 +229,55 @@ func observe(
207229 Task ( operation: $1)
208230 }
209231) -> ObserveToken {
210- let token = ObserveToken ( )
211- onChange (
212- { [ weak token] transaction in
213- guard
214- let token,
215- !token. isCancelled
216- else { return }
217-
218- var perform : @Sendable ( ) -> Void = { apply ( transaction) }
219- for key in transaction. storage. keys {
220- guard let keyType = key. keyType as? any _UICustomTransactionKey . Type
221- else { continue }
222- func open< K: _UICustomTransactionKey > ( _: K . Type ) {
223- perform = { [ perform] in
224- K . perform ( value: transaction [ K . self] ) {
225- perform ( )
226- }
227- }
228- }
229- open ( keyType)
230- }
231- perform ( )
232- } ,
232+ observe (
233+ apply,
234+ onChange: apply,
233235 task: task
234236 )
235- return token
236237}
237238
238239func observe(
239- _ tracking : @escaping @Sendable ( _ transaction: UITransaction ) -> Void ,
240+ _ context : @escaping @Sendable ( _ transaction: UITransaction ) -> Void ,
240241 onChange apply: @escaping @Sendable ( _ transaction: UITransaction ) -> Void ,
241242 task: @escaping @Sendable (
242243 _ transaction: UITransaction ,
243244 _ operation: @escaping @Sendable ( ) -> Void
244245 ) -> Void = {
245246 Task ( operation: $1)
246247 }
248+ ) -> ObserveToken {
249+ apply ( . current)
250+
251+ return SwiftNavigation . onChange (
252+ of: context,
253+ perform: apply,
254+ task: task
255+ )
256+ }
257+
258+ func onChange(
259+ of context: @escaping @Sendable ( _ transaction: UITransaction ) -> Void ,
260+ perform operation: @escaping @Sendable ( _ transaction: UITransaction ) -> Void ,
261+ task: @escaping @Sendable (
262+ _ transaction: UITransaction ,
263+ _ operation: @escaping @Sendable ( ) -> Void
264+ ) -> Void = {
265+ Task ( operation: $1)
266+ }
247267) -> ObserveToken {
248268 let token = ObserveToken ( )
249- SwiftNavigation . onChange (
269+ SwiftNavigation . withRecursivePerceptionTracking (
250270 of: { [ weak token] transaction in
251271 guard let token, !token. isCancelled else { return }
252- tracking ( transaction)
272+ context ( transaction)
253273 } ,
254274 perform: { [ weak token] transaction in
255275 guard
256276 let token,
257277 !token. isCancelled
258278 else { return }
259279
260- var perform : @Sendable ( ) -> Void = { apply ( transaction) }
280+ var perform : @Sendable ( ) -> Void = { operation ( transaction) }
261281 for key in transaction. storage. keys {
262282 guard let keyType = key. keyType as? any _UICustomTransactionKey . Type
263283 else { continue }
@@ -277,37 +297,22 @@ func observe(
277297 return token
278298}
279299
280- private func onChange(
281- _ apply: @escaping @Sendable ( _ transaction: UITransaction ) -> Void ,
282- task: @escaping @Sendable (
283- _ transaction: UITransaction , _ operation: @escaping @Sendable ( ) -> Void
284- ) -> Void
285- ) {
286- withPerceptionTracking {
287- apply ( . current)
288- } onChange: {
289- task ( . current) {
290- onChange ( apply, task: task)
291- }
292- }
293- }
294-
295- private func onChange(
296- of tracking: @escaping @Sendable ( _ transaction: UITransaction ) -> Void ,
300+ private func withRecursivePerceptionTracking(
301+ of context: @escaping @Sendable ( _ transaction: UITransaction ) -> Void ,
297302 perform operation: @escaping @Sendable ( _ transaction: UITransaction ) -> Void ,
298303 task: @escaping @Sendable (
299304 _ transaction: UITransaction ,
300305 _ operation: @escaping @Sendable ( ) -> Void
301306 ) -> Void
302307) {
303- operation ( . current)
304-
305308 withPerceptionTracking {
306- tracking ( . current)
309+ context ( . current)
307310 } onChange: {
308311 task ( . current) {
309- onChange (
310- of: tracking,
312+ operation ( . current)
313+
314+ withRecursivePerceptionTracking (
315+ of: context,
311316 perform: operation,
312317 task: task
313318 )
0 commit comments