一、RxSwift
Microsoft 的一个团队接受了解决我们在本章中讨论过的异步、可扩展、实时应用程序开发问题的挑战。大约在 2009 年的某个时候,他们提供了一个名为 Reactive Extensions for .NET (Rx) 的新客户端和服务器端框架。Rx for .NET 自 2012 年以来一直是开源的,允许其他语言和平台重新实现相同的功能,这将 Rx 变成了跨平台标准。今天,您拥有 RxJS、RxKotlin、Rx.NET、RxScala、RxSwift 等等。基于响应式扩展规范,所有人都努力实现相同的行为和相同的表达 API。最终,使用 RxSwift 创建 iOS 应用程序的开发人员可以在网络上与其他使用 RxJS 的程序员自由讨论应用程序逻辑。
什么是RxSwift?学习RxSwift有哪些优势呢?
复合- Rx就是复合的代名词复用- 复用性比较强 - 代码量降低清晰- 因为声明都是不可变更的,代码函数式编程可读性强易用- 理解容易,还抽象了异步编程,统一代码风格稳定- 因为Rx是完全通过单元测试的
1、函数式编程
响应式编程(reactive programming)是一种基于数据流(data stream)和变化传递(propagation of change)的声明式(declarative)的编程范式。
我有一个栗子:
let array = [1, 2, 3, 4, 5, 6, 7]
// 首先获取 > 3的数字
// 获取的数字之后 + 1
// 所有数字中的偶数
那我们能想到的做法是一个for循环先判断>3,后+1在取偶数。
for num in array {
if num > 3 {
let number = num + 1
if (number % 2 == 0) {
print(number)
}
}
}
可是这个代码的可读性,清晰度,可维护性较差。有没有更少的代码,可清晰的方式来完成呢?
array.filter { $0 > 3 }
.filter { ($0+1) % 2 == 0 }
.forEach { print($0+1) }
函数响应式编程
函数式负责序列操作,响应式负责监听变化,响应这个序列。当然这个序列是具备着特别的封装(异步等)
我们通过不同的构建函数,来创建所需要的数据序列。最后通过适当的方式来响应这个序列。这就是函数响应式编程。
extension Binder {
func bindingValueRx( first : inout Int, second : inout Int) -> (String) -> Binder {
return { output in
// binding a and b to result
print(output)
return self
}
}
func unbindingValueRx( first : inout Int, second : inout Int) -> () -> Binder {
return {
//unbindg a and b to result
return self
}
}
}
//可以通过 .函数.函数 表达出来
binder.bindingValueRx(first: &a, second: &b)("finished").unbindingValueRx(first: &a, second: &b)()
2、基础用法
搭建一个工程配置Podfile:
target '002-RxSwift初探' do
# Comment the next line if you're not using Swift and don't want to use dynamic frameworks
use_frameworks!
pod 'RxSwift'
pod 'RxCocoa'
# Pods for 002-RxSwift初探
end
然后熟练的开始在Main.storyboard 上布局如下:
先来了解一下在swift中KVO的使用
//记住需要标识 Objc dynamic
@objc dynamic var name: String = "我真6"
func setupKVO() {
//三部曲
self.person.addObserver(self, forKeyPath: "name", options: .new, context: nil)
//1.注册观察者
}
//修改 name
override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) {
textFiled.resignFirstResponder()
print("来了")
person.name = "\(person.name) 6"
// print(person.name)
}
//2.响应
override func observeValue(forKeyPath keyPath: String?, of object: Any?, change: [NSKeyValueChangeKey : Any]?, context: UnsafeMutableRawPointer?) {
print("响应")
print(change as Any)
}
//3.释放kvo
deinit {
self.removeObserver(self.person, forKeyPath: "name", context: nil)
}
打印结果:
**2022-08-25 22:18:30.317247+0800 002-RxSwift初探[3311:40668] Writing analzed variants.**
**来了**
**响应**
**NSKeyValueChangeKey(_rawValue: new): 我真6 6])**
如果我们使用RXSwift响应序列就变的很简单了:
func setupKVO() {
//响应序列
self.person.rx.observeWeakly(String.self, "name")
.subscribe { value in
print(value as Any)
}
.disposed(by: disposeBag)
}
你看只需要几行代码就能完成,不需要原本的三部曲了。
核心问题:
为什么所有对象都能.rx呢?
rx是如何让对象可使用相应序列的呢?
我们看到NSObject进行了扩展继承了ReactiveCompatible协议并扩展实现了rx的get,set方法。
observable的流程图:
通过几个例子
继续探索:
//**MARK: - RxSwift应用-timer定时器**
func setupTimer() {
timer = Observable<Int>.interval(.seconds(1), scheduler: MainScheduler.instance)
timer.subscribe { num in
print(num)
}
.disposed(by: disposeBag)
}
//**MARK: - RxSwift应用-scrollView**
func setupScrollerView() {
scrollView.rx.contentOffset
.subscribe { [weak self]content in
self?.view.backgroundColor = UIColor.init(red: content.y/255*0.8, green: content.y/255*0.6, blue: content.y/255*0.3, alpha: 1) }
.disposed(by: disposeBag)
}
//**MARK: - RxSwift应用-textfiled**
func setupTextFiled() {
self.textFiled.rx.text.orEmpty.changed
.subscribe { text in
print(text)
}
.disposed(by: disposeBag)
//RxSwift更加面向开发者
self.textFiled.rx.text
.bind(to: self.button.rx.title())
.disposed(by: disposeBag)
}
//**MARK: - RxSwift应用-button响应**
func setupButton() {
//功能逻辑/业务逻辑分开了
// self.button.addTarget(self, action: #selector(<#T##@objc method#>), for: .touchUpInside)
self.button.rx.controlEvent(.touchUpInside)
.subscribe { _ in
print("点击事件")
}
.disposed(by: disposeBag)
}
总结
- RxSwift就是
函数响应式编程的框架,减少了大量胶水代码,使代码清晰,复用,可读性提升。 - RxSwift的核心是使用了
Observable 的函数闭包->订阅保存->然后通知响应到对应 AnonymousObservableSink-run(Ob)执行。 - RxSwift的主要流程: 创建序列 --> 订阅序列 --> 发送信号 --> 信号接收。
DisposeBag就像个垃圾袋一样,我们把创建的序列放在DisposeBag这个垃圾袋中,他会在合适的时候帮我们释放资源。