概述
从 C 语言的面向过程开始,到后来的 Objective-C、C++ 面向对象编程,风靡了编程界几十年。后来 Java 的 Spring 框架提出了面向切面
编程的思想,但是并未在 iOS 开发中流行起来。如今,码友们听得最多的应该是函数响应式
编程。本文算是笔者的一个学习记录过程。
RxSwift 简介
RxSwift 是 GitHub 的 ReactiveX 团队出的一套框架,针对 Swift 语言。除此之外,ReactiveX 还推出了 RxJava,RxAndroid,RxPHP 等蕴含类似思想的框架。
RxSwift 安装
如果你还没有掌握 CocoaPods,请先学习,依赖管理是学习每一种语言都需要掌握的技能。建议通过 Pods 来安装 RxSwift,在Podfile
文件中引入 RxSwift 和 RxCocoa。
pod 'RxSwift'
pod 'RxCocoa'
RxSwift 是 Swift 语言的函数响应式编程框架。
RxCocoa 则是对苹果原声面向对象 Api 的封装。
在需要用到 RxSwift 相关内容的类里面,引入模块即可。
import RxSwift
import RxCocoa
RxSwift 简单应用(一)
需求:现在界面上有两个 UIButton,我想监听它们的点击事件。
传统做法
按照以往的做法,我们会首先增加按钮的点击监听,然后自定义一个方法,最后再方法内部去处理点击之后的逻辑。
// 增加点击监听
button1.addTarget(self, action: #selector(clickButton1), for: .touchUpInside)
button1.addTarget(self, action: #selector(clickButton2), for: .touchUpInside)
// 实现点击之后的逻辑
@objc func clickButton1() {
print("按钮1 被点")
}
@objc func clickButton2() {
print("按钮1 被点")
}
这样做可能面临的问题是:代码分离度比较高、后期代码维护费力等等。
RxSwift 做法
下面来看一看用 RxSwift 来实现上述需求。
button1.rx.tap.subscribe { (event: Event<()>) in
print("按钮1 被点")
}
当你写下
button1.rx.tap
后,试图通过“.”语法把后面的语句敲出来时,会发现没有提示。
我的解决方法是重新实例化一个 UIButton,然后就可以看到代码提示,写完代码之后再替换。
不知道哪位码友有更好的解决方案?
subscribe
是订阅的意思,整体可以理解为订阅button1
的点击事件,当按钮被点击是,通过闭包回调。这样就实现了监听按钮点击并处理点击事件的需求。但是当前代码会报一个警告:
解决:
// 类里面懒加载 DisposeBag 对象
fileprivate lazy var bag = DisposeBag()
// 增加点击监听
button1.rx.tap.subscribe { (event: Event<()>) in
print("按钮1 被点")
}.addDisposableTo(bag)
.addDisposableTo(bag) 的作用可以先不用理会,后面会提到,现在就当它是用来消除警告的语句。
RxSwift 简单应用(二)
需求:界面上有2个 UITextField,我想监听它们的输入。
传统做法
成为文本框的代理
textField1.delegate = self
textField2.delegate = self
实现文本框协议
// MARK: - UITextFieldDelegate
extension ViewController: UITextFieldDelegate {
func textField(_ textField: UITextField, shouldChangeCharactersIn range: NSRange, replacementString string: String) -> Bool {
// 判断是哪一个输入框发生改变
if textField == textField1 {
print("输入框1 改变")
} else {
print("输入框2 改变")
}
return true
}
}
这样做可能面临的问题:界面有多个文本框,需要每个都实现代理,并且需要判断是哪一个文本框发生了改变,维护成本比较高,代码可读性差。
RxSwift 做法
先订阅 UITextField,文字输入改变时通过闭包回调。
textField1.rx.text.subscribe { (event: Event<String?>) in
print(event.element)
}.addDisposableTo(bag)
打印出来的结果有点吓唬人,再一看
element
的类型也就不足为奇了。还有另外一种写法:
textField1.rx.text.subscribe(onNext: { (str: String?) in
print(str)
}).addDisposableTo(bag)
这样打印出来的东西友好了许多。
RxSwift 简单应用(三)
需求:现在我们在上面例子的基础上,增加两个 UILabel,实时显示文本框所输入的内容。
RxSwift 做法
textField1.rx.text
.bind(to: label1.rx.text)
.addDisposableTo(bag)
把文本输入框的值,绑定到 UILabel 上面。
RxSwift 简单应用(四)
在平时的开发中,我们经常使用KVO
来监听某个对象的某一属性改变。KVO 使用流程和监听按钮点击差不多,首先需要添加监听,然后覆盖系统方法进行逻辑处理。
传统做法
// 对 frame 属性添加监听
label1.addObserver(self, forKeyPath: "frame", options: .new, context: nil)
// 覆盖父类方法,实现监听回调
override func observeValue(forKeyPath keyPath: String?, of object: Any?, change: [NSKeyValueChangeKey : Any]?, context: UnsafeMutableRawPointer?) {
if label1.isEqual(object) {
if keyPath == "frame" {
print("位置发生改变")
}
}
}
RxSwift 做法
label1.rx.observe(CGRect.self, "frame")
.subscribe(onNext: { (frame: CGRect?) in
print(frame)
})
.addDisposableTo(bag)
observe 方法接收 2 个参数:
- 监听的属性的类型
- 监听的属性的名字
监听完毕之后,对该事件进行订阅,通过闭包形式进行回调。
除此之外,还可以直接监听属性的改变,例如:监听 UIScrollView 的偏移量。
读到这里,算对函数响应式编程
和RxSwift
,RxCocoa
有了初步的了解和认识。
如果对你有所帮助,请点一个👍 ,谢谢!
网友评论
let temp = textField.rx.text
temp.subscribe(...) //使用一个临时变量,然后就能使用点语法了,等写完了再把 temp 干掉即可