菜鸟教程小白 发表于 2022-12-12 12:16:32

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


                                            <p><p>问题是我有一个协议(protocol),其中包含我想要在可用时对其进行排序的属性。当我试图让一切都变得 superreact 时。</p>

<pre><code>protocol DeviceConnectionProtocol {
...
    var id : Observable&lt;String&gt; { get }
...
}
</code></pre>

<p>而我的情况是,无论 url/name/etc 是否更改,我都想找到我连接的最后一个设备。</p>

<pre><code>class DeviceFinder {

    let rx_DeviceList = Variable(())
    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)

    }

}
</code></pre>

<p>...</p>

<p>这是我目前的排序功能。但它不可行,因为 device.id.map 返回一个 Observable 而不是过滤操作所需的 Bool </p>

<pre><code>struct LastConnectedDevice {

    private static let lastConnectedKeyForID = &#34;lastConnected&#34;

    static func get() -&gt; Observable&lt;DeviceConnectionProtocol&gt;{
    let lastID = UserDefaults.standard.string(forKey: lastConnectedKeyForID)
       return DeviceFinder().rx_DeviceList.asObservable().flatMap{list in
            return Observable.from(list)
            }.filter { (device : DeviceConnectionProtocol) -&gt; Bool in
                return device.id.map{ id in
                  return id == lastID
                }
      }
    }
}
</code></pre></p>
                                    <br><hr><h1><strong>Best Answer-推荐答案</ strong></h1><br>
                                            <p><h2>诊断</h2>

<p>根据我对您问题的理解,您在执行过滤操作时遇到了困难,因为该属性是 <code>Observable<Int></code> 而不是 <code>Int</code>。这意味着您不能只使用等号运算符检查 ID,因为您 <a href="https://github.com/ReactiveX/RxSwift/blob/master/Documentation/GettingStarted.md#life-happens" rel="noreferrer noopener nofollow">need to get out of the Rx monad</a> .</p>

<h2>继续使用 Rx Monad</h2>

<p>对于更优雅的 FRP 解决方案:</p>

<ol>
<li>定义您的可观察设备。</li>
<li>定义可观察的设备 ID。</li>
<li> <a href="http://rxmarbles.com/#zip" rel="noreferrer noopener nofollow">Zip</a>他们在一起。</li>
<li> <a href="http://rxmarbles.com/#filter" rel="noreferrer noopener nofollow">Filter</a>通过 <a href="http://reactivex.io/documentation/operators/filter.html" rel="noreferrer noopener nofollow">checking</a>最后一个设备 ID。</li>
<li>返回你想要的数据类型(<code>DeviceConnectionProtocol</code>)。</li>
<li>使用最后一个设备执行必要的代码。</li>
</ol>

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

<pre><code>// Observable&lt;DeviceConnectionProtocol&gt;
let devices = rx_DeviceList
    .asObservable()
    .flatMap { array in Observable.from(array) }

// Observable&lt;Int&gt;
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)
</code></pre>

<p><em>Monad 只是一种表达范式、处理方式或思维方式的方式。您可以随时退出 RxMonad,这意味着离开数据流并返回到命令式代码。这是程序员更习惯的。</em></p>

<hr/>

<h2>退出 Rx Monad 的简单方法</h2>

<p>这是一个(有些困惑的)解决方案。 TL;DR 转到 <strong>如何同步退出 RxMonad</strong> 部分。</p>

<pre><code>import RxSwift

protocol DeviceConnectionProtocol {
    var id : Observable&lt;String&gt; { get }
}


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

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

    var id: Observable&lt;String&gt; {
      return Observable.create { obx in
            obx.onNext(self.myName)
            return Disposables.create()
      }
    }
}
let rx_DeviceList = Variable(())
let disposeBag = DisposeBag()

let lastID = &#34;Hillary&#34;

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

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

      // How to exit the RxMonad synchronously

      // Have a result variable
      var currentID = &#34;&#34;

      // 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 =
</code></pre>

<p>结果:</p>

<pre><code>Hillary was found!
</code></pre>

<p>请注意,结束的序列(例如 <code></code>)能够使用 <code>takeLast</code> 运算符,但出于某种原因,您的情况是不同的,它不起作用。</p>

<h2>引用和注释</h2>

<ol>
<li><p>这是 <a href="https://gist.github.com/darrensapalo/faf4307c84deaf0c05d02c17de7e118b" rel="noreferrer noopener nofollow">Github Gist</a>如果你想要在 Rx Playground 上运行的整个代码。</p></li>
<li><p><code>zip</code> 运算符在 <a href="http://rxmarbles.com/#zip" rel="noreferrer noopener nofollow">RxMarbles</a> 上可视化.</p></li>
<li><p><code>zip</code> 运算符 <a href="http://reactivex.io/documentation/operators/zip.html" rel="noreferrer noopener nofollow">documentation</a> .</p></li>
<li><p><code>filter</code> 运算符在 <a href="http://rxmarbles.com/#filter" rel="noreferrer noopener nofollow">RxMarbles</a> 上可视化.</p></li>
<li><p><code>过滤器</code>操作符<a href="http://reactivex.io/documentation/operators/filter.html" rel="noreferrer noopener nofollow">documentation</a> .</p></li>
<li><p>这是一个 Swift 3 解决方案。</p></li>
</ol></p>
                                   
                                                <p style="font-size: 20px;">关于ios - 如何在属于 Observable 的属性上过滤 Observable?,我们在Stack Overflow上找到一个类似的问题:
                                                        <a href="https://stackoverflow.com/questions/40405811/" rel="noreferrer noopener nofollow" style="color: red;">
                                                                https://stackoverflow.com/questions/40405811/
                                                        </a>
                                                </p>
                                       
页: [1]
查看完整版本: ios - 如何在属于 Observable 的属性上过滤 Observable?