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

3
我试图创建一个可观察的序列来指示设备上蓝牙的状态。我正在使用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
这不是一个答案,但你知道有人已经为你做了这项工作吗?https://github.com/Polidea/RxBluetoothKit - Daniel T.
1个回答

7
这正是Subjects擅长的事情。它们主要存在是将非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)

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接