我正在尝试创建一个可观察的序列来指示设备上蓝牙的状态。我正在使用ReplaySubject<CBManagerState>
,但对是否有更好的东西感到好奇,因为我听到有关使用onNext()
将回调委托连接到RxSwift可观察域的适当方法是什么?
class BluetoothStatusMonitor: NSObject, CBPeripheralManagerDelegate {
let bluetoothStatusSequence = ReplaySubject<CBManagerState>.create(bufferSize: 1)
var bluetoothPeripheralManager: CBPeripheralManager?
func checkBluetoothStatus()
{
//silently check permissions, without alert
let options = [CBCentralManagerOptionShowPowerAlertKey:0]
bluetoothPeripheralManager = CBPeripheralManager(delegate: self, queue: nil, options: options)
}
func peripheralManagerDidUpdateState(_ peripheral: CBPeripheralManager) {
bluetoothStatusSequence.onNext(peripheral.state)
}
}
答案 0 :(得分:3)
这正是主题所擅长的。它们主要用于将非Rx代码转换为Rx代码。就是说,RxCocoa具有DelegateProxy
类型,该类型旨在处理正确完成委托所需的许多工作。仍然很难弄清楚如何实现它,但是一旦掌握了它们,它们就非常有用...
我必须承认大多数代码对我来说都是不可思议的,但是它确实有效。我会在下面的评论中尽我所能解释。
import RxSwift
import RxCocoa
import CoreBluetooth
// The HasDelegate protocol is an associated type for the DelegateProxyType
extension CBPeripheralManager: HasDelegate {
public typealias Delegate = CBPeripheralManagerDelegate
}
class CBPeripheralManagerDelegateProxy
: DelegateProxy<CBPeripheralManager, CBPeripheralManagerDelegate>
, DelegateProxyType
, CBPeripheralManagerDelegate {
init(parentObject: CBPeripheralManager) {
super.init(parentObject: parentObject, delegateProxy: CBPeripheralManagerDelegateProxy.self)
}
deinit {
_didUpdateState.onCompleted()
}
static func registerKnownImplementations() {
register { CBPeripheralManagerDelegateProxy(parentObject: $0) }
}
// a couple of static functions for getting and setting a delegate on the object.
static func currentDelegate(for object: CBPeripheralManager) -> CBPeripheralManagerDelegate? {
return object.delegate
}
static func setCurrentDelegate(_ delegate: CBPeripheralManagerDelegate?, to object: CBPeripheralManager) {
object.delegate = delegate
}
// required delegate functions must be implemented in the class. This is where Subjects come in.
func peripheralManagerDidUpdateState(_ peripheral: CBPeripheralManager) {
_didUpdateState.onNext(peripheral.state)
}
fileprivate let _didUpdateState = PublishSubject<CBManagerState>()
}
extension Reactive where Base: CBPeripheralManager {
var delegate: CBPeripheralManagerDelegateProxy {
return CBPeripheralManagerDelegateProxy.proxy(for: base)
}
var state: Observable<CBManagerState> {
return delegate._didUpdateState
}
var didUpdateState: Observable<Void> {
return delegate._didUpdateState.map { _ in }
}
// optional methods are setup using the `methodInvoked` function on the delegate
var willRestoreState: Observable<[String: Any]> {
return delegate.methodInvoked(#selector(CBPeripheralManagerDelegate.peripheralManager(_:willRestoreState:)))
.map { $0[1] as! [String: Any] }
}
var didStartAdvertising: Observable<Error?> {
return delegate.methodInvoked(#selector(CBPeripheralManagerDelegate.peripheralManagerDidStartAdvertising(_:error:)))
.map { $0[1] as? Error }
}
// I didn't implement all of the optionals. Use the above as a template to implement the rest.
}
据我所知,methodInvoked
函数对对象执行一些元编程魔术,以在运行时安装该方法。这样做是因为许多具有委托的iOS类的行为实际上取决于是否在委托上定义了该方法(无论该方法执行了什么),因此行为不同,因此我们不想简单地为代理提供每个方法协议。
当然,一旦您具备以上条件,就可以了。您可以使用外围设备管理器执行所有标准的RX任务:
bluetoothManager.rx.state
.subscribe(onNext: { state in print("current state:", state) })
.disposed(by: disposeBag)
bluetoothManager.rx.didStartAdvertising
.subscribe(onNext: { error in
if let error = error {
print("there was an error:", error)
}
}
.disposed(by: disposeBag)