美文网首页Swift函数式编程iOS-项目实战
RXSwift基础用法及响应核心底层逻辑原理(超详细吐血篇)

RXSwift基础用法及响应核心底层逻辑原理(超详细吐血篇)

作者: lb_ | 来源:发表于2019-07-23 22:47 被阅读0次

    RXSwift GitHub地址
    RXSwift中文文档
    RX家族

    絮叨:
    这篇之所以讲核心逻辑时很仔细(啰嗦),是因为其重要性,必须要给弄懂了!。

    简介

    全称ReactiveX for Swift,是一个简化异步编程的框架,实现了函数响应式编程,事件与对象紧密联系,业务流清晰,便于管理。在RxSwift中,所有异步操作(事件)和数据流均被抽象为可观察序列的概念。
    流程为:
    创建序列 -> 订阅序列 -> 发送信号 -> 信号接收

    简单使用:

    • 框架导入: CocoaPods
    pod 'RxSwift'
    pod 'RxCocoa'
    //友情提示 当使用  Moya-ObjectMapper 时,由于此库引用了RxSwift,所以如果有pod 'Moya-ObjectMapper/RxSwift'时,无需再pod 'RxSwift'
    写为:
    #pod 'RxSwift'
    pod 'RxCocoa'
    pod 'Moya-ObjectMapper/RxSwift'
    

    在需要使用的类中添加依赖:

    import RxCocoa
    import RxSwift
    
    • 简单用法:
      1 : KVO
    class LBPerson:NSObject{
        @objc dynamic var name : String = "default"
    }
    
    extension LBRegisterViewController{
        fileprivate func kvoTest(){
            let person = LBPerson.init()
            person.rx.observeWeakly(String.self, "name")
                .subscribe(onNext: { (value) in
                print(value as Any)
            })
            .disposed(by: disposeBag)
            
            person.name = "lb"
        }
    }
    

    输出结果:

    Optional("lb")
    

    2 : UIButton 事件响应

    fileprivate func btnTest(){
        let btn = UIButton()
        btn.rx.tap.subscribe(onNext: { (_) in
            print("事件")
        })
    }
    
    /*注:tap默认为TouchUpInside. 点进去看源码*/
    extension Reactive where Base : UIButton {
    
        /// Reactive wrapper for `TouchUpInside` control event.
        public var tap: RxCocoa.ControlEvent<Void> { get }
    }
    
    //那么其他类型Event呢: 你看-->
    btn.rx.controlEvent(.touchUpOutside).subscribe(onNext: { (_) in
        print("事件")
    })
    

    输出:

    "事件"
    

    3: UITextFiled 键盘内容监听

    fileprivate func TFTest(){
        let tf = UITextFiled()
        let textFieldInputSequence = tf.rx.text.orEmpty.asDriver().throttle(0.4)
    
        textFieldInputSequence.drive(onNext: { (str) in
                print("tf值改变-->\(str)")
        }).disposed(by: disposeBag)
    }
    
    // orEmpty,防空处理.
    // throttle节气阀,防暴力触发,参数为时间间隔.
    

    4: UIScrollView ContentOffser监听

    let scrollView = UIScrollView()
    scrollView.rx.contentOffset
       .subscribe(onNext: { [weak self](content) in
           print(scrollView.contentOffset.y)
       })
    .disposed(by: disposeBag)
    

    5: 手势监听

    let tap = UITapGestureRecognizer()
    let label = UILabel()
    label.addGestureRecognizer(tap)
    label.isUserInteractionEnabled = true
    tap.rx.event.subscribe(onNext: { (tap) in
        print(tap.view)
    })
    .disposed(by: disposeBag)
    

    6: 通知

    NotificationCenter.default.rx.notification(UIResponder.keyboardWillShowNotification)
        .subscribe(onNext: { (noti) in
            print(noti)
        })
    .disposed(by: disposeBag)
    

    7: 定时器

    let timer = Timer.init()
    timer = Observable<Int>.interval(1, scheduler: MainScheduler.instance)
    timer.subscribe(onNext: { (num) in
        print(num)
    }).disposed(by: disposeBag)
    

    8: 网络(URLSession)

    let url = URL(string: "https://www.baidu.com")
    //        原本写法
    //        URLSession.shared.dataTask(with: url!) { (data, response, error) in
    //            print(String.init(data:data!,encoding: .utf8))
    //        }.resume()
            
    URLSession.shared.rx.response(request: URLRequest(url: url!))
       .subscribe(onNext: { (response,data) in
           print(response)
       }).disposed(by: disposeBag)
    

    这个看起来有点鸡肋,后续文章中会给大家介绍RXSwift结合MOYA使用,从而更优雅的调用网络。先看个效果:

    let provider = MoyaProvider<ApiManager>();
    
    provider.request(.login(username: "haha", password: "123456", token: "***")) { (result) in
         if result.error == nil{
              LBLog(result.value);
         }
    }
    

    核心逻辑:

    重点:重头戏它又来了.

    先来个最简单的响应流程:

    fileprivate func exploringTest(){
       let ob = Observable<Any>.create { (observer) -> Disposable in
           observer.onNext("测试")
           observer.onCompleted()
           return Disposables.create()
       }
            
       _ = ob.subscribe(onNext: { (text) in
           print("订阅到:\(text)")
       }, onError: { (error) in
           print("error:\(error)")
       }, onCompleted: {
           print("完成")
       }, onDisposed: {
           print("销毁")
       })
    }
    

    打印结果:

    订阅到:测试
    完成
    销毁
    

    以上便是一个序列,从创建,到订阅,发送,接收,销毁的全过程。
    那么接下来我们来撩开它滴裙子👗

    一步一步来,

    • 先来看Observable<Any>.create
      首先Cmd+点击Observable,进来了,找了一堆没找着.create,不急,看图
      Observable.create
      选择Create.Swift, 看到了啥,第一个就是ObservableType的create方法
    Observable.create方法实现

    小注: 有滴同学说我找的是Observablecreate方法,你找的这个不是ObservableType吗。
    答: 方法查找流程。那么Observable点进去你看

    ObservableType与Observable关系

    好滴,找到了create实现。

    总结:我们看到我们所写的Observable<Any>.create其实就是return了一个AnonymousObservable对象的构造方法,也就是返回了一个AnonymousObservable对象。这个对象中储存了我们发送的事件,需要回调的处理。

    继续,本文件搜索AnonymousObservable,找到这个类

    找到AnonymousObservable
    找到构造方法具体实现了
    我们看到它啥也没干,只是把传给自己的匿名函数用成员变量保存了下来。OK,Observable<Any>.create干了啥我们知道了。继续-->
    • ob.subscribe
      第二句代码ob.subscribe
      老规矩 先点进去再说,CMD+点subscribe
      ObservableType.subscribe
      我再点:额。方法实现不给看了。 无妨,既然你都告诉我了是ObservableTypesubscribe(onNext:balabala方法,那我自己找。还是看图:
      图666: ObservableType的subscribe(onNext:...方法实现

    好我们来到了重点了:
    首先Disposable放过不管
    图中第一个绿框,创建了一个AnonymousObserver订阅者对象。又是构造方法,又不给点进去?,没关系,我们自己查:

    AnonymousObserver构造方法

    绿框框里看到啥,AnonymousObserver 的初始化构造方法时init(_ eventHandler: @escaping EventHandler),利用逃逸闭包写法,当逃逸闭包被当作函数参数初始化时,可以把闭包写开,这个gay位同学应该问题不大。

    总结:
    第一个绿框中干了啥?
    一句话:创建了一个AnonymousObserver对象,并且在创建时就保存了传进来的eventHandler的Block到自己的成员变量中。

    ok,继续看图666中,AnonymousObserver创建后,第二个绿框,return的时候调用了self.asObservable().subscribe(observer)方法 (Disposables不用管,后续我会专门写一篇文章来介绍垃圾袋机制).

    注意:注意:坑来了啊,self.asObservable().subscribe(observer),提问:想看subscribe的实现,那我们改找哪个类。
    Observable? 错啦。仔细回忆下第一句代码,Observable<Any>.create时做了什么,上面第一句代码总价加粗的字体:

    因为第一句代码返回了一个AnonymousObservable对象。所以此时self指的是AnonymousObservable对象,而asObservable()则是return了一个self,啥也没干,因此我们需要去找AnonymousObservable的subscribe()方法

    不信?看图,


    self.asObservable().subscribe(observer)中,self指的是谁

    走到这 ,恭喜,裙底的风光快显露了。
    继续,找AnonymousObservable的subscribe()方法,同样在Create.swift文件中.

    AnonymousObservable对象

    what the hell?为什么对象里没得subscribe()方法。 别急,子类找不着找谁?找爸爸。CMD+点Producer

    Producer调用subscribe()方法
    图上看到,不管 if / else 都会创建SinkDisposer类,然后调用self.run方法.
    注意: 别忘了,儿子AnonymousObservable重写了run方法,儿子没得方法才找到的爸爸Producer
    因此回到AnonymousObservable中,

    终于被我看见裙底了。


    AnonymousObservable对象,run方法

    创建了AnonymousObservableSink对象,调用其run方法,

    run

    run干了啥?调用传参中parent的Block,传进来的parent是谁?

    执行谁的_subscribeHandler
    传进来是self,那self的_subscribeHandler是谁?
    ok 第一句代码create时我们保存的,也就是说,

    总结:图666中第二个绿框(也就是self.asObservable().subscribe(observer))干了啥.
    一: 保存了接收到事件时的回调.
    二: 执行我们创建序列时的回调.

    换句话说,此时接下来就走到了序列创建回调中。


    序列创建回调

    那么接下来我们查找 AnonymousObserveron() 方法

    AnonymousObserver类
    没找着on(Next)方法?找父类 ObserverBase
    ObserverBase类以及on(_ event: Event<E>)方法
    方法里使用了个 switch,最后都调用了self.onCore(event)方法,由于子类AnonymousObserver重写了onCore方法所以回到子类调用(不信你看 大大的override写着),最终找到执行保存的_eventHandler,参数为调用onNext时传递的参数,也就是我们写的字符串"测试",也就是我们创建订阅者时传进来的收到订阅回调。
    以及onCore方法

    至此:从创建序列 -> 订阅序列 -> 发送信号 -> 信号接收整个流程我们已经分析完毕。(我都觉得自己啰嗦的不行,但是没办法,谁让是重点,老老实实吃透吧)。

    最后流程总结:画图(改图为引用自Cooci老师)


    响应流程核心原理完整流程

    写这篇博客花了3个多小时,学习是枯燥的过程,但是坚持下来的时候是最爽的。

    相关文章

      网友评论

        本文标题:RXSwift基础用法及响应核心底层逻辑原理(超详细吐血篇)

        本文链接:https://www.haomeiwen.com/subject/jggwlctx.html