返回 导航

Swift

hangge.com

Swift - RxSwift的使用详解69(RxFeedback架构1:安装配置、基本用法)

作者:hangge | 2018-06-20 08:10
    在之前的文章中,我介绍了在 RxSwift 项目中如何使用 MVVM 架构进行开发(点击查看)。下面我介绍另一种架构:RxFeedback

一、基本介绍

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)

回到顶部