阅读 334

函数响应式编程思想 & RxSwift 核心逻辑

函数响应式编程 = 函数式编程 + 响应式编程

一、函数式

一种编程范式,如y=f(x)y=f(f(x))(高阶函数),不同的输入对应不同结果,f(x)对应具体的数据处理流程,可以是简单的常量值,也可以是复杂的计算或其他函数调用,x即为因变量,输入不同的x会输出不同的y。C中的函数调用,OC中的方法调用,这种写法就叫做函数式编程。 特点:代码简洁(复用)、易于理解(接近自然语言)、便于代码管理。如代码:

eat().play().sleep()
sleep().eat().play()
play().eat()
复制代码

一系列的动作简洁明了,相互不干扰,可以合并使用也可以分开单独使用。

二、响应式

对象对某一数据流变化做出响应的这种编码方式称为响应式。如对象A和对象BAB有一种“说不清”的关系,A要时刻监控B的行为,对B的变化也做出相应的变化。那么怎么实现呢?对于B来说,B做任何事都需要向A汇报,这样A就能实时监控B的行为,并响应。

在iOS开发中我们经常会响应一些事件buttontaptextFieldtextViewnotifactionKVONSTimer等等这些,都需要做响应监听,响应后都需要在对应的响应事件中去做处理,而原生开发中,触发对象与响应方法是分离的,如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<Int>
    .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处做出改变。

scroll.png

通过以上的介绍和示例,RxSwift实现逻辑感觉很清晰了,说多了自己都烦,赶紧用起来。直接上一个总结图,偷来的🤠:

sequence.png

RxSwift中文文档

RxSwift-github

ReactiveX系列

关注下面的标签,发现更多相似文章
评论