Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Added initial state improvement & a minor fix for BluetoothState methods. #371

Merged
merged 3 commits into from
Aug 27, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good point. Thanks for suggesting this changes.

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
return BluetoothState(rawValue: manager.state.rawValue) ?? .unknown
return BluetoothState(rawValue: manager.state.rawValue).unsafelyUnwrapped

}

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
Copy link
Collaborator

@minixT minixT Aug 21, 2020

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'd rather add a new method which will return also current state than change current implementation. This will require less changes for users who already use our library. Can you create create new method for observing state and put there you code?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done :). Let me know what you think.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ping :D

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