JHHK

欢迎来到我的个人网站
行者常至 为者常成

21、响应式编程

目录

响应式编程

一、响应式编程

响应式编程(Reactive Programming,简称RP)
也是一种编程范式,于1997年提出,可以简化异步编程,提供更优雅的数据绑定
一般与函数式融合在一起,所以也会叫做:函数响应式编程(Functional Reactive Programming,简称FRP)

比较著名的、成熟的响应式框架

ReactiveCocoa
简称RAC,有Objective-C、Swift版本
官网: http://reactivecocoa.io/
github:https://github.com/ReactiveCocoa

ReactiveX
简称Rx,有众多编程语言的版本,比如RxJava、RxKotlin、RxJS、RxCpp、RxPHP、RxGo、RxSwift等等
官网: http://reactivex.io/
github: https://github.com/ReactiveX

二、RXSwift

RxSwift(ReactiveX for Swift),ReactiveX的Swift版本
源码:https://github.com/ReactiveX/RxSwift
中文文档: https://beeth0ven.github.io/RxSwift-Chinese-Documentation/
RxSwift的github上已经有详细的安装教程,这里只演示CocoaPods方式的安装

① Podfile

    use_frameworks!
    target 'target_name' do
    pod 'RxSwift', '~> 5'
    pod 'RxCocoa', '~> 5'
    end

② 命令行
pod repo update
pod install

③ 导入模块
import RxSwift
import RxCocoa

模块说明
RxSwift:Rx标准API的Swift实现,不包括任何iOS相关的内容
RxCocoa:基于RxSwift,给iOS UI控件扩展了很多Rx特性

三、RxSwift的核心角色

Observable:负责发送事件(Event)
Observer:负责订阅Observable,监听Observable发送的事件(Event)

public enum Event<Element> {
    /// Next element is produced.
    case next(Element)
    /// Sequence terminated with an error.
    case error(Swift.Error)
    /// Sequence completed successfully.
    case completed
} 

Event有3种
next:携带具体数据
error:携带错误信息,表明Observable终止,不会再发出事件
completed:表明Observable终止,不会再发出事件

四、传统的状态监听

在开发中经常要对各种状态进行监听,传统的常见监听方案有
KVO
Target-Action
Notification
Delegate
Block Callback

传统方案经常会出现错综复杂的依赖关系、耦合性较高,还需要编写重复的非业务代码

代码

import UIKit

import RxSwift
import RxCocoa


extension Reactive where Base : UIControl {
    
    var hidden : Binder<Bool>{
        Binder<Bool>.init(base) { (control, value) in
            control.isHidden = value
        }
    }
    
    var enable : Binder<Bool>{
        Binder<Bool>(base) { (control, value) in
            control.isEnabled = value
        }
    }
}

class LCRXSwiftViewController: UIViewController {
    
    enum LCError:Error {
        case Test
    }

    let bag = DisposeBag()
    var label:UILabel!
    var button:UIButton!
    @IBOutlet weak var tableView: UITableView!
    @IBOutlet weak var textField: UITextField!
    @IBOutlet weak var slider: UISlider!
    
    override func viewDidLoad() {
        super.viewDidLoad()
        title = "RXSwiftViewController"
        addLabel()
        addButton()
//        showRXSwiftUse1()
        
//        showRXSwiftUse2()
        
//        showRXSwiftUse3()
        
//        showRXSwiftUse4()
        
//        showRXSwiftUse5()
        
//        showRXSwiftUse6()
        
//        showRXSwiftUse7()
        
//        showRXSwiftUse8()
        
//        showRXSwiftUse9()

        
        showRXSwiftUse10()



    }
    
    
    //创建一个label
    func addLabel() -> Void {
        label = UILabel(frame: CGRect(x: 20, y: 100, width: 100, height: 80))
        label.backgroundColor = UIColor.green
        view.addSubview(label)
    }
    func addButton() -> Void {
        button = UIButton(frame: CGRect(x: 140, y: 100, width: 100, height: 80))
        button.backgroundColor = UIColor.blue
        button.setTitleColor(UIColor.gray, for: UIControl.State.disabled)
        button.setTitleColor(UIColor.blue, for: UIControl.State.normal)
        view.addSubview(button)
    }
    
    
    //MARK: -  一、发送事件、订阅事件1
    func showRXSwiftUse1() -> Void {
                
        //
        let observable = Observable<Int>.create { (observer:AnyObserver<Int>) -> Disposable in
            observer.onNext(11)
            observer.onError(LCError.Test)//会终止不会再发出事件
            observer.onNext(22)
            observer.onCompleted()//会终止不会再发出事件
            observer.onNext(33)
            return Disposables.create()
        }
        
        
        //
        let _ = observable.subscribe { (event:Event<Int>) in
            switch event {
            case .next(let element):
                print("element:",element)
            case .error(let error):
                print("error:",error)
            case .completed:
                print("completed")
            }
        }
        
        
        //可以被多次订阅
        let _ = observable.subscribe { (event:Event<Int>) in
            switch event {
            case .next(let element):
                print("element:",element)
            case .error(let error):
                print("error:",error)
            case .completed:
                print("completed")
            }
        }
        
        
        //另外一种订阅形式
        let _ = observable.subscribe { (element:Int) in
            print("element:",element)
        } onError: { (error:Error) in
            print("error:",error)
        } onCompleted: {
            print("completed")
        } onDisposed: {
            print("onDisposed")
        }
    }
    
    
    //MARK: -  二、发送事件、订阅事件2
    func showRXSwiftUse2() -> Void {
        /**
         相当于:
         Observable<Int>.create { (observer) -> Disposable in
             observer.onNext(1)
             observer.onCompleted()
             return Disposables.create()
         }
         */
        //let observable = Observable.just(1)
        
        
//        let observable = Observable.of(1,2,3)
        
//        let observable = Observable.from([1,2,3])
        
        let observable = Observable<Int>.timer(.seconds(2),         //2秒后
                                               period: .seconds(1), //每隔1秒
                                               scheduler: MainScheduler.instance)//主线程
        
        
        //返回一个Disposable
        let _ = observable.subscribe { (element) in
            print("element:",element)
        } onError: { (error) in
            print("error:",error)
        } onCompleted: {
            print("completed")
        } onDisposed: {
            print("onDisposed")
        }
            
        
        
        //绑定到一个label上,也是订阅
        let _ = observable.map{"数值是:\($0)"}.bind(to: label.rx.text)
    }
    
    
    //MARK: -  三、取消订阅的方式
    func showRXSwiftUse3() -> Void {
        
        /**
         每当Observable被订阅时,都会返回一个Disposable实例,当调用Disposable的dispose,就相当于取消订阅
         在不需要再接收事件时,建议取消订阅,释放资源。有3种常见方式取消订阅
         
         // 立即取消订阅(一次性订阅)
         observable.subscribe { event in
            print(event)
         }.dispose()
         
         // 当bag销毁(deinit)时,会自动调用Disposable实例的dispose
         observable.subscribe { event in
            print(event)
         }.disposed(by: bag)
         
         
         // self销毁时(deinit)时,会自动调用Disposable实例的dispose
         let _ = observable.takeUntil(self.rx.deallocated).subscribe { event in
            print(event)
         }
         */
        
        let observable = Observable<Int>.timer(.seconds(3),
                                               period: .seconds(1),
                                               scheduler: MainScheduler.instance)
        
        
        
        let disposable:Disposable = observable.subscribe { (element) in
            print("element:",element)
        } onError: { (error) in
            print("error:",error)
        } onCompleted: {
            print("completed")
        } onDisposed: {
            print("onDisposed")
        }
        print(disposable)
        //在某个特定的时刻取消订阅
        //disposable.dispose()
        
        
        
        //只订阅一次
        observable.subscribe { (element) in
            print("element:",element)
        } onError: { (error) in
            print("error:",error)
        } onCompleted: {
            print("completed")
        } onDisposed: {
            print("onDisposed")
        }.dispose()

        
        //bag销毁时调用dispose
        observable.subscribe { (element) in
            print("element:",element)
        } onError: { (error) in
            print("error:",error)
        } onCompleted: {
            print("completed")
        } onDisposed: {
            print("onDisposed")
        }.disposed(by: bag)
        
        
        //直到self销毁时取消订阅
        let _ = observable
            .take(until:self.rx.deallocated)
            .map { "数值是:\($0)"}
            .bind(to: label.rx.text)
    }
    
    
    //MARK: -  四、创建Observer
    func showRXSwiftUse4() -> Void {
        
        let observer = AnyObserver<Int>.init { (event) in
            switch event {
            case .next(let data):
                print(data)
            case .completed:
                print("completed")
            case .error(let error):
                print(error)
            }
        }
        Observable.just(1).subscribe(observer).dispose()
    }
    
    
    //MARK: -  五、Binder label
    func  showRXSwiftUse5() -> Void {
        
        let binder = Binder<String>(label) { (label, value) in
            print("value:",value)
            label.text = value
        }
        
        //以下写法等价
        Observable.of(1,2).map{"数值是:\($0)"}.subscribe(binder).dispose()
        Observable.just(3).map {"数值是:\($0)"}.bind(to: binder).dispose()
        Observable.just(4).map {"数值是:\($0)"}.bind(to: label.rx.text).dispose()
    }

    
    //MARK: -  六、Binder2 button
    func showRXSwiftUse6() -> Void {
        let observable = Observable<Int>.timer(.seconds(2), period: .seconds(1), scheduler: MainScheduler.init())
        
        /**
         let binder = Binder<Bool>(label) { (label, value) in
             label.isHidden = value
         }
         observable.map { $0 % 2 == 0}.bind(to: binder).disposed(by: bag)
         */
        //通过扩展Reactive 可以简化成下面这样
        //observable.map{ $0%2 == 0 }.bind(to: button.rx.hidden).disposed(by: bag)
        
        //绑定enable属性
        //observable.map{$0%2 == 0}.bind(to: button.rx.enable).disposed(by: bag)
        
        //其实系统已经帮我们实现好了
        observable.map{$0%2 == 0}.bind(to: button.rx.isHidden).disposed(by: bag)
    }
    
    
    //MARK: -  七、Binder3 button点击事件
    func showRXSwiftUse7() -> Void {
        
        //observable
        let observable =  button.rx.tap.map { "按钮事件:\($0)"}
        
        
        //observer
        let _ = observable.subscribe { (event) in
            print(event)
        } onError: { (error) in
            print(error)
        } onCompleted: {
            print("onCompleted")
        } onDisposed: {
            print("onDisposed")
        }
    }
    
    
    //MARK: -  八、binder4 tableview
    func showRXSwiftUse8() -> Void {
        
        //Observable
        let data = Observable.just([
            LCPerson(name: "Jack", age: 10),
            LCPerson(name: "Rose", age: 20)
        ])
        
        
        //Observer
        data.bind(to: tableView.rx.items(cellIdentifier: "rxcellid")){
            row,person,cell in
            cell.textLabel?.text = "\(row) " + person.name
            cell.detailTextLabel?.text = "\(person.age)"
        }.disposed(by: bag)
        
        
        let _ = tableView.rx.modelSelected(LCPerson.self)
            .subscribe { (person) in
                print("点击了",person.name)
            } onError: { (error) in
                print("error",error)
            } onCompleted: {
                print("onCompleted")
            } onDisposed: {
                print("onCompleted")
            }
    }
    
    
    //MARK: -  九、binder5
    func showRXSwiftUse9() -> Void {
        
        //kvo
        let _ = label.rx.observe(String.self,"text")
            .subscribe { (text) in
                print("text:",text as Any)
            } onError: { (error) in
                print("error:",error)
            } onCompleted: {
                print("onCompleted")
            } onDisposed: {
                print("onDisposed")
            }
        label.text = "哈哈"
        
        
        //notification
        NotificationCenter.default.rx.notification(UIApplication.didEnterBackgroundNotification)
            .subscribe { (notification) in
                print("App进入后台",notification)
            } onError: { (error) in
                print("error:",error)
            } onCompleted: {
                print("onCompleted")
            } onDisposed: {
                print("onDisposed")
            }.disposed(by: bag)

    }
    
    
    //MARK: -  十、binder6
    func showRXSwiftUse10() -> Void {
        //既是Observable 又是 observer
        
        //slider.rx.value 作为observer
        Observable.just(0.8).bind(to: slider.rx.value).dispose()
        
        
        //slider.rx.value 作为 observable
        //textField.rx.text 作为observer
        slider.rx.value.map{"当前数值是:\($0)"}
            .bind(to: textField.rx.text).disposed(by: bag)
        
        
        //textField.rx.text 作为observable
        textField.rx.text.subscribe { (text) in
            print("text:",text as Any)
        } onError: { (error) in
            print("error:",error)
        } onCompleted: {
            print("onCompleted")
        } onDisposed: {
            print("onDisposed")
        }

        /**
         诸如UISlider.rx.value、UTextField.rx.text这类属性值,既是Observable,又是Observer
         它们是RxCocoa.ControlProperty类型
         */
    }
    
}

行者常至,为者常成!





R
Valine - A simple comment system based on Leancloud.