如何在RxSwift中翻译if-else语句?

7

我正在尝试学习库RxSwift

我有一些代码像这样:

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

现在,在进行检查之前,我需要从服务器更新数据,因此我建立了一个返回Observable的getData()。

我的当前方法是这样的:

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()

它可以正常工作(或者应该可以,因为我还在写它),但感觉不太对劲。。。有没有更“反应性”的方法来实现它?使用哪个操作符最合适?

也许对“false”返回错误并使用catch块会更合适吗?

更新

按照ssrobbi建议的方法,我将2个分支分成了2个不同的subscribeNext,并使用过滤器选择正面或负面分支。以下是生成的代码:

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),因此不会重复获取数据。
4个回答

5
坦白地说,我也还在学习中,并且现在没有RxSwift(如果我在胡说八道,请有经验的人纠正我),但也许我可以给你指明方向。
你的解决方案确实可行,但正如你所说,它并不是很“响应式”。我认为问题在于,你的数据流程设置方式导致必须根据情况做出这样那样的决定。getData函数应该获取它需要的任何数据(无论是来自网络、核心数据等),然后更新一个可观察属性,而不是返回一个可观察对象。
对于执行操作: 现在,你将观察该属性,将其映射以检查是否可以,像你之前一样进行订阅,检查它是否为真,如果是,则执行操作。(并添加disposable)
对于警报: 你将做完全相同的事情,再次观察同一属性,但检查相反的情况并执行相应操作。
我认为它不太具有“响应性”的原因在于,你正在同步等待getData()函数的响应,这样会创建一种情况:你现在有了状态,即显示警报或执行其他工作。它们不是从某个其他属性的值流派生出来的。显示警报和执行操作仅因为你以命令式的方式设置了代码而彼此相关。
编辑:在订阅之前,你可以通过筛选器对其进行过滤,而不是使用if语句来检查它是否为真。

3

getData() 应该返回一个 Observable<Data>,其中包含的数据应该已经是正确的。换句话说,如果 getData() 被正确实现,那么在从可观察对象中推出的数据上调用 data.checkAllIsOk() 应该总是返回 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]
}

3

我不懂 RXSwift,但我了解函数式编程(RXSwift 也是函数式的)。if else 语句已经处于其最低形式,您不需要进行函数分支,虽然这样做可以实现功能,但会使代码难以阅读。

如果您想更加符合函数式编程,可以将 if else 改为 condition ? a : b(Haskell 的 if else 正是如此)。但这也会使代码难以阅读,所以我建议您还是使用原来的写法 ;)


我想很多都是个人口味问题,所以我投了两个答案 :) - hariseldon78

1
你更新的方法存在问题,因为checkData是一个Observable<Bool>,所以你不能真正地对其进行“操作”。

我认为你想要的是这样的(为了更清晰,进行了分解):

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

let data = getData().shareReplay(1)

let goodData = data.filter(isDataOk)
let badData = data.filter{ isDataOk($0) == false }

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

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

但我同意丹尼尔的观点,这是使用可观察对象产生错误的绝佳机会。就像这样:

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)

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接