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)