ios - 如何在 Observable 属性上过滤 Observable?

标签 ios swift3 rx-swift

问题是我有一个协议(protocol),其中包含我想要在可用时对其进行排序的属性。因为我正在努力让一切变得超响应式。

protocol DeviceConnectionProtocol {
...
    var id : Observable<String> { get }
...
}

我现在的情况是,我想找到我最后连接的设备,无论 url/name/etc 是否发生变化。

  class DeviceFinder {

    let rx_DeviceList = Variable([DeviceConnectionProtocol]())
    let disposeBag = DisposeBag()

    init() {
        SMOIPConnection.FindDevices().subscribe(onNext : { smoip in
            self.rx_DeviceList.value.append(smoip)
        }).addDisposableTo(disposeBag)

        MockDevice.FindDevices().subscribe(onNext : { mock in
            self.rx_DeviceList.value.append(mock)
        }).addDisposableTo(disposeBag)

    }

}

...

这是我迄今为止的排序功能。但它是行不通的,因为 device.id.map 返回一个 Observable 而不是过滤器操作所需的 Bool

struct LastConnectedDevice {

    private static let lastConnectedKeyForID = "lastConnected"

    static func get() -> Observable<DeviceConnectionProtocol>{
    let lastID = UserDefaults.standard.string(forKey: lastConnectedKeyForID)
       return DeviceFinder().rx_DeviceList.asObservable().flatMap{list in
            return Observable.from(list)
            }.filter { (device : DeviceConnectionProtocol) -> Bool in
                return device.id.map{ id in
                    return id == lastID
                }
        }
    }
}

最佳答案

诊断

根据我对您问题的理解,您在执行过滤操作时遇到困难,因为该属性是 Observable<Int>而不是Int 。这意味着您不能仅使用等于运算符检查 ID,因为您 need to get out of the Rx monad .

留在 Rx Monad

更优雅的 FRP 解决方案:

  1. 定义您的设备可观察对象。
  2. 定义可观察的设备 ID。
  3. Zip他们在一起。
  4. Filter通过 checking最后的设备 ID。
  5. 返回所需的数据类型 ( DeviceConnectionProtocol )。
  6. 使用最后一个设备执行必要的代码。

这是 RxSwift 代码。我的一些类定义可以在下面的代码块中看到。

// Observable<DeviceConnectionProtocol>
let devices = rx_DeviceList
    .asObservable()
    .flatMap { array in Observable.from(array) } 

// Observable<Int>
let deviceIDs = devices
    .flatMap { device in device.id } 

Observable.zip(devices, deviceIDs) { $0 } 

    // data type of (DeviceConnectionProtocol, Int)
    .filter { $0.1 == lastID }
    .map { $0.0 }
    .subscribe(onNext: lastDeviceSelected)

Monad 只是一种表达范式、处理方式或思维方式的方式。您始终可以退出 RxMonad,这意味着离开数据流并返回命令式代码。这是程序员比较习惯的。


退出 Rx Monad 的简单方法

这是一个(有点困惑)的解决方案。 TL;DR 请转到如何同步退出 RxMonad 部分。

import RxSwift

protocol DeviceConnectionProtocol {
    var id : Observable<String> { get }
}


class Person : DeviceConnectionProtocol {
    var myName: String! = nil

    init(name: String) {
        self.myName = name
    }

    var id: Observable<String> {
        return Observable.create { [unowned self] obx in
            obx.onNext(self.myName)
            return Disposables.create()
        }
    }
}
let rx_DeviceList = Variable([DeviceConnectionProtocol]())
let disposeBag = DisposeBag()

let lastID = "Hillary"

func lastDeviceSelected(device: DeviceConnectionProtocol) {
    if let person = device as? Person {
        print(person.myName + " was found!")
    }
}

rx_DeviceList
    .asObservable()
    .flatMap { array in Observable.from(array) }
    .filter{ (device: DeviceConnectionProtocol) -> Bool in

        // How to exit the RxMonad synchronously

        // Have a result variable
        var currentID = ""

        // Subscribe on the observable on the default schedulers (main thread) and assign result
        device.id.subscribe(onNext: { (id: String) in currentID = id })

        // Return result
        return lastID == currentID
    }
    .subscribe(onNext: lastDeviceSelected)

rx_DeviceList.value = [Person(name: "Donald"), Person(name: "Goofy"), Person(name: "Hillary")]

结果:

Hillary was found!

请注意,以 [1,2,3,4,5] 结尾的序列可以使用 takeLast运算符,但由于某种原因,您的情况不同并且不起作用。

引用和注释

  1. 这是一个 Github Gist如果您想要在 Rx Playground 上运行的整个代码。

  2. zip可视化运算符(operator) RxMarbles .

  3. zip运算符(operator)documentation .

  4. filter可视化运算符(operator) RxMarbles .

  5. filter运算符(operator)documentation .

  6. 这是一个 Swift 3 解决方案。

关于ios - 如何在 Observable 属性上过滤 Observable?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/40405811/

相关文章:

ios - 如何在 swift 中使用加速度计和重力检测苹果 watch 的位置?

Swift 3 私有(private)继承

ios - Xcode 中两个目标中的 swift 包导致重复符号

ios - 将 iOS 核心数据添加到现有项目 - 展开可选值时出错

ios - App Store 的存档 IPA 大小大于 Ad Hoc

ios - 无法将自定义类分配给 Xcode 7 中的 View

ios - 如何在RxBluetoothKit中处理 “Ambiguous reference to member ' = ='”?

ios - 通过自动布局在 UIScrollView 中使用顶部布局指南

ios - 在 ios swift 3.0 中解析 json 对象数组

swift - Rx swift : disposed(by:) weirdness