美文网首页iOS-swiftswift收藏问题
一头扎进 RxSwift(一)

一头扎进 RxSwift(一)

作者: 張無忌 | 来源:发表于2017-04-23 11:38 被阅读1581次

    概述

    从 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 个参数:

    1. 监听的属性的类型
    2. 监听的属性的名字

    监听完毕之后,对该事件进行订阅,通过闭包形式进行回调。

    除此之外,还可以直接监听属性的改变,例如:监听 UIScrollView 的偏移量。


    读到这里,算对函数响应式编程RxSwiftRxCocoa有了初步的了解和认识。

    如果对你有所帮助,请点一个👍 ,谢谢!

    相关文章

      网友评论

      • 小明2021:点语法没提示可以敲空格然后方法的首字母就OK了
      • 混不吝丶:有没有2
        天净沙:@任兴金 同问有没有 qq 群
        任兴金:你好,我也正在学RxSwift 有没有qq可以交流一下
      • 风与心愿:代码补全那个bug,我的解决办法是:
        let temp = textField.rx.text
        temp.subscribe(...) //使用一个临时变量,然后就能使用点语法了,等写完了再把 temp 干掉即可
      • efcb9d5bedaf:请教,跨界面传值怎么实现啊?
        TeacherXue:闭包呀
        efcb9d5bedaf:@張無忌 就是不会传值:sweat:
        張無忌:@水电管家v 兄弟,我也是初学,还在学习中

      本文标题:一头扎进 RxSwift(一)

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