如何在 RxSwift 中翻译 if-else?

how to translate an if-else in RxSwift?

我正在努力学习图书馆RxSwift

我有一些这样的代码:

if data.checkAllIsOk()
{ 
    [do things]
}
else
{ 
    [show alert]
}

现在我需要在检查之前从服务器更新数据,所以我建模了一个 getData(),return 一个 Observable。

我目前的做法是这样的:

getData()  
    >- flatMap{ (data:Data) -> Observable<Bool> in
        _=0 // workaround for type inference bugs
        return just(data.checkAllIsOk())
    }
    >- subscribeNext{ (ok) -> Void in
        if ok
        {
            [do the things]
        }
        else
        {
            [show the alert]
        }
    } 
    >- disposeBag.addDisposable()

它有效(或者它应该有效,我还在写它),但感觉不对..有没有更“反应性”的方法来做到这一点? 最适合使用的运算符是什么?

也许 return 为“false”报错并使用 catch 块?

更新

按照 ssrobbi 建议的方法,我将 2 个分支拆分为 2 个不同的 subscribeNext,并对 select 正分支或负分支使用过滤器。这是生成的代码:

let checkData=getData()  
        >- flatMap{ (data:Data) -> Observable<Bool> in
            _=0 
            return just(data.checkAllIsOk())
        }
        >- shareReplay(1)
}
[...]
checkData
    >- filter{ (ok) -> Bool in
        ok == true
    }
    >- subscribeNext{ (_) -> Void in
        [do the things]
    }
    >- disposeBag.addDisposable()

checkData
    >- filter{ (ok) -> Bool in
        ok == false
    }
    >- subscribeNext{ (_) -> Void in
        [show the alert]
    } 
    >- disposeBag.addDisposable()

这种方法的优点是我可以在代码的其他部分只重用两个分支中的一个,而无需重写订阅主体(重复越少越好!)

更新

在 RxSwift slack 中进行了一些讨论后,我添加了 shareReplay(1),因此不会重复 getData()。

我不知道 RXSwift,但我知道函数式编程(RXSwift 也是函数式的)。 if else 语句已经处于最低形式,您不需要进行功能分支,这会起作用,但会降低可读性。

如果您想要更实用,您可以将 if else 更改为 condition ? a : b(Haskell 的 if else 正是这样)。但这也降低了它的可读性,我会坚持你得到的 ;)

所以老实说我还在学习,我现在没有 RxSwift 在我面前(所以如果我在胡说八道,请有人纠正我),但也许我可以引导你朝着正确的方向前进。

您的解决方案确实有效,但正如您所说,它不是很好 "reactive"。我认为问题在于您的数据流设置方式必须就是否显示警报或执行某些操作做出必要的决定。应该发生的是,getData 不返回一个可观察对象,getData 应该获取它需要的任何数据(无论是来自网络、核心数据等),然后它应该更新一个可观察对象 属性.

为做事: 现在,您会观察到 属性,将其映射以检查它是否正常,然后像您一样订阅它,检查它是否为真,以及它是否正在执行操作。 (并添加一次性)

警报: 你会做完全相同的事情,再次观察相同的 属性,但检查相反的情况并做一些事情。


我认为它不是超级反应的是你正在同步等待来自那个 getData() 函数的响应,它创建了一个你现在有状态的场景,无论是显示警报,还是额外的工作。它们并非源自其他 属性 的价值流。显示警报和执行操作仅相互关联,因为您命令式地设置了代码。

编辑: 与其使用 if 语句检查是否为真,也许您可​​以在订阅之前将其通过过滤器。

getData() 应该 return 一个 Observable<Data> 并且包含的​​数据应该 已经 没问题。换句话说,如果 getData() 被正确实现,那么对从 observable 推出的数据调用 data.checkAllIsOk() 应该总是 return true。

所以你在 getData() 之外应该有的东西是这样的(在 Rx v2 和 Swift v2 中):

getData().subscribe { event in 
switch event {
case .Next(let data):
    [do things with data]
case .Error(let error):
    [show the alert]
}

您的更新方法的问题在于 checkData 是一个 Observable<Bool>,因此您不能真正 "do stuff" 使用它。

我想你想要的是这个(为清楚起见分解):

func isDataOk(_ data: Data) -> Bool { /* ... */ }

let data = getData().shareReplay(1)

let goodData = data.filter(isDataOk)
let badData = data.filter{ isDataOk([=10=]) == false }

goodData
  .subscribe( /* do stuff */ )
  .addDisposableTo(disposeBag)

badData
  .subscribe( /* show alert */ )
  .addDisposableTo(disposeBag)

但我同意 Daniel 的观点,这是一个很好的机会来使用可观察到的错误。像这样:

func passOrThrow(_ data: Data) throws -> Data { /* throw an error here if data is bad */ }

getData()
  .map(passOrThrow)
  .subscribe(onNext: { data in
    // do the things
  }, onError: { error in
    // show the alert
  }).addDisposableTo(disposeBag)