iOS RxSwift如何将Core蓝牙连接到Rx序列?

时间:2018-09-10 19:30:05

标签: ios swift observable core-bluetooth rx-swift

我正在尝试创建一个可观察的序列来指示设备上蓝牙的状态。我正在使用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)
    }
}

1 个答案:

答案 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)
相关问题