SwiftUI — Combine 实践 双向绑定和时间机器

学习完苹果的教程
我们知道了通过@State 就可以实现 数据和UI的绑定
修改APP就可以直接修改数据的State 例如

@State private var showDetail = true
Button(action: {
 self.showDetail.toggle()
}
 if showDetail {
  HikeDetail(hike: hike).transition(.moveAndFade)
 }

当点击Button的时候会修改数据,同时SwiftUI会reload页面
做过大型一点的APP的同学都会知道 当你们公司出现数据部门的时候
APP端就会要求打点 对用户当前所做的操作做记录 那么用户的所有操作都会定义一个State 我们就可以创建一个protocol 来完成这件事

//
public protocol StateMachine {

    // 定义你APP内可能发生的事情例如:添加一个item 修改item Title
    associatedtype Event

    //储存事件信息
    mutating func update(with event: Event)
}

     //事件类型
    enum Event {
            //开始创建item 点击 +
             case startCreatingItem
            //取消创建item 点击 后面蒙版
             case cancelCreatingItem
            //修改 添加 title
             case changePartialItemName(String)
            //点击add
             case addItem
            //点击Toggle 开关
             case setItemDone(identifier: UUID, isDone: Bool)
    }

用户操作后你就要记录下来 那么通过上面你就可以知道我们可以创建一个记录操作的类 在用户操作的时候自动记录
数据部门还会有需求,把用户的操作链式表现,那么就可以用数组装下他
创建一个全局的Store,并增加一个方法记录TodoState

@EnvironmentObject var store: Store
 // 添加事件
     private var subsequentStates: [TodoState] = []

        func dispatch(event: TodoState.Event) {
           var newState = state
           newState.update(with: event)
           subsequentStates.append(newState)
       }

说到这里呢,最后把数据上报,就已经完成了数据部门的要求。
我们已经完成了View对State的绑定,学过前端的同学就知道,前端一般都会实现双向绑定,单向绑定非常简单,就是 用户修改View,也更新了State的数据。有单向绑定,就有双向绑定。如果用户更新了State时,View就会自动更新,这种情况就是双向绑定。

把UI根据当前的State绑定

var body: some View {
        ZStack{
            NavigationView{
                List(store.state.todoItems){item in
                    TodoListItem(item: item)
                }.navigationBarTitle(Text("TimeTrave"))
                    .navigationBarItems(trailing: Button(action: {
                        self.store.dispatch(event: .startCreatingItem)
                    }, label: {
                        Image(systemName: "plus.circle")
                    }))
            }
            if store.state.isCreatingItem {
                ModalDimmingView()
                    VStack{
                    Spacer()
                    AddItemView()
                    .background(Color.white)
                    .cornerRadius(12.0)
                    .shadow(radius: 16.0)
                    .padding()
                    Spacer()
                    }
                .transition(.move(edge: .bottom))
            }
        }
双向绑定

那么UI绑定已经绑定State,那怎么实现State发生变化View就能变化了,那我们就可以让Store成为一个ObservableObject,绑定方法也修改,当前State需要改变时,发布change,当currentState发生变化的时候就可以让View发生变化了

//观察对象
public final class Store: ObservableObject {
    //初始State
    private let initialState: TodoState
    //储存TodoState
    private var subsequentStates: [TodoState] = []
    //Publisher 发布者 发布状态改变
    public let objectWillChange = PassthroughSubject<Void, Never>()

  //当前state需要改变时 发布change
    var currentStateIndex: Int = 0 {
        didSet {
            withAnimation {
                objectWillChange.send(())
            }
        }
    }

       func dispatch(event: TodoState.Event) {
           var newState = state
           newState.update(with: event)
           subsequentStates.append(newState)
           currentStateIndex = stateCount - 1
       }

最后既然我们都实现了双向绑定那么就可以手动修改currentState看一下,用一个Slider绑定currentStateIndex

 let indexBinding = Binding(
        get: {
           return Double(self.store.currentStateIndex)
        }, set: {
            self.store.currentStateIndex = Int($0)
    })
 Slider(value: indexBinding, in: 0...Double(store.stateCount - 1)

当你拖动Slider的时候,是不是就有种时间机器的感觉,可以回到任意的State,看一下效果

TimeTrave.gif

最后放上代码地址

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 203,547评论 6 477
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,399评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 150,428评论 0 337
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,599评论 1 274
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,612评论 5 365
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,577评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,941评论 3 395
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,603评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,852评论 1 297
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,605评论 2 321
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,693评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,375评论 4 318
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,955评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,936评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,172评论 1 259
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 43,970评论 2 349
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,414评论 2 342

推荐阅读更多精彩内容