一头扎进 RxSwift(一)

概述

从 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) in
    print(event.element)
}.addDisposableTo(bag)

一头扎进 RxSwift(一)_第1张图片

打印出来的结果有点吓唬人,再一看 element的类型也就不足为奇了。

还有另外一种写法:

textField1.rx.text.subscribe(onNext: { (str: String?) in
    print(str)
}).addDisposableTo(bag)
一头扎进 RxSwift(一)_第2张图片

这样打印出来的东西友好了许多。

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 的偏移量。


一头扎进 RxSwift(一)_第3张图片

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

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

你可能感兴趣的:(一头扎进 RxSwift(一))