函数响应式编程 = 函数式编程 + 响应式编程
一、函数式
一种编程范式,如y=f(x)
,y=f(f(x))(高阶函数)
,不同的输入对应不同结果,f(x)
对应具体的数据处理流程,可以是简单的常量值,也可以是复杂的计算或其他函数调用,x
即为因变量,输入不同的x
会输出不同的y
。C
中的函数调用,OC
中的方法调用,这种写法就叫做函数式编程。
特点:代码简洁(复用)、易于理解(接近自然语言)、便于代码管理。如代码:
eat().play().sleep()
sleep().eat().play()
play().eat()
一系列的动作简洁明了,相互不干扰,可以合并使用也可以分开单独使用。
二、响应式
对象对某一数据流变化做出响应的这种编码方式称为响应式。如对象A
和对象B
,A
和B
有一种“说不清”的关系,A
要时刻监控B的行为,对B
的变化也做出相应的变化。那么怎么实现呢?对于B
来说,B
做任何事都需要向A
汇报,这样A
就能实时监控B
的行为,并响应。
在iOS开发中我们经常会响应一些事件button
、tap
、textField
、textView
、notifaction
、KVO
、NSTimer
等等这些,都需要做响应监听,响应后都需要在对应的响应事件中去做处理,而原生开发中,触发对象与响应方法是分离的,如button
的初始化和点击响应方法是分离的。如下:
override func viewDidLoad(){
button = UIButton.init(frame: CGRect(x: 40, y: 100, width: width-80, height: 40))
button.backgroundColor = .gray
button.setTitle("按钮", for: .normal)
self.view.addSubview(button)
button.addTarget(self, action: #selector(clickBtn(button:)), for: .touchUpInside)
}
//button event
@objc func clickBtn(button:UIButton) {
print("点击")
}
在代码量多的情况下,编写处理事件代码就不够直接,代码凌乱,需要联系上下文。如果将对象(button
)和对应的响应方法(event
)绑定在一起呢,如下:
override func viewDidLoad(){
button = UIButton.init(frame: CGRect(x: 40, y: 100, width: width-80, height: 40))
button.backgroundColor = .gray
button.setTitle("按钮", for: .normal)
self.view.addSubview(button)
button.clickEvent = {(val)->Void in
print("我被点击了")
}
}
这样就很清晰了,对button
要做的事一目了然。当然这里我对点击事件做了封装,事件在内部类触发,在内部button
调用闭包,回调到当前button
所实现的闭包中。除此之外,textfield
、scrollview
、tableview
等事件通过闭包传值都可以封装成类似的写法。而这些简洁写法,在OC
的ARC
和Swift
的RxSwift
都做了更好的封装,这种编程思想便称为函数响应式编程思想。
三、RxSwift介绍
全称ReactiveX for Swift
,是一个简化异步编程的框架,实现了函数响应式编程,事件与对象紧密联系,业务流清晰,便于管理。在RxSwift
中,所有异步操作(事件)和数据流均被抽象为可观察序列的概念。流程:
创建序列 -> 订阅序列 -> 发送信号 -> 信号接收
对象的创建到事件监听一气呵成。下面看一段代码感受一下:
override func viewDidLoad() {
super.viewDidLoad()
//button
button = UIButton.init(frame: CGRect(x: 40, y: 100, width: width-80, height: 40))
button.backgroundColor = .gray
button.setTitle("按钮", for: .normal)
self.view.addSubview(button)
//修改事件类型 button.rx.controlEvent(.touchUpOutside)
button.rx.tap.subscribe(onNext: { () in
//此处响应点击事件
print("我被点击了")
}).disposed(by: disposeBag)
//textfield
textfield = UITextField.init(frame: CGRect(x: 40, y: 200, width: width-80, height: 40))
textfield.borderStyle = .roundedRect
textfield.placeholder = "请输入内容"
self.view.addSubview(textfield)
//监听输入变化
textfield.rx.text.orEmpty.changed.subscribe(onNext: { (text) in
print(text)
}).disposed(by: disposeBag)
}
每一个对象将可监听序列绑定到观察者上(对象本身),独立在自己的一块区域。咋一看太爽了,不用写事件方法(或代理方法)了,直接在闭包回调中就可以处理响应事件。
顿时感觉人生观被颠覆了,事件还可以这么写!!!再也不用联系上下文了
四、RxSwift简单使用
Rx
多用于事件响应绑定,绑定到button
上、手势、输入框、KVO、代理等等。在OC
开发中我也经常对这些事件封装,与对象绑定,使之形影不离,代码简洁,结构清晰,代码量少,非常好用,自从看到RAC
、RxSwift
发现自己的那些工作量,哎!,相见恨晚。下面就来体验一下Rx
的使用:
1、button点击事件
//修改事件类型 button.rx.controlEvent(.touchUpOutside)
button.rx.tap.subscribe(onNext: { () in
print("被点击了")
//处理事件 ……
}).disposed(by: disposeBag)
2、手势点击事件
let tap = UITapGestureRecognizer.init()
self.view.addGestureRecognizer(tap)
tap.rx.event.subscribe(onNext: { (tap) in
print(tap.view as Any)
//处理事件 ……
}).disposed(by: disposeBag)
3、输入框监听输入事件
//监听输入变化
textfield.rx.text.orEmpty.changed.subscribe(onNext: { (text) in
print(text)
//处理事件 ……
}).disposed(by: disposeBag)
//绑定,数据传递
textfield.rx.text.bind(to: label.rx.text)
天呐!这个居然还能绑定!!
4、KVO事件监听
self.person.rx.observeWeakly(String.self, "name").subscribe(onNext: { (value) in
print(value as Any)
//处理事件 ……
}).disposed(by: disposeBag)
5、监听滑动事件
scrollview.rx.contentOffset.subscribe(onNext: { [weak self](content) in
let y = content.y
print(content.y)
//处理事件 ……
}).disposed(by: disposeBag)
6、定时器应用 - 定时1秒响应一次
let timer = Observable
.interval(1, scheduler: MainScheduler.instance)
timer.subscribe(onNext: { (time) in
print(time)
//处理事件 ……
}).disposed(by: disposeBag)
这种骚操作吓得我不敢说话了,用就是了~
7、键盘通知
NotificationCenter.default.rx
.notification(UIResponder.keyboardWillShowNotification)
.subscribe(onNext: { (notification) in
//获取值
let during = notification.userInfo?["UIKeyboardAnimationDurationUserInfoKey"] as? Float
print(during!)
//处理事件 ……
}).disposed(by: disposeBag)
8、网络请求
let url = URL.init(string: "https://www.baidu.com")
URLSession.shared.dataTask(with: url!) { (data, response, error) in
print("network")
print(String.init(data: data!, encoding: .utf8))
}.resume()
URLSession.shared.rx.response(request: URLRequest.init(url: url!))
.subscribe(onNext: { (data) in
print(data)
}, onError: { (error) in
print(error)
}, onCompleted: {
print("请求完成")
}).disposed(by: disposeBag)
……
还有很多这种事件绑定就不一一列出了,自己使用自己体会。
五、RxSwift核心
凡事物皆序列,如scrollview
滑动的距离 10、20、30、40 ……就构成了一个序列,设置在100处做出改变。
通过以上的介绍和示例,RxSwift实现逻辑感觉很清晰了,说多了自己都烦,赶紧用起来。直接上一个总结图,偷来的:
有个老铁这块源码分析写的很清楚,我偷懒了:
https://www.jianshu.com/p/c9f854718933
RxSwift核心源码探索
RxSwift中文文档
RxSwift-github
ReactiveX系列