0%

Data Flow Through SwiftUI

  • 两种设计模式

    • 每次在视图中读取数据时,都会在那个视图中创建一个依赖

      每次数据发生变化时,视图也会发生变化

    • 在视图层级中个,读取的每一条数据,都只有一个数据源

      例如,在同级视图中,用同一个数据,你的实现是这样的:

      03:40

      这种实现会在不同的View中维护同一个数据来源,这一个过程很容易造成数据同步错误导致的BUG。不妨改成这样来实现:

      4:10

  • @State

    1
    @State var isPlaying: Bool = false

    @State告诉系统isPlaying是一个可以变化的值,视图也会随之改变

    9:08

    当你声明一个@State变量时,SwiftUI框架会为之分配永久存储,SwiftUI可以在变量发生变化时,重新渲染其关联的视图和其所有的SubvIew(只会重新渲染发生改变的地方)

    11:02

    在SwiftUI中,数据流向是单一向的

  • @Binding

    保持不同视图的数据同步

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    struct PlayerView: View {
    let episode: Episode
    @State private var isPlaying: Bool = false

    var body: some View {
    VStack {
    Text(episode.title).foregroundColor(isPlaying ?.white : .gray)
    Text(episode.showTitle).font(.caption).foregroundColor(.gray)
    PlayButton(isPlaying: $isPlaying)
    }
    }
    }

    struct PlayButton: View {
    // 这里的isPlaying和👆的是同一个,所以无需同步数据
    @Binding var isPlaying: Bool
    var body: some View {
    Button(action: {
    self.isPlaying.toggle()
    }) {
    Image(systemName: isPlaying ? "pause.circle" : "play.circle")
    }
    }
    }
  • Publisher

    19:45

    在SwiftUI中,使用Publisher来表述这些例如Timer和通知的外部事件。

    1
    2
    3
    4
    // 接受来自currentTimePublisher的事件
    .onReceive(PodcastPlayer.currentTimePublisher, perform: { newCurrentTime in
    self.currentTime = newCurrentTime
    })
    • BindableObject

      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      11
      12
      13
      class PodcastPlayerStore: BindableObject {

      var didChange = PassthroughSubject<Void, Never>()

      // ...

      func advance() {
      currentEpisode = nextEpisode
      currentTime = 0.0

      didChange.send()
      }
      }

      PassthroughSubject是一个Publisher,SwiftUI会订阅这个Publisher,来更新视图层级

      • @ObjectBinding

        当使用@ObjectBinding声明模型时,SwiftUI会识别出这个属性,并给它设置依赖,一旦模型发生变化,框架就会自动明白什么时候刷新视图。

        1
        2
        3
        4
        5
        6
        struct MyView: View {
        @ObjectBinding var model: MyModelObject
        // ...
        }

        MyView(model: modelInstance)

        26:08

        所有声明@ObjectBindng模型的视图,都会自动订阅模型,并在模型发生改变时,刷新视图。(即:依赖自动追踪)

    • 创建一个间接依赖

      上面声明的依赖关系,属于视图直接依赖,接下来看看如何生成一个视图的间接依赖

      27:01