RxFlow 3: 提示和技巧

文章目录
  1. 1. UIViewController 支持 Reactive
  2. 2. 暂停

-

这篇是 RxFlow 系列文章的最后一章。在前两篇文章中,我已经介绍了所有关键功能/原理

让我们深入探讨我在响应式编程中发现的技巧和窍门。

UIViewController 支持 Reactive

正如我们在第2篇中所看到的,我们有时需要以响应方式知道何时显示一个Presentable。一个 Presentable 暴露三个 Observables:

code
1
2
3
4
5
6
7
8
9
10
/// Observable that triggers a bool indicating if
/// the current Presentable is being displayed
var rxVisible: Observable<Bool> { get }

/// Single triggered when this presentable is displayed
/// for the first time
var rxFirstTimeVisible: Single<Void> { get }

/// Single triggered when this presentable is dismissed
var rxDismissed: Single<Void> { get }

RxFlow 中,UIViewController 遵从 Presentable 协议,因此我们必须找到方法让他们支持 Reactive。

幸运的是在此过程中发现的一个项目在此方面起到了很大作用:RxViewController.

通过应用我在这篇文章中(Swift中的静态名称空间)描述的模式,它为UIViewControllers提供了Reactive扩展。它使用RxCocoa内置函数允许观察选择器调用。一旦理解了这一概念,便对UIViewController进行了自己的扩展。

code
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
extension Reactive where Base: UIViewController {
/// Observable, triggered when the view has appeared for the first time
public var firstTimeViewDidAppear: Single<Void> {
return sentMessage(#selector(Base.viewDidAppear)).map { _ in
return Void()
}.take(1).asSingle()
}

/// Observable, triggered when the view is being dismissed
public var dismissed: ControlEvent<Bool> {
let source = sentMessage(#selector(Base.dismiss))
.map { $0.first as? Bool ?? false }
return ControlEvent(events: source)
}

/// Observable, triggered when the view appearance state changes
public var displayed: Observable<Bool> {
let viewDidAppearObs = sentMessage(#selector(Base.viewDidAppear))
.map { _ in true }
let viewWillDisappearObs = sentMessage(#selector(Base.viewWillDisappear))
.map { _ in false }
return Observable<Bool>.merge(viewDidAppearObs, viewWillDisappearObs)
}
}

作为记录,这就是 Coordinator 的用法,其中 “nextPresentable” 是由 Flow 上的 “navigate(to : )” 函数生成的 Presentable 。在已经关联的Presentable首次显示之后,我们仅监听下一个Stepper。

code
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
nextPresentable.rxFirstTimeVisible.subscribe(onSuccess: { [unowned self,
unowned nextPresentable,
unowned nextStepper] (_) in
// we listen to the presentable's Stepper.
// For each new Step value, we trigger a new navigation process
// this is the core principle of the whole RxFlow mechanism
// The process is paused each time the presentable is not currently displayed
// for instance when another presentable is above it in the VCs hierarchy.
nextStepper.steps
.pausable(nextPresentable.rxVisible.startWith(true))
.asDriver(onErrorJustReturn: NoStep())
.drive(onNext: { [unowned self] (step) in
// the nextPresentable's Stepper fires a new Step
self.steps.onNext(step)
}).disposed(by: nextPresentable.disposeBag)

}).disposed(by: self.disposeBag)

暂停

在 RxFlow 中另一个关键原则:Flow 中发生什么就要停留在 Flow 中。因此我必须找到一个方式