嗨,今天讲讲GitHub - RxSwiftCommunity/RxSwiftExt,再开始IT邦系列之後,才发现了这个library,如同它的名字,就是对RxSwift的Operator进行扩充,多了25种operator、materialize扩充和两个Reactive Extensions,感觉像是个大礼包(?),今天就针对个人觉得有趣或是可能常用到的提出来介绍。
如果是用CocoaPod,加入pod 'RxSwiftExt', '~> 5'
,若是要使用UIViewPropertyAnimator
跟UITableView
的扩充,需要在安装pod 'RxSwiftExt/Core'
unwrap
可以unwrap optional value,并且排除掉nil
Observable.of(1, nil, Int("2"), Int("a"), 3)
.unwrap()
.subscribe(onNext: {
print($0)
})
.disposed(by: disposeBag)
执行结果
1
2
3
原本的话,会是这样写
Observable.of(1, nil, Int("2"), Int("a"), 3)
.filter { $0 != nil }
.map { $0! }
相比之下,unwrap
更简洁也更加的可读了
distinct
可以把重复的元素去除
Observable.of("a", "1", "b", "1", "c")
.distinct()
.debug("Result")
.subscribe()
.disposed(by: disposeBag)
执行结果
a
1
b
c
相似的operator有distinctUntilChanged
,但distinctUntilChanged
是判断是否与上一个元素重复,是的话则过滤掉,distinct
则是看全部曾经发送过的元素是否重复。
pairwise
有点像是滑动视窗,把按照顺序两两合并成tuple
Observable.of(1, 2, 3, 4, 5, 6)
.pairwise()
.subscribe(onNext: {
print($0)
})
.disposed(by: disposeBag)
执行结果
(1, 2)
(2, 3)
(3, 4)
(4, 5)
(5, 6)
如果要用原本写法,大概会像下面这样
Observable.zip(observable, observable.skip(1)) { ($0, $1) }
.subscribe(onNext: {
print($0)
})
.disposed(by: disposeBag)
我们在第 18 天 - Error Handling Operators (下)那篇,介绍retryWhen
时,写了延迟retry范例,在RxSwiftExt中,对此作了封装,让写法更佳的简洁,我们就拿原本retryWhen
的范例做修改
let result = subject
.flatMapLatest { _ in
API().request().asObservable().debug("Call")
.retry(.exponentialDelayed(maxCount: 5, initial: 1.0, multiplier: 1.0))
.materialize()
}
.share()
.exponentialDelayed
是RepeatBehavior
枚举中的一个case,你也可以选择只定义次数、固定时间或是自订时间
public enum RepeatBehavior {
case immediate (maxCount: UInt)
case delayed (maxCount: UInt, time: Double)
case exponentialDelayed (maxCount: UInt, initial: Double, multiplier: Double)
case customTimerDelayed (maxCount: UInt, delayCalculator: (UInt) -> DispatchTimeInterval)
}
.exponentialDelayed
则是提供一个延迟时间增加的公式initial * pow(1 + multiplier, Double(currentAttempt - 1))
,如果multiplier是1
,那延迟时间就是2的0次方、2的1次方、2的2次方,依此类推
repeatWithBehavior
跟retry
极为相似,retry
是侦测到.error
後进行retry,而repeatWithBehavior
是侦测到.completed
後进行repeat
let result = subject
.flatMapLatest { _ in
API().request().asObservable().debug("Call")
.repeatWithBehavior(.exponentialDelayed(maxCount: 5, initial: 1.0, multiplier: 1.0))
.materialize()
}
.share()
我们在第 11 天 - Transforming Observables(下) 所提到的 materialized+elements.swift 也被整合进RxSwiftExt中了。
ofType
可以筛选出元素的type
let result = Observable.of(NSNumber(value: 1),
NSDecimalNumber(string: "2"),
NSNumber(value: 3),
NSNumber(value: 4),
NSDecimalNumber(string: "5"),
NSNumber(value: 6))
result
.ofType(NSDecimalNumber.self)
.subscribe { print($0) }
.disposed(by: disposeBag)
执行结果
next(2)
next(5)
completed
如果要用原本写法,大概会像下面这样
result
.filter { $0 is NSDecimalNumber }
partiion
可以帮你做二分流,也就是符合条件的是一个Observable,不符合条件的是另一条Observable
let (evens, odds) = numbers.partition { $0 % 2 == 0 }
evens.debug("even").subscribe().disposed(by: disposeBag)
odds.debug("odds").subscribe().disposed(by: disposeBag)
执行结果如下
even -> subscribed
even -> Event next(2)
even -> Event next(4)
even -> Event next(6)
even -> Event completed
even -> isDisposed
odds -> subscribed
odds -> Event next(1)
odds -> Event next(3)
odds -> Event next(5)
odds -> Event completed
odds -> isDisposed
这是对RxCocoa进行扩增,所以需要安装pod 'RxSwiftExt/Core'
,animate
提供.subscribe
跟.completed
时触发动画
建立UI
let button = UIButton(frame: .zero)
let myView = UIView(frame: .zero)
建立动画
var animator1: UIViewPropertyAnimator!
var animator2: UIViewPropertyAnimator!
private func makeAnimators() {
// 1
animator1 = UIViewPropertyAnimator(duration: 0.3, curve: .easeInOut) { [unowned self] in
self.myView.transform = self.myView.transform.translatedBy(x: 0, y: 100)
}
// 2
animator2 = UIViewPropertyAnimator(duration: 0.3, curve: .easeInOut) { [unowned self] in
self.myView.transform = self.myView.transform.scaledBy(x: 1.5, y: 1.5)
}
}
myView
下移100距离myView
放大1.5倍绑定事件
button.rx.tap
.flatMap {
self.animator1.rx.animate()
.andThen(self.animator2.rx.animate(afterDelay: 0.15))
}
.subscribe()
.disposed(by: disposeBag)
当按钮点击myView
会先下滑,延迟0.15秒,後放大1.5倍
在第 20 天 - TableView + Rx 与范例(上) 当中,我们实现Infinite scroll,需要侦测UITableView滑至最底,所以我们写了
func bindViewModel() {
tableView.rx.setDelegate(self).disposed(by: disposeBag)
...
}
extension ProductListViewController: UITableViewDelegate {
func tableView(_ tableView: UITableView, willDisplay cell: UITableViewCell, forRowAt indexPath: IndexPath) { ... }
}
RxSwiftExt对这行为作了封装,写法变得更加简洁,於是我们可以改写成,且允许设定offset距离
tableView.rx.reachedBottom(offset: 40)
.bind(to: viewModel.triggerNextPage)
.disposed(by: disposeBag)
在研究RxSwiftExt时,发现有些很实用的作法,对比之前的作法,更加的简洁,更加的可读,也跟各位做个分享,明天就是最後一天了,大家明天见。
<<: Day 28 / DL x RL / RL 不只会打电动?
>>: iOS Developer Learning Flutter. Lesson27 Map + Location
接下来为您介绍 10 款不错的第三方 YouTube 下载软件!让我们来看看哪个软件才是 2022 ...
在经过了多日有一天没一天的研究、写Code与写作,今天假日花了一点时间将原本从Jupyter Not...
好了,最後一天了,也没有太多新花样, 今天就来个组合拳吧! 建立LIFF页面 在LIFF的官方API...
精确率(precision) 召回率(recall) Precision和Recall同时关注的都是...
Git 有四种 type (类型) 的物件:blob、tree、commit 和 tag。 本篇主要...