iOS初识RxSwift

572 阅读4分钟

一、RxSwift

Microsoft 的一个团队接受了解决我们在本章中讨论过的异步、可扩展、实时应用程序开发问题的挑战。大约在 2009 年的某个时候,他们提供了一个名为 Reactive Extensions for .NET (Rx) 的新客户端和服务器端框架。Rx for .NET 自 2012 年以来一直是开源的,允许其他语言和平台重新实现相同的功能,这将 Rx 变成了跨平台标准。今天,您拥有 RxJS、RxKotlin、Rx.NET、RxScala、RxSwift 等等。基于响应式扩展规范,所有人都努力实现相同的行为和相同的表达 API。最终,使用 RxSwift 创建 iOS 应用程序的开发人员可以在网络上与其他使用 RxJS 的程序员自由讨论应用程序逻辑。

什么是RxSwift?学习RxSwift有哪些优势呢?

  • 复合 - Rx就是复合的代名词
  • 复用 - 复用性比较强 - 代码量降低
  • 清晰 - 因为声明都是不可变更的,代码函数式编程可读性强
  • 易用 - 理解容易,还抽象了异步编程,统一代码风格
  • 稳定 - 因为Rx是完全通过单元测试的

1、函数式编程

响应式编程(reactive programming)是一种基于数据流(data stream)和变化传递(propagation of change)的声明式(declarative)的编程范式。

我有一个栗子:

let array = [1, 2, 3, 4, 5, 6, 7]

        // 首先获取 > 3的数字
        // 获取的数字之后 + 1
        // 所有数字中的偶数

那我们能想到的做法是一个for循环先判断>3,后+1在取偶数。

    for num in array {
            if num > 3 {
                let number = num + 1
                if (number % 2 == 0) {
                    print(number)
                }
            }
   }

image.png 可是这个代码的可读性,清晰度,可维护性较差。有没有更少的代码,可清晰的方式来完成呢?

array.filter { $0 > 3 }
            .filter { ($0+1) % 2 == 0 }
            .forEach { print($0+1) }

image.png

函数响应式编程

函数式负责序列操作,响应式负责监听变化,响应这个序列。当然这个序列是具备着特别的封装(异步等)
我们通过不同的构建函数,来创建所需要的数据序列。最后通过适当的方式来响应这个序列。这就是函数响应式编程。

extension Binder {
    func bindingValueRx( first : inout Int, second : inout Int) -> (String) -> Binder  {
        return { output in
            // binding a and b to result
            print(output)
            return self
        }
    }
    func unbindingValueRx( first : inout Int, second : inout Int) -> () -> Binder  {
        return {
            //unbindg a and b to result
            return self
        }
    }
}
//可以通过 .函数.函数 表达出来
binder.bindingValueRx(first: &a, second: &b)("finished").unbindingValueRx(first: &a, second: &b)()

2、基础用法

搭建一个工程配置Podfile:

target '002-RxSwift初探' do
  # Comment the next line if you're not using Swift and don't want to use dynamic frameworks
  use_frameworks!
  pod 'RxSwift'
  pod 'RxCocoa'
  # Pods for 002-RxSwift初探
end

然后熟练的开始在Main.storyboard 上布局如下: image.png 先来了解一下在swift中KVO的使用

//记住需要标识 Objc dynamic 
@objc dynamic var name: String = "我真6"

func setupKVO() {
        //三部曲 
        self.person.addObserver(self, forKeyPath: "name", options: .new, context: nil)
        //1.注册观察者
}
//修改 name
override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) {
        textFiled.resignFirstResponder()
        print("来了")
        person.name = "\(person.name) 6"
        // print(person.name)
}

//2.响应
override func observeValue(forKeyPath keyPath: String?, of object: Any?, change: [NSKeyValueChangeKey : Any]?, context: UnsafeMutableRawPointer?) {
        print("响应")
        print(change as Any)
}
//3.释放kvo
deinit {
        self.removeObserver(self.person, forKeyPath: "name", context: nil)
}

打印结果:
**2022-08-25 22:18:30.317247+0800 002-RxSwift初探[3311:40668] Writing analzed variants.**
**来了**
**响应**
**NSKeyValueChangeKey(_rawValue: new): 我真6 6])**

如果我们使用RXSwift响应序列就变的很简单了:

func setupKVO() {
        //响应序列
        self.person.rx.observeWeakly(String.self, "name")
            .subscribe { value in
                print(value as Any)
            }
            .disposed(by: disposeBag)
}

你看只需要几行代码就能完成,不需要原本的三部曲了。 image.png

核心问题
为什么所有对象都能.rx呢?
rx是如何让对象可使用相应序列的呢? image.png 我们看到NSObject进行了扩展继承了ReactiveCompatible协议并扩展实现了rx的get,set方法。

observable的流程图: image.png

通过几个例子

继续探索:

//**MARK: - RxSwift应用-timer定时器**
func setupTimer() {
        timer = Observable<Int>.interval(.seconds(1), scheduler: MainScheduler.instance)
        timer.subscribe { num in
            print(num)
        }
        .disposed(by: disposeBag)
}
    
//**MARK: - RxSwift应用-scrollView**
func setupScrollerView() {
    scrollView.rx.contentOffset
    .subscribe { [weak self]content in
    self?.view.backgroundColor = UIColor.init(red: content.y/255*0.8, green: content.y/255*0.6, blue: content.y/255*0.3, alpha: 1) }
            .disposed(by: disposeBag)
}

//**MARK: - RxSwift应用-textfiled**
func setupTextFiled() {
        self.textFiled.rx.text.orEmpty.changed
            .subscribe { text in
                print(text)
            }
            .disposed(by: disposeBag)
        //RxSwift更加面向开发者
        self.textFiled.rx.text
            .bind(to: self.button.rx.title())
            .disposed(by: disposeBag)
}

//**MARK: - RxSwift应用-button响应**
func setupButton() {
 //功能逻辑/业务逻辑分开了
//        self.button.addTarget(self, action: #selector(<#T##@objc method#>), for: .touchUpInside)
    self.button.rx.controlEvent(.touchUpInside)
            .subscribe { _ in
                print("点击事件")
            }
            .disposed(by: disposeBag)
}

总结

  1. RxSwift就是函数响应式编程的框架,减少了大量胶水代码,使代码清晰,复用,可读性提升。
  2. RxSwift的核心是使用了Observable 的函数闭包->订阅保存->然后通知响应到对应 AnonymousObservableSink-run(Ob) 执行。
  3. RxSwift的主要流程: 创建序列 --> 订阅序列 --> 发送信号 --> 信号接收。
  4. DisposeBag就像个垃圾袋一样,我们把创建的序列放在DisposeBag这个垃圾袋中,他会在合适的时候帮我们释放资源。