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),因此不再重复 getData()。

4

4 回答 4

5

所以说实话,我还在学习,而且我现在没有 RxSwift 摆在我面前(所以如果我在喷 BS,请有人纠正我),但也许我可以引导你走向正确的方向。

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

对于 do things: 现在,您将观察该属性,将其映射以检查它是否正常,然后像您一样订阅它,检查它是否为真,以及它是否是 do things。(并添加一次性)

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


我认为不是超级反应的是您正在同步等待该getData()函数的响应,这会创建一个您现在拥有状态的场景,无论是显示警报还是做额外的工作。它们不是来自其他财产的价值流。显示警报和执行操作仅彼此相关,因为您以命令式方式设置代码。

编辑:而不是用 if 语句检查这是否是真的,也许你可以在订阅之前把它通过一个过滤器。

于 2015-09-02T19:21:58.443 回答
3

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

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

于 2015-09-02T17:27:12.253 回答
3

getData()应该返回一个Observable<Data>并且包含的​​数据应该已经可以了。换句话说,如果getData()正确实现,那么调用data.checkAllIsOk()从 observable 推出的数据应该总是返回 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]
}
于 2015-11-11T13:46:15.547 回答
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)

但我同意 Daniel 的观点,因为这是使用 observable that errors 的绝佳机会。像这样的东西:

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)
于 2017-02-03T20:02:45.873 回答