Skip to content

Commit

Permalink
Merge pull request #371 from radumvlad/initial-state-when-observing
Browse files Browse the repository at this point in the history
Added initial state improvement & a minor fix for BluetoothState methods.
  • Loading branch information
minixT authored Aug 27, 2020
2 parents 267530a + bb91a9d commit 504eb79
Show file tree
Hide file tree
Showing 6 changed files with 78 additions and 22 deletions.
22 changes: 17 additions & 5 deletions Source/CentralManager.swift
Original file line number Diff line number Diff line change
Expand Up @@ -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) }
Expand Down Expand Up @@ -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<BluetoothState> {
return self.delegateWrapper.didUpdateState.asObservable()
}

public func observeStateWithInitialValue() -> Observable<BluetoothState> {
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
Expand Down
9 changes: 7 additions & 2 deletions Source/ManagerType.swift
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,12 @@ public protocol ManagerType: class {
///
/// It's **infinite** stream, so `.complete` is never called.
func observeState() -> Observable<BluetoothState>

/// 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<BluetoothState>
}

public extension ManagerType {
Expand All @@ -27,8 +33,7 @@ public extension ManagerType {
func ensure<T>(_ state: BluetoothState, observable: Observable<T>) -> Observable<T> {
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)
Expand Down
19 changes: 15 additions & 4 deletions Source/PeripheralManager.swift
Original file line number Diff line number Diff line change
Expand Up @@ -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) }
Expand Down Expand Up @@ -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<BluetoothState> {
return self.delegateWrapper.didUpdateState.asObservable()
}

public func observeStateWithInitialValue() -> Observable<BluetoothState> {
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
Expand Down
22 changes: 17 additions & 5 deletions Tests/Autogenerated/_CentralManager.generated.swift
Original file line number Diff line number Diff line change
Expand Up @@ -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) }
Expand Down Expand Up @@ -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<BluetoothState> {
return self.delegateWrapper.didUpdateState.asObservable()
}

func observeStateWithInitialValue() -> Observable<BluetoothState> {
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
Expand Down
9 changes: 7 additions & 2 deletions Tests/Autogenerated/_ManagerType.generated.swift
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,12 @@ protocol _ManagerType: class {
///
/// It's **infinite** stream, so `.complete` is never called.
func observeState() -> Observable<BluetoothState>

/// 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<BluetoothState>
}

extension _ManagerType {
Expand All @@ -28,8 +34,7 @@ extension _ManagerType {
func ensure<T>(_ state: BluetoothState, observable: Observable<T>) -> Observable<T> {
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)
Expand Down
19 changes: 15 additions & 4 deletions Tests/Autogenerated/_PeripheralManager.generated.swift
Original file line number Diff line number Diff line change
Expand Up @@ -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) }
Expand Down Expand Up @@ -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<BluetoothState> {
return self.delegateWrapper.didUpdateState.asObservable()
}

func observeStateWithInitialValue() -> Observable<BluetoothState> {
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
Expand Down

0 comments on commit 504eb79

Please sign in to comment.