diff --git a/Source/CentralManager.swift b/Source/CentralManager.swift index 7437a8ae..123d485f 100644 --- a/Source/CentralManager.swift +++ b/Source/CentralManager.swift @@ -8,11 +8,11 @@ public typealias DisconnectionReason = Error /// CentralManager is a class implementing ReactiveX API which wraps all Core Bluetooth Manager's functions allowing to /// discover, connect to remote peripheral devices and more. /// You can start using this class by discovering available services of nearby peripherals. Before calling any -/// public `CentralManager`'s functions you should make sure that Bluetooth is turned on and powered on. It can be done -/// by calling and observing returned value of `observeState()` and then chaining it with `scanForPeripherals(_:options:)`: +/// public `CentralManager`'s functions you should make sure that Bluetooth is turned on and powered on. +/// It can be done by calling and observing returned value of `observeStateWithInitialValue()` and then +/// chaining it with `scanForPeripherals(_:options:)`: /// ``` -/// let disposable = centralManager.observeState -/// .startWith(centralManager.state) +/// let disposable = centralManager.observeStateWithInitialValue() /// .filter { $0 == .poweredOn } /// .take(1) /// .flatMap { centralManager.scanForPeripherals(nil) } @@ -92,13 +92,25 @@ public class CentralManager: ManagerType { // MARK: State public var state: BluetoothState { - return BluetoothState(rawValue: manager.state.rawValue) ?? .unsupported + return BluetoothState(rawValue: manager.state.rawValue) ?? .unknown } public func observeState() -> Observable { return self.delegateWrapper.didUpdateState.asObservable() } + public func observeStateWithInitialValue() -> Observable { + return Observable.deferred { [weak self] in + guard let self = self else { + RxBluetoothKitLog.w("observeState - CentralManager deallocated") + return .never() + } + + return self.delegateWrapper.didUpdateState.asObservable() + .startWith(self.state) + } + } + // MARK: Scanning /// Scans for `Peripheral`s after subscription to returned observable. First parameter `serviceUUIDs` is diff --git a/Source/ManagerType.swift b/Source/ManagerType.swift index ae5e189c..b99481b0 100644 --- a/Source/ManagerType.swift +++ b/Source/ManagerType.swift @@ -16,6 +16,12 @@ public protocol ManagerType: class { /// /// It's **infinite** stream, so `.complete` is never called. func observeState() -> Observable + + /// Continuous state of `CBManager` instance described by `BluetoothState` which is equivalent to [CBManagerState](https://developer.apple.com/documentation/corebluetooth/cbmanagerstate). + /// - returns: Observable that emits `next` event starting with current state and whenever state changes. + /// + /// It's **infinite** stream, so `.complete` is never called. + func observeStateWithInitialValue() -> Observable } public extension ManagerType { @@ -27,8 +33,7 @@ public extension ManagerType { func ensure(_ state: BluetoothState, observable: Observable) -> Observable { return .deferred { [weak self] in guard let strongSelf = self else { throw BluetoothError.destroyed } - let statesObservable = strongSelf.observeState() - .startWith(strongSelf.state) + let statesObservable = strongSelf.observeStateWithInitialValue() .filter { $0 != state && BluetoothError(state: $0) != nil } .map { state -> T in throw BluetoothError(state: state)! } return .absorb(statesObservable, observable) diff --git a/Source/PeripheralManager.swift b/Source/PeripheralManager.swift index 07b0c8b0..4740e67f 100644 --- a/Source/PeripheralManager.swift +++ b/Source/PeripheralManager.swift @@ -6,10 +6,9 @@ import RxSwift /// advertise, to publish L2CAP channels and more. /// You can start using this class by adding services and starting advertising. /// Before calling any public `PeripheralManager`'s functions you should make sure that Bluetooth is turned on and powered on. It can be done -/// by `observeState()`, observing it's value and then chaining it with `add(_:)` and `startAdvertising(_:)`: +/// by `observeStateWithInitialValue()`, observing it's value and then chaining it with `add(_:)` and `startAdvertising(_:)`: /// ``` -/// let disposable = centralManager.observeState -/// .startWith(centralManager.state) +/// let disposable = centralManager.observeStateWithInitialValue() /// .filter { $0 == .poweredOn } /// .take(1) /// .flatMap { centralManager.add(myService) } @@ -69,13 +68,25 @@ public class PeripheralManager: ManagerType { // MARK: State public var state: BluetoothState { - return BluetoothState(rawValue: manager.state.rawValue) ?? .unsupported + return BluetoothState(rawValue: manager.state.rawValue) ?? .unknown } public func observeState() -> Observable { return self.delegateWrapper.didUpdateState.asObservable() } + public func observeStateWithInitialValue() -> Observable { + return Observable.deferred { [weak self] in + guard let self = self else { + RxBluetoothKitLog.w("observeState - PeripheralManager deallocated") + return .never() + } + + return self.delegateWrapper.didUpdateState.asObservable() + .startWith(self.state) + } + } + // MARK: Advertising /// Starts peripheral advertising on subscription. It create inifinite observable diff --git a/Tests/Autogenerated/_CentralManager.generated.swift b/Tests/Autogenerated/_CentralManager.generated.swift index ad0a5cb8..c900acf0 100644 --- a/Tests/Autogenerated/_CentralManager.generated.swift +++ b/Tests/Autogenerated/_CentralManager.generated.swift @@ -9,11 +9,11 @@ typealias DisconnectionReason = Error /// _CentralManager is a class implementing ReactiveX API which wraps all Core Bluetooth Manager's functions allowing to /// discover, connect to remote peripheral devices and more. /// You can start using this class by discovering available services of nearby peripherals. Before calling any -/// public `_CentralManager`'s functions you should make sure that Bluetooth is turned on and powered on. It can be done -/// by calling and observing returned value of `observeState()` and then chaining it with `scanForPeripherals(_:options:)`: +/// public `_CentralManager`'s functions you should make sure that Bluetooth is turned on and powered on. +/// It can be done by calling and observing returned value of `observeStateWithInitialValue()` and then +/// chaining it with `scanForPeripherals(_:options:)`: /// ``` -/// let disposable = centralManager.observeState -/// .startWith(centralManager.state) +/// let disposable = centralManager.observeStateWithInitialValue() /// .filter { $0 == .poweredOn } /// .take(1) /// .flatMap { centralManager.scanForPeripherals(nil) } @@ -93,13 +93,25 @@ class _CentralManager: _ManagerType { // MARK: State var state: BluetoothState { - return BluetoothState(rawValue: manager.state.rawValue) ?? .unsupported + return BluetoothState(rawValue: manager.state.rawValue) ?? .unknown } func observeState() -> Observable { return self.delegateWrapper.didUpdateState.asObservable() } + func observeStateWithInitialValue() -> Observable { + return Observable.deferred { [weak self] in + guard let self = self else { + RxBluetoothKitLog.w("observeState - _CentralManager deallocated") + return .never() + } + + return self.delegateWrapper.didUpdateState.asObservable() + .startWith(self.state) + } + } + // MARK: Scanning /// Scans for `_Peripheral`s after subscription to returned observable. First parameter `serviceUUIDs` is diff --git a/Tests/Autogenerated/_ManagerType.generated.swift b/Tests/Autogenerated/_ManagerType.generated.swift index 9a02a1da..eb604dae 100644 --- a/Tests/Autogenerated/_ManagerType.generated.swift +++ b/Tests/Autogenerated/_ManagerType.generated.swift @@ -17,6 +17,12 @@ protocol _ManagerType: class { /// /// It's **infinite** stream, so `.complete` is never called. func observeState() -> Observable + + /// Continuous state of `CBManagerMock` instance described by `BluetoothState` which is equivalent to [CBManagerState](https://developer.apple.com/documentation/corebluetooth/cbmanagerstate). + /// - returns: Observable that emits `next` event starting with current state and whenever state changes. + /// + /// It's **infinite** stream, so `.complete` is never called. + func observeStateWithInitialValue() -> Observable } extension _ManagerType { @@ -28,8 +34,7 @@ extension _ManagerType { func ensure(_ state: BluetoothState, observable: Observable) -> Observable { return .deferred { [weak self] in guard let strongSelf = self else { throw _BluetoothError.destroyed } - let statesObservable = strongSelf.observeState() - .startWith(strongSelf.state) + let statesObservable = strongSelf.observeStateWithInitialValue() .filter { $0 != state && _BluetoothError(state: $0) != nil } .map { state -> T in throw _BluetoothError(state: state)! } return .absorb(statesObservable, observable) diff --git a/Tests/Autogenerated/_PeripheralManager.generated.swift b/Tests/Autogenerated/_PeripheralManager.generated.swift index 677b4074..abb7ce0a 100644 --- a/Tests/Autogenerated/_PeripheralManager.generated.swift +++ b/Tests/Autogenerated/_PeripheralManager.generated.swift @@ -7,10 +7,9 @@ import RxSwift /// advertise, to publish L2CAP channels and more. /// You can start using this class by adding services and starting advertising. /// Before calling any public `_PeripheralManager`'s functions you should make sure that Bluetooth is turned on and powered on. It can be done -/// by `observeState()`, observing it's value and then chaining it with `add(_:)` and `startAdvertising(_:)`: +/// by `observeStateWithInitialValue()`, observing it's value and then chaining it with `add(_:)` and `startAdvertising(_:)`: /// ``` -/// let disposable = centralManager.observeState -/// .startWith(centralManager.state) +/// let disposable = centralManager.observeStateWithInitialValue() /// .filter { $0 == .poweredOn } /// .take(1) /// .flatMap { centralManager.add(myService) } @@ -70,13 +69,25 @@ class _PeripheralManager: _ManagerType { // MARK: State var state: BluetoothState { - return BluetoothState(rawValue: manager.state.rawValue) ?? .unsupported + return BluetoothState(rawValue: manager.state.rawValue) ?? .unknown } func observeState() -> Observable { return self.delegateWrapper.didUpdateState.asObservable() } + func observeStateWithInitialValue() -> Observable { + return Observable.deferred { [weak self] in + guard let self = self else { + RxBluetoothKitLog.w("observeState - _PeripheralManager deallocated") + return .never() + } + + return self.delegateWrapper.didUpdateState.asObservable() + .startWith(self.state) + } + } + // MARK: Advertising /// Starts peripheral advertising on subscription. It create inifinite observable