Swift - RxSwift的使用详解69(RxFeedback架构1:安装配置、基本用法)
作者:hangge | 2018-06-20 08:10
一、基本介绍
1,什么是 RxFeedback?
(1)RxFeedback 是用于 RxSwift 的一个架构,号称是最简单的 RxSwift 架构。他的作者同时也是 RxSwift 的创始人以及 ReactiveX 组织的核心成员。
typealias Feedback<State, Event> = (Observable<State>) -> Observable<Event> public static func system<State, Event>( initialState: State, reduce: @escaping (State, Event) -> State, feedback: Feedback<State, Event>... ) -> Observable<State>
(2)RxFeedback 的核心内容为状态(State)、事件(Event)、反馈循环(Feedback Loop):
- State:包含页面中各种需要的数据。我们可以用这些状态来控制页面内容的显示,或者触发另外一个事件。
- Event:用来描述所产生的事件。当发生某个事件时,更新当前状态。
- Feedback Loop:用来修改状态、IO 和资源管理的。比如我们可以将状态输出到 UI 页面上,或者将 UI 事件输入到反馈循环里面去。
2,安装配置
(1)RxFeedback 依赖于 RxSwift,关于 RxSwift 的安装配置可以看我之前的文章:
(2)接着把 RxFeedback 库下载到本地。
(3)将下载下来的源码包中 RxFeedback.xcodeproj 拖拽至工程中。
(4)工程 -> General -> Embedded Binaries 项,把 iOS 版的 RxFeedback.framework 添加进来
二、一个简单的样例(仅UI反馈)
1,效果图
(1)界面上有 1 个文本标签(label)、2 个按钮(button)。
(2)文本标签显示显示一个初始数字 0。
(3)点击按钮可以对这个初始数字进行“加1”或“减1”操作,并将结果实时更新到文本标签上。
2,样例代码
代码说明:
- 代码 15 行:状态定义。本样例的状态比较简单(就是一个数字)。
- 代码 18 ~ 21 行:定义各种改变状态的事件,本文样例就“加一”“减一”两个事件。
- 代码 31 ~ 38 行:在 reduce 根据不同的事件,对当前的状态进行修改,并返回新状态。
- 代码 39 ~ 52 行:feedback 后面可以添加多个反馈。本样例就一个 UI 反馈(UI feedback),即通过 UI.bind 分别将状态输出到页面控件上(subscriptions 部分),以及将 UI 事件变成 Event 输入到反馈循环里面去(events 部分)。
import UIKit import RxSwift import RxCocoa import RxFeedback class ViewController: UIViewController { @IBOutlet weak var label: UILabel! //显示数字的文本标签 @IBOutlet weak var minus: UIButton! //减一按钮 @IBOutlet weak var plus: UIButton! //加一按钮 let disposeBag = DisposeBag() //状态(就是一个Int类型的数字) typealias State = Int //事件 enum Event { case increment //加一 case decrement //减一 } override func viewDidLoad() { super.viewDidLoad() //RxRxFeedback的核心方法 Driver.system( //初始状态 initialState: 0, //各个事件对状态的改变 reduce: { (state, event) -> State in switch event { case .increment: return state + 1 case .decrement: return state - 1 } }, feedback: // UI反馈 bind(self) { me, state -> Bindings<ViewController.Event> in //状态输出到页面控件上 let subscriptions = [ state.map(String.init).drive(me.label!.rx.text) ] //将 UI 事件变成Event输入到反馈循环里面去 let events = [ me.plus!.rx.tap.map { Event.increment }, me.minus!.rx.tap.map { Event.decrement } ] return Bindings(subscriptions: subscriptions, events: events) } ) .drive() .disposed(by: disposeBag) } }
三、功能改进(增加非UI的自动反馈)
1,效果图
(1)和上面的功能一样,点击“加一”“减一”同样会改变数字并实时地显示在文本标签上。
(2)不同的是这个数字是文章 id,当其改变时会自动去请求相应的数据并显示在界面上。(为方便演示,我这里使用延时序列来模拟网络请求)。
2,样例代码
代码说明:
- 代码 16 ~ 19 行:状态定义。本样例的状态内容除了 id 值外,还有该 id 对应的内容。
- 代码 22 ~ 26 行:定义各种改变状态的事件,除了“加一”“减一”外,还增加了“数据响应”这个新事件。
- 代码 36 ~ 51 行:在 reduce 根据不同的事件,对当前的状态进行修改,并返回新状态。
- 代码 52 ~ 72 行:feedback 后面可以添加多个反馈。本样例除了前面介绍的 UI 反馈(UI feedback)外,还增加了个与 UI 无关的自动反馈(使用 react 方法),即根据状态 id 变化来自动去获取数据,并触发“数据响应”这个 Event。
import UIKit import RxSwift import RxCocoa import RxFeedback class ViewController: UIViewController { @IBOutlet weak var label: UILabel! //显示数字的文本标签 @IBOutlet weak var minus: UIButton! //减一按钮 @IBOutlet weak var plus: UIButton! //加一按钮 @IBOutlet weak var textView: UITextView! //显示内容 let disposeBag = DisposeBag() //状态 struct State { var id: Int //id数字 var content: String //当前id对应的内容 } //事件 enum Event { case increment //加一 case decrement //减一 case response(String) //获取到内容 } override func viewDidLoad() { super.viewDidLoad() //RxRxFeedback的核心方法 Driver.system( //初始状态 initialState: State(id:0, content:""), //各个事件对状态的改变 reduce: { (state, event) -> State in switch event { case .increment: var result = state result.id = result.id + 1 return result case .decrement: var result = state result.id = result.id - 1 return result case .response(let content): var result = state result.content = content return result } }, feedback: //UI反馈 bind(self) { me, state in //状态输出到页面控件上 let subscriptions = [ state.map{ "\($0.id)" }.drive(me.label!.rx.text), state.map{ "\($0.content)" }.drive(me.textView!.rx.text) ] //将 UI 事件变成Event输入到反馈循环里面去 let events = [ me.plus!.rx.tap.map { Event.increment }, me.minus!.rx.tap.map { Event.decrement } ] return Bindings(subscriptions: subscriptions, events: events) }, //非UI的自动反馈 react(query: { $0.id }, effects: { id in return self.getContent(id: id) .asSignal(onErrorRecover: { _ in .empty() }) .map(Event.response) }) ) .drive() .disposed(by: disposeBag) } //根据id获取对应数据 func getContent(id: Int) -> Observable<String> { print("正在请求数据......") let observable = Observable.just("这个是 id=\(id) 的新闻内容......") //延迟1秒模拟网络请求 return observable.delay(1, scheduler: MainScheduler.instance) } }
全部评论(0)