一旦找到匹配项,如何停止RxSwift ble扫描仪?

问题描述 投票:1回答:2

我有一个工作正常且外观如下的ble扫描仪:

func scan(serviceId: String) -> Observable<[BleHandler.BlePeripheral]> {
    knownDevices = []
    return waitForBluetooth()
        .flatMap { _ in self.scanForPeripheral(serviceId: serviceId) }
        .map { _ in self.knownDevices }
}

private func waitForBluetooth() -> Observable<BluetoothState> {
    return self.manager
        .observeState()
        .startWith(self.manager.state)
        .filter { $0 == .poweredOn }
        .take(1)
}

然后在viewModel class中过滤来自core data的匹配项:

func scanAndFilter() -> Observable<[LocalDoorCoreDataObject]> {
        let persistingDoors: [LocalDoorCoreDataObject] = coreDataHandler.fetchAll(fetchRequest: NSFetchRequest<LocalDoorCoreDataObject>(entityName: "LocalDoorCoreDataObject"))

    return communicationService
        .scanForDevices(register: false)
        .map{ peripherals in
            print("🐶 THIS WILL GO ON FOR ETERNITY", peripherals.count)
            self.knownDevices = peripherals
            return persistingDoors
                .filter { door in peripherals.contains(where: { $0.identifier.uuidString == door.dPeripheralId }) }
        }
}

并且在view中,我想在扫描完成后连接:

private func scanAndConnect(data: LocalDoorCoreDataObject) {
    viewModel.scanRelay().subscribe(
        onNext: {
            print("🐶SCANNED NAME", $0.first?.dName)},
        onCompleted: {
            print("🐶COMPLETED SCAN")
            self.connectToFilteredPeripheral(localDoor: data)
    }).disposed(by: disposeBag)
}

它永远不会到达onCompleted,因为即使找到并与filtered匹配core data,它也只会扫描永恒。在Apple的框架coreBluetooth中,我可以在找到我想要的内容后简单地调用manager.stopScan(),但是Rx对应对象上似乎没有这个功能。 RxSwift

如何工作
ios swift bluetooth-lowenergy rx-swift rxbluetooth
2个回答
0
投票

首先,始终确保将所有返回Observable的函数包装到Observable.deferred中(更多信息here)。

您可以创建一个新的Observable来查找设备,然后在找到要查找的设备后立即完成。类似于:

func scanAndFilter() -> Observable<[LocalDoorCoreDataObject]> {
        return Observable.deferred { in
            let persistingDoors: [LocalDoorCoreDataObject] = coreDataHandler.fetchAll(fetchRequest: NSFetchRequest<LocalDoorCoreDataObject>(entityName: "LocalDoorCoreDataObject"))

            return communicationService
                .scanForDevices(register: false)
                .filter { /* verify if the device(s) you're looking for is/are in this list */ }
                .take(1)
        }
    }

filter operator将确保仅传递包含您要查找的设备的列表,并且filter将采用第一个发出的值并立即完成。


0
投票

如果只希望一个事件退出过滤器运算符,则只需使用take(1) operator。 Observable发出单个值后将关闭。如果BLE功能编写正确,则处置Disposable时它将调用take(1)

我不知道为什么另一个答案说“总是确保将所有返回Observables的函数包装到.take(1)中。自2015年以来我一直在使用RxSwift,而我只需要推迟一次。当然不是每个我调用了一个返回Observable的函数。

© www.soinside.com 2019 - 2024. All rights reserved.