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

How do I stop RxSwift ble scanner once it has found a match?

我有一个 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 { [=10=] == .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: { [=11=].identifier.uuidString == door.dPeripheralId }) }
        }
}

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

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

它永远不会到达 onCompleted,因为即使在找到 filtered core data 匹配后,它也会一直扫描下去。在 Apple 的框架 coreBluetooth 中,我可以在找到我想要的内容后简单地调用 manager.stopScan(),但是 Rx 对应的框架似乎不可用。它如何适用于 RxSwift

您可以创建一个新的 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 will make sure that only lists that contain the device you're looking for are passed on and the take(1) operator 将获取第一个发出的值并立即完成。

deferred 调用确保第一行中执行的获取请求不会在您调用 scanAndFilter() 时执行,而只会在有人实际订阅生成的 Observable 时执行。

如果只想让一个事件退出过滤算子,那么就用.take(1)。 Observable 将在发出单个值后关闭。如果BLE函数写对了,Disposable处理时会调用stopScan()

我不知道为什么另一个答案说“始终确保将 return Observables 的所有函数包装到 .deferred 中。自 2015 年以来我一直在使用 RxSwift,并且我已经只需要延迟一次。当然不是每次我调用 returned 一个 Observable 的函数时。