@@ -98,18 +98,21 @@ public final class DarwinCentral: CentralManager, ObservableObject {
9898 self . log ? ( " Discovered \( self . cache. peripherals. count) peripherals " )
9999 }
100100 } ) { continuation in
101- self . async {
101+ self . async { [ unowned self ] in
102102 self . stopScan ( )
103- // disconnect all first
104- self . _disconnectAll ( )
105- // queue scan operation
106- let operation = Operation . Scan (
107- services: services,
108- filterDuplicates: filterDuplicates,
109- continuation: continuation
110- )
111- self . continuation. scan = operation
112- self . execute ( operation)
103+ }
104+ Task {
105+ await self . disconnectAll ( )
106+ self . async { [ unowned self] in
107+ // queue scan operation
108+ let operation = Operation . Scan (
109+ services: services,
110+ filterDuplicates: filterDuplicates,
111+ continuation: continuation
112+ )
113+ self . continuation. scan = operation
114+ self . execute ( operation)
115+ }
113116 }
114117 }
115118 }
@@ -145,36 +148,22 @@ public final class DarwinCentral: CentralManager, ObservableObject {
145148 }
146149 }
147150
148- public func disconnect( _ peripheral: Peripheral ) {
149- self . async { [ weak self] in
150- guard let self = self else { return }
151- if self . _disconnect ( peripheral) {
152- self . log ? ( " Will disconnect \( peripheral) " )
153- }
154- }
155- }
156-
157- private func _disconnect( _ peripheral: Peripheral ) -> Bool {
158- guard let peripheralObject = self . cache. peripherals [ peripheral] else {
159- return false
160- }
161- self . continuation. peripherals [ peripheral] ? . didDisconnect ( )
162- self . centralManager. cancelPeripheralConnection ( peripheralObject)
163- return true
164- }
165-
166- public func disconnectAll( ) {
167- self . log ? ( " Will disconnect all " )
168- self . async { [ weak self] in
169- guard let self = self else { return }
170- self . _disconnectAll ( )
151+ public func disconnect( _ peripheral: Peripheral ) async {
152+ try ? await queue ( for: peripheral) { continuation in
153+ Operation . Disconnect (
154+ peripheral: peripheral,
155+ continuation: continuation
156+ )
171157 }
172158 }
173159
174- private func _disconnectAll( ) {
175- for (peripheral, peripheralObject) in self . cache. peripherals {
176- self . continuation. peripherals [ peripheral] ? . didDisconnect ( )
177- self . centralManager. cancelPeripheralConnection ( peripheralObject)
160+ public func disconnectAll( ) async {
161+ let connected = await self . peripherals
162+ . filter { $0. value }
163+ . keys
164+
165+ for peripheral in connected {
166+ await disconnect ( peripheral)
178167 }
179168 }
180169
@@ -347,7 +336,8 @@ public final class DarwinCentral: CentralManager, ObservableObject {
347336 #endif
348337 return try await withThrowingContinuation ( for: peripheral, function: function) { continuation in
349338 let queuedOperation = QueuedOperation ( operation: operation ( continuation) )
350- self . async {
339+ self . async { [ unowned self] in
340+ self . stopScan ( ) // stop scanning
351341 let context = self . continuation ( for: peripheral)
352342 context. operations. push ( queuedOperation)
353343 }
@@ -537,13 +527,15 @@ private extension DarwinCentral {
537527
538528fileprivate extension DarwinCentral . PeripheralContinuationContext {
539529
540- func didDisconnect( ) {
541- let error = CentralError . disconnected
530+ func didDisconnect( _ error: Swift . Error ? = nil ) {
531+ let error = error ?? CentralError . disconnected
532+ // resume all pending operations
542533 while operations. isEmpty == false {
543534 operations. pop {
544535 $0. operation. resume ( throwing: error)
545536 }
546537 }
538+ // end all notifications with disconnect error
547539 notificationStream. values. forEach {
548540 $0. finish ( throwing: error)
549541 }
@@ -578,6 +570,7 @@ internal extension DarwinCentral {
578570
579571 enum Operation {
580572 case connect( Connect )
573+ case disconnect( Disconnect )
581574 case discoverServices( DiscoverServices )
582575 case discoverIncludedServices( DiscoverIncludedServices )
583576 case discoverCharacteristics( DiscoverCharacteristics )
@@ -598,6 +591,8 @@ internal extension DarwinCentral.Operation {
598591 switch self {
599592 case let . connect( operation) :
600593 operation. continuation. resume ( throwing: error)
594+ case let . disconnect( operation) :
595+ operation. continuation. resume ( throwing: error)
601596 case let . discoverServices( operation) :
602597 operation. continuation. resume ( throwing: error)
603598 case let . discoverIncludedServices( operation) :
@@ -657,6 +652,12 @@ internal extension DarwinCentral.Operation {
657652 var operation : DarwinCentral . Operation { . connect( self ) }
658653 }
659654
655+ struct Disconnect : DarwinCentralOperation {
656+ let peripheral : DarwinCentral . Peripheral
657+ let continuation : PeripheralContinuation < ( ) , Error >
658+ var operation : DarwinCentral . Operation { . disconnect( self ) }
659+ }
660+
660661 struct DiscoverServices : DarwinCentralOperation {
661662 let peripheral : DarwinCentral . Peripheral
662663 let services : Set < BluetoothUUID >
@@ -750,6 +751,8 @@ internal extension DarwinCentral {
750751 switch operation {
751752 case let . connect( operation) :
752753 return execute ( operation)
754+ case let . disconnect( operation) :
755+ return execute ( operation)
753756 case let . discoverServices( operation) :
754757 return execute ( operation)
755758 case let . discoverIncludedServices( operation) :
@@ -790,6 +793,21 @@ internal extension DarwinCentral {
790793 return true
791794 }
792795
796+ func execute( _ operation: Operation . Disconnect ) -> Bool {
797+ log ? ( " Will disconnect \( operation. peripheral) " )
798+ // check power on
799+ guard validateState ( . poweredOn, for: operation. continuation) else {
800+ return false
801+ }
802+ // get peripheral
803+ guard let peripheralObject = validatePeripheral ( operation. peripheral, for: operation. continuation) else {
804+ return false
805+ }
806+ // connect
807+ self . centralManager. cancelPeripheralConnection ( peripheralObject)
808+ return true
809+ }
810+
793811 func execute( _ operation: Operation . DiscoverServices ) -> Bool {
794812 log ? ( " Peripheral \( operation. peripheral) will discover services " )
795813 // check power on
@@ -1246,7 +1264,7 @@ internal extension DarwinCentral {
12461264
12471265 @objc ( centralManager: didDisconnectPeripheral: error: )
12481266 func centralManager(
1249- _ central : CBCentralManager ,
1267+ _ centralManager : CBCentralManager ,
12501268 didDisconnectPeripheral corePeripheral: CBPeripheral ,
12511269 error: Swift . Error ?
12521270 ) {
@@ -1261,7 +1279,16 @@ internal extension DarwinCentral {
12611279 assertionFailure ( " Missing context " )
12621280 return
12631281 }
1264- context. didDisconnect ( )
1282+ // user requested disconnection
1283+ if error == nil {
1284+ self . central. dequeue ( for: peripheral, result: . success( ( ) ) , filter: { ( operation: DarwinCentral . Operation ) -> ( Operation . Disconnect ? ) in
1285+ guard case let . disconnect( disconnectOperation) = operation else {
1286+ return nil
1287+ }
1288+ return disconnectOperation
1289+ } )
1290+ }
1291+ context. didDisconnect ( error)
12651292 self . central. objectWillChange. send ( )
12661293 }
12671294
0 commit comments