SwiftUI DataFlow

问题

  1. view 和 data 如何 two-way 绑定,View如何跟随Data的变化进行刷新
  2. view 和 data 声明周期
  3. 不同view之间如何share data
  4. @State @Binding @StateObject @ObserverableObject @ObserveredObject @EnvirmentObject 区别

为什么需要SwiftUI

graph TD
Code --> initialView 
Code --> updateView
updateView --> updateVieww
updateView --> updateData

平时我们在code页面代码的时候,codepath并不是单一路径的,很多情况下,data和view不统一导致问题的产生。 为了编写维护性更高的代码。

graph TD
code --> data 
data --> view

siggle code path,应呼声而出。 我们使用SwiftUI并不是说为了优化多少性能,而是提高代码的可维护性。使用框架避免问题的的发生。

SwiftUI的基本结构

struct SomeView: View {
    var body: some View {
        Text(" some view ")
    }
}
复制代码

所有的视图组件都是value类型的struct,随时随地rebuild. 如果这样的struct持有页面状态,当页面刷新的时候,所有的状态是否都会回归到默认状态?

这时候就需要我们property wrapper登场了

struct SomeView: View {
    @State var someState = false
    var someValue = ""
    var body: some View {
        Text(" some view ")
    }
}
复制代码

@State @Binding

graph TD
ContentView --> SomeView持有someValue
ContentViewObject --> SomeViewObject持有someState
  1. @State修饰的属性,不会由视图保存,而是另外保存。所以让视图rebuild的时候,视图的状态也不会丢失。
  2. 因为Swift中的属性都是值类型,所以如果多个视图想share state怎么办? 这时候就需要@binding 拿到 @state的引用。来share data.
struct SomeView: View {
    @State var someState = false
    var body: some View {
        OtherView(someState: $someState)
    }
}

struct OtherView: View {
    @Binding var someState: Bool
    var body: some View {
        Text("")
    }
}
复制代码

如果我有很多State,如果处理? 这里就引入StateObject的概念

@StateObject @ObservedObject ObservableObject

类比@State声明单一属性,@StateObject可以修饰一个复杂的状态对象。状态对象里面的属性是否是State,可以足有控制。

  1. 遵循ObservableObject协议,使用@published来Wrapper需要响应视图响应的属性
  2. value changed 必须在主线程
// 声明一个complexObject
class ComplexObject: ObservableObject {
    // 可相应视图rebuild的state
    @Published var someState = false
    var someValue = true
}

// 持有complexObject
struct SomeView: View {
    @StateObject var someStateObject = ComplexObject()
    var body: some View {
        OtherView(someStateObject: someStateObject)
    }
}

// 仅使用
struct OtherView: View {
    @ObservedObject var someStateObject: ComplexObject
    var body: some View {
        Text("")
    }
}
复制代码

这里有几个点讲一下

Q:为什么ComplexObject使用class

A: 因为ObservableObject必须遵循AnyObject,必须是class

Q: share State 不使用 $ 符号了

A: 因为是class,原本就是引用类型

Q: StateObject 和 ObservedObject的区别

A: 类似State 和 Binding,一个是持有使用状态,一个仅仅是使用状态

多视图share state需要视图初始化一个一个传递,也太麻烦了。所以引出我们的@EnvironmentObject

@EnvironmentObject

// 声明一个complexObject
class ComplexObject: ObservableObject {
    // 可相应视图rebuild的state
    @Published var someState = false
    var someValue = true
}

// 持有complexObject
struct SomeView: View {
    @StateObject var someStateObject = ComplexObject()
    var body: some View {
        //>>>>>>>>>>>>>>>>>>>>>>>看这里>>>>>>>>>>
        OtherView()
            .environmentObject(someStateObject)
        //
    }
}

// 仅使用
struct OtherView: View {
    //>>>>>>>>>>>>>>>>>>>>>>看这里
    @EnvironmentObject var someStateObject: ComplexObject
    
    var body: some View {
        Text("")
    }
}
复制代码
  1. 使用environmentObject的midifier注入对象
  2. 从EnvironmentObject取出对象

简单粗暴

参考

whats-the-difference-between-observedobject-state-and-environmentobject

猜你喜欢

转载自juejin.im/post/7120158284459278350