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

标签 ios swift observable core-bluetooth rx-swift

我正在尝试创建一个可观察的序列来指示设备上蓝牙的状态。我正在使用 ReplaySubject<CBManagerState> , 但很好奇是否有更好的东西,因为我听说使用 onNext() 不好

将回调委托(delegate)连接到 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)
    }
}

最佳答案

这正是 Subjects 擅长的事情。它们的存在主要是为了将非 Rx 代码转换为 Rx 代码。也就是说,RxCocoa 具有 DelegateProxy 类型,旨在处理正确执行委托(delegate)所需的大量工作。仍然很难弄清楚具体如何实现,但一旦掌握了窍门,它们就会非常有用...

我不得不承认大部分代码对我来说都是黑魔法,但它确实有效。我尽量在下面的评论中解释。

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 函数对对象执行了一些元编程魔术,以便在运行时安装该方法。这样做是因为许多具有委托(delegate)的 iOS 类实际上根据是否在委托(delegate)上定义了方法(不管方法做什么)而表现不同,所以我们不想简单地给代理中的每个方法协议(protocol)。

当然,一旦您具备上述条件。您可以使用外设管理器执行所有标准 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)

关于iOS RxSwift 如何将核心蓝牙连接到 Rx 序列?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/52264303/

相关文章:

ios - 有没有办法在倒数计时器中使用 UIButton 作为文本?

ios - 如何找到 UInt64 之间的随机数? ( swift )

ios - 如何从 mapView 中删除我的自定义注释?

ios - 在 iOS 应用程序上控制语言

swift - 如何检测 swift 应用程序何时从后台变为前台?

ios - 是否可以禁用点击自定义 UITableViewCell 的附件 View 部分?

ios - IOS 中 url 的 %20 个空格

iOS swift : autoresize collection view nested inside a table view cell

angular - 在组件之间共享一个 observable/在 Angular2 中多播一个 observable

angular - 类型 'Observable<string[]>' 缺少类型 'string[]' 的以下属性 : length, pop、push、concat 和另外 25 个