File tree Expand file tree Collapse file tree 4 files changed +88
-21
lines changed Expand file tree Collapse file tree 4 files changed +88
-21
lines changed Original file line number Diff line number Diff line change @@ -5,24 +5,6 @@ import Foundation
55 import FoundationNetworking
66#endif
77
8- public final class AuthStateChangeListenerHandle {
9- var onCancel : ( @Sendable ( ) -> Void ) ?
10-
11- public func cancel( ) {
12- onCancel ? ( )
13- onCancel = nil
14- }
15-
16- deinit {
17- cancel ( )
18- }
19- }
20-
21- public typealias AuthStateChangeListener = @Sendable (
22- _ event: AuthChangeEvent ,
23- _ session: Session ?
24- ) -> Void
25-
268public actor AuthClient {
279 /// FetchHandler is a type alias for asynchronous network request handling.
2810 public typealias FetchHandler = @Sendable (
@@ -216,7 +198,7 @@ public actor AuthClient {
216198 @discardableResult
217199 public func onAuthStateChange(
218200 _ listener: @escaping AuthStateChangeListener
219- ) async -> AuthStateChangeListenerHandle {
201+ ) async -> AuthStateChangeListenerRegistration {
220202 let handle = eventEmitter. attachListener ( listener)
221203 await emitInitialSession ( forHandle: handle)
222204 return handle
@@ -240,7 +222,7 @@ public actor AuthClient {
240222 }
241223
242224 continuation. onTermination = { _ in
243- handle. cancel ( )
225+ handle. remove ( )
244226 }
245227 }
246228
Original file line number Diff line number Diff line change 1+ //
2+ // AuthStateChangeListener.swift
3+ //
4+ //
5+ // Created by Guilherme Souza on 17/02/24.
6+ //
7+
8+ import ConcurrencyExtras
9+ import Foundation
10+
11+ /// A listener that can be removed by calling ``AuthStateChangeListenerRegistration/remove()``.
12+ ///
13+ /// - Note: Listener is automatically removed on deinit.
14+ public protocol AuthStateChangeListenerRegistration : Sendable , AnyObject {
15+ /// Removes the listener. After the initial call, subsequent calls have no effect.
16+ func remove( )
17+ }
18+
19+ final class AuthStateChangeListenerHandle : AuthStateChangeListenerRegistration {
20+ let _onRemove = LockIsolated ( ( @Sendable ( ) - > Void) ? . none)
21+
22+ public func remove( ) {
23+ _onRemove. withValue {
24+ if $0 == nil {
25+ return
26+ }
27+
28+ $0 ? ( )
29+ $0 = nil
30+ }
31+ }
32+
33+ deinit {
34+ remove ( )
35+ }
36+ }
37+
38+ public typealias AuthStateChangeListener = @Sendable (
39+ _ event: AuthChangeEvent ,
40+ _ session: Session ?
41+ ) -> Void
Original file line number Diff line number Diff line change @@ -35,7 +35,7 @@ final class DefaultEventEmitter: EventEmitter {
3535 let handle = AuthStateChangeListenerHandle ( )
3636 let key = ObjectIdentifier ( handle)
3737
38- handle. onCancel = { [ weak self] in
38+ handle. _onRemove . setValue { [ weak self] in
3939 self ? . listeners. withValue {
4040 $0 [ key] = nil
4141 }
Original file line number Diff line number Diff line change 1+ //
2+ // AuthStateChangeListenerHandleTests.swift
3+ //
4+ //
5+ // Created by Guilherme Souza on 17/02/24.
6+ //
7+
8+ @testable import Auth
9+ import ConcurrencyExtras
10+ import Foundation
11+ import XCTest
12+
13+ final class AuthStateChangeListenerHandleTests : XCTestCase {
14+ func testRemove( ) {
15+ let handle = AuthStateChangeListenerHandle ( )
16+
17+ let onRemoveCallCount = LockIsolated ( 0 )
18+ handle. _onRemove. setValue {
19+ onRemoveCallCount. withValue {
20+ $0 += 1
21+ }
22+ }
23+
24+ handle. remove ( )
25+ handle. remove ( )
26+
27+ XCTAssertEqual ( onRemoveCallCount. value, 1 )
28+ }
29+
30+ func testDeinit( ) {
31+ var handle : AuthStateChangeListenerHandle ? = AuthStateChangeListenerHandle ( )
32+
33+ let onRemoveCallCount = LockIsolated ( 0 )
34+ handle? . _onRemove. setValue {
35+ onRemoveCallCount. withValue {
36+ $0 += 1
37+ }
38+ }
39+
40+ handle = nil
41+
42+ XCTAssertEqual ( onRemoveCallCount. value, 1 )
43+ }
44+ }
You can’t perform that action at this time.
0 commit comments