data flow through swiftui · 2019-11-07 · tools for data flow property @binding bindableobject...

122
#WWDC19 © 2019 Apple Inc. All rights reserved. Redistribution or public display not permitted without written permission from Apple. Luca Bernardi, SwiftUI Engineer Raj Ramamurthy, SwiftUI Engineer Data Flow Through SwiftUI

Upload: others

Post on 21-Jun-2020

5 views

Category:

Documents


0 download

TRANSCRIPT

Page 1: Data Flow Through SwiftUI · 2019-11-07 · Tools for Data Flow Property @Binding BindableObject @Environment @State. Data Access as a Dependency PlayerView isPlaying: Bool. Data

#WWDC19

© 2019 Apple Inc. All rights reserved. Redistribution or public display not permitted without written permission from Apple.

Luca Bernardi, SwiftUI Engineer Raj Ramamurthy, SwiftUI Engineer

•Data Flow Through SwiftUI

Page 2: Data Flow Through SwiftUI · 2019-11-07 · Tools for Data Flow Property @Binding BindableObject @Environment @State. Data Access as a Dependency PlayerView isPlaying: Bool. Data

•Principles of Data Flow •Anatomy of an Update •Understanding Your Data

Page 3: Data Flow Through SwiftUI · 2019-11-07 · Tools for Data Flow Property @Binding BindableObject @Environment @State. Data Access as a Dependency PlayerView isPlaying: Bool. Data

•Principles of Data Flow •Anatomy of an Update •Understanding Your Data

Page 4: Data Flow Through SwiftUI · 2019-11-07 · Tools for Data Flow Property @Binding BindableObject @Environment @State. Data Access as a Dependency PlayerView isPlaying: Bool. Data

•Principles of Data Flow •Anatomy of an Update •Understanding Your Data

Page 5: Data Flow Through SwiftUI · 2019-11-07 · Tools for Data Flow Property @Binding BindableObject @Environment @State. Data Access as a Dependency PlayerView isPlaying: Bool. Data

What is data?

Page 6: Data Flow Through SwiftUI · 2019-11-07 · Tools for Data Flow Property @Binding BindableObject @Environment @State. Data Access as a Dependency PlayerView isPlaying: Bool. Data

Tools for Data Flow

Property

@Binding

BindableObject

@Environment

@State

Page 7: Data Flow Through SwiftUI · 2019-11-07 · Tools for Data Flow Property @Binding BindableObject @Environment @State. Data Access as a Dependency PlayerView isPlaying: Bool. Data

Data Access as a Dependency

PlayerView isPlaying: Bool

Page 8: Data Flow Through SwiftUI · 2019-11-07 · Tools for Data Flow Property @Binding BindableObject @Environment @State. Data Access as a Dependency PlayerView isPlaying: Bool. Data

Data Access as a Dependency

PlayerView isPlaying: Bool

Page 9: Data Flow Through SwiftUI · 2019-11-07 · Tools for Data Flow Property @Binding BindableObject @Environment @State. Data Access as a Dependency PlayerView isPlaying: Bool. Data

Data Access as a Dependency

PlayerView false

Page 10: Data Flow Through SwiftUI · 2019-11-07 · Tools for Data Flow Property @Binding BindableObject @Environment @State. Data Access as a Dependency PlayerView isPlaying: Bool. Data

Data Access as a Dependency

falsePlayerViewPlayerView

Page 11: Data Flow Through SwiftUI · 2019-11-07 · Tools for Data Flow Property @Binding BindableObject @Environment @State. Data Access as a Dependency PlayerView isPlaying: Bool. Data

Data Access as a Dependency

truePlayerView

Page 12: Data Flow Through SwiftUI · 2019-11-07 · Tools for Data Flow Property @Binding BindableObject @Environment @State. Data Access as a Dependency PlayerView isPlaying: Bool. Data

Source of Truth

Page 13: Data Flow Through SwiftUI · 2019-11-07 · Tools for Data Flow Property @Binding BindableObject @Environment @State. Data Access as a Dependency PlayerView isPlaying: Bool. Data

Source of Truth

accentColor: Color

isPlaying: Bool

store: MessageStore

post: PhotoPost

Page 14: Data Flow Through SwiftUI · 2019-11-07 · Tools for Data Flow Property @Binding BindableObject @Environment @State. Data Access as a Dependency PlayerView isPlaying: Bool. Data

Duplicated Source of Truth

View

ViewView

isPlaying: Bool isPlaying: Bool

Page 15: Data Flow Through SwiftUI · 2019-11-07 · Tools for Data Flow Property @Binding BindableObject @Environment @State. Data Access as a Dependency PlayerView isPlaying: Bool. Data

Duplicated Source of Truth

View

ViewView

isPlaying: Bool isPlaying: Bool

Page 16: Data Flow Through SwiftUI · 2019-11-07 · Tools for Data Flow Property @Binding BindableObject @Environment @State. Data Access as a Dependency PlayerView isPlaying: Bool. Data

Duplicated Source of Truth

View

ViewView

isPlaying: BoolisPlaying: Bool

Page 17: Data Flow Through SwiftUI · 2019-11-07 · Tools for Data Flow Property @Binding BindableObject @Environment @State. Data Access as a Dependency PlayerView isPlaying: Bool. Data

Single Source of Truth

View

ViewView

isPlaying: Bool

Page 18: Data Flow Through SwiftUI · 2019-11-07 · Tools for Data Flow Property @Binding BindableObject @Environment @State. Data Access as a Dependency PlayerView isPlaying: Bool. Data

Single Source of Truth

View

ViewView

isPlaying: Bool

Page 19: Data Flow Through SwiftUI · 2019-11-07 · Tools for Data Flow Property @Binding BindableObject @Environment @State. Data Access as a Dependency PlayerView isPlaying: Bool. Data

Single Source of Truth

View

ViewView

isPlaying: Bool

Page 20: Data Flow Through SwiftUI · 2019-11-07 · Tools for Data Flow Property @Binding BindableObject @Environment @State. Data Access as a Dependency PlayerView isPlaying: Bool. Data
Page 21: Data Flow Through SwiftUI · 2019-11-07 · Tools for Data Flow Property @Binding BindableObject @Environment @State. Data Access as a Dependency PlayerView isPlaying: Bool. Data

struct PlayerView : View { let episode: Episode

var body: some View { VStack { Text(episode.title) Text(episode.showTitle).font(.caption).foregroundColor(.gray) } } }

Page 22: Data Flow Through SwiftUI · 2019-11-07 · Tools for Data Flow Property @Binding BindableObject @Environment @State. Data Access as a Dependency PlayerView isPlaying: Bool. Data

struct PlayerView : View { let episode: Episode

var body: some View { VStack { Text(episode.title) Text(episode.showTitle).font(.caption).foregroundColor(.gray) } } }

Page 23: Data Flow Through SwiftUI · 2019-11-07 · Tools for Data Flow Property @Binding BindableObject @Environment @State. Data Access as a Dependency PlayerView isPlaying: Bool. Data

struct PlayerView : View { let episode: Episode

var body: some View { VStack { Text(episode.title) Text(episode.showTitle).font(.caption).foregroundColor(.gray) } } }

Page 24: Data Flow Through SwiftUI · 2019-11-07 · Tools for Data Flow Property @Binding BindableObject @Environment @State. Data Access as a Dependency PlayerView isPlaying: Bool. Data

struct PlayerView : View { let episode: Episode

var body: some View { VStack { Text(episode.title) Text(episode.showTitle).font(.caption).foregroundColor(.gray) } } }

Page 25: Data Flow Through SwiftUI · 2019-11-07 · Tools for Data Flow Property @Binding BindableObject @Environment @State. Data Access as a Dependency PlayerView isPlaying: Bool. Data

struct PlayerView : View { let episode: Episode var isPlaying: Bool

var body: some View { VStack { Text(episode.title) Text(episode.showTitle).font(.caption).foregroundColor(.gray)

Image(systemName: isPlaying ? "pause.circle" : "play.circle") } } }

Page 26: Data Flow Through SwiftUI · 2019-11-07 · Tools for Data Flow Property @Binding BindableObject @Environment @State. Data Access as a Dependency PlayerView isPlaying: Bool. Data

struct PlayerView : View { let episode: Episode var isPlaying: Bool

var body: some View { VStack { Text(episode.title) Text(episode.showTitle).font(.caption).foregroundColor(.gray)

Image(systemName: isPlaying ? "pause.circle" : "play.circle") } } }

Page 27: Data Flow Through SwiftUI · 2019-11-07 · Tools for Data Flow Property @Binding BindableObject @Environment @State. Data Access as a Dependency PlayerView isPlaying: Bool. Data

struct PlayerView : View { let episode: Episode var isPlaying: Bool var body: some View { VStack { Text(episode.title) Text(episode.showTitle).font(.caption).foregroundColor(.gray)

Button(action: { self.isPlaying.toggle() }) { Image(systemName: isPlaying ? "pause.circle" : "play.circle") } } } }

Page 28: Data Flow Through SwiftUI · 2019-11-07 · Tools for Data Flow Property @Binding BindableObject @Environment @State. Data Access as a Dependency PlayerView isPlaying: Bool. Data

struct PlayerView : View { let episode: Episode var isPlaying: Bool var body: some View { VStack { Text(episode.title) Text(episode.showTitle).font(.caption).foregroundColor(.gray)

Button(action: { self.isPlaying.toggle() }) { Image(systemName: isPlaying ? "pause.circle" : "play.circle") } } } }

Page 29: Data Flow Through SwiftUI · 2019-11-07 · Tools for Data Flow Property @Binding BindableObject @Environment @State. Data Access as a Dependency PlayerView isPlaying: Bool. Data

struct PlayerView : View { let episode: Episode var isPlaying: Bool var body: some View { VStack { Text(episode.title) Text(episode.showTitle).font(.caption).foregroundColor(.gray)

Button(action: { self.isPlaying.toggle() }) { Image(systemName: isPlaying ? "pause.circle" : "play.circle") } } } }

Cannot use mutating member on immutable value: 'self' is immutable

Page 30: Data Flow Through SwiftUI · 2019-11-07 · Tools for Data Flow Property @Binding BindableObject @Environment @State. Data Access as a Dependency PlayerView isPlaying: Bool. Data

struct PlayerView : View { let episode: Episode @State private var isPlaying: Bool = false var body: some View { VStack { Text(episode.title) Text(episode.showTitle).font(.caption).foregroundColor(.gray)

Button(action: { self.isPlaying.toggle() }) { Image(systemName: isPlaying ? "pause.circle" : "play.circle") } } } }

Page 31: Data Flow Through SwiftUI · 2019-11-07 · Tools for Data Flow Property @Binding BindableObject @Environment @State. Data Access as a Dependency PlayerView isPlaying: Bool. Data

struct PlayerView : View { let episode: Episode @State private var isPlaying: Bool = false var body: some View { VStack { Text(episode.title) Text(episode.showTitle).font(.caption).foregroundColor(.gray)

Button(action: { self.isPlaying.toggle() }) { Image(systemName: isPlaying ? "pause.circle" : "play.circle") } } } }

false

Page 32: Data Flow Through SwiftUI · 2019-11-07 · Tools for Data Flow Property @Binding BindableObject @Environment @State. Data Access as a Dependency PlayerView isPlaying: Bool. Data

struct PlayerView : View { let episode: Episode @State private var isPlaying: Bool = false var body: some View { VStack { Text(episode.title) Text(episode.showTitle).font(.caption).foregroundColor(.gray)

Button(action: { self.isPlaying.toggle() }) { Image(systemName: isPlaying ? "pause.circle" : "play.circle") } } } }

false

Page 33: Data Flow Through SwiftUI · 2019-11-07 · Tools for Data Flow Property @Binding BindableObject @Environment @State. Data Access as a Dependency PlayerView isPlaying: Bool. Data

struct PlayerView : View { let episode: Episode @State private var isPlaying: Bool = false var body: some View { VStack { Text(episode.title) Text(episode.showTitle).font(.caption).foregroundColor(.gray)

Button(action: { self.isPlaying.toggle() }) { Image(systemName: isPlaying ? "pause.circle" : "play.circle") } } } }

true

Page 34: Data Flow Through SwiftUI · 2019-11-07 · Tools for Data Flow Property @Binding BindableObject @Environment @State. Data Access as a Dependency PlayerView isPlaying: Bool. Data

Wraps property access with additional behavior

What’s New in Swift WWDC 2019

Modern Swift API Design Thursday, 2:00

Property Wrapper

Page 35: Data Flow Through SwiftUI · 2019-11-07 · Tools for Data Flow Property @Binding BindableObject @Environment @State. Data Access as a Dependency PlayerView isPlaying: Bool. Data

@State Property Wrapper

@State private var isPlaying: Bool = false

PlayerView

SwiftUI

Page 36: Data Flow Through SwiftUI · 2019-11-07 · Tools for Data Flow Property @Binding BindableObject @Environment @State. Data Access as a Dependency PlayerView isPlaying: Bool. Data

@State Property Wrapper

@State private var isPlaying: Bool = false

PlayerView isPlaying = false

SwiftUI

Page 37: Data Flow Through SwiftUI · 2019-11-07 · Tools for Data Flow Property @Binding BindableObject @Environment @State. Data Access as a Dependency PlayerView isPlaying: Bool. Data

Anatomy of a View Update

PlayerView

ButtonTextText

SwiftUI isPlaying = false

Page 38: Data Flow Through SwiftUI · 2019-11-07 · Tools for Data Flow Property @Binding BindableObject @Environment @State. Data Access as a Dependency PlayerView isPlaying: Bool. Data

PlayerView

TextText

SwiftUI isPlaying = false

Anatomy of a View Update

Button

Page 39: Data Flow Through SwiftUI · 2019-11-07 · Tools for Data Flow Property @Binding BindableObject @Environment @State. Data Access as a Dependency PlayerView isPlaying: Bool. Data

PlayerView

TextText

SwiftUI isPlaying = false

Anatomy of a View Update

isPlaying = true

Button

Page 40: Data Flow Through SwiftUI · 2019-11-07 · Tools for Data Flow Property @Binding BindableObject @Environment @State. Data Access as a Dependency PlayerView isPlaying: Bool. Data

Anatomy of a View Update

PlayerView

SwiftUI

ButtonTextText

isPlaying = true

Page 41: Data Flow Through SwiftUI · 2019-11-07 · Tools for Data Flow Property @Binding BindableObject @Environment @State. Data Access as a Dependency PlayerView isPlaying: Bool. Data

Anatomy of a View Update

PlayerView

ButtonTextText

SwiftUI isPlaying = true

PlayerView

ButtonTextText

Page 42: Data Flow Through SwiftUI · 2019-11-07 · Tools for Data Flow Property @Binding BindableObject @Environment @State. Data Access as a Dependency PlayerView isPlaying: Bool. Data

Anatomy of a View Update

PlayerView

ButtonTextText

SwiftUI isPlaying = true

Page 43: Data Flow Through SwiftUI · 2019-11-07 · Tools for Data Flow Property @Binding BindableObject @Environment @State. Data Access as a Dependency PlayerView isPlaying: Bool. Data

Every @State is a source of truth.

Page 44: Data Flow Through SwiftUI · 2019-11-07 · Tools for Data Flow Property @Binding BindableObject @Environment @State. Data Access as a Dependency PlayerView isPlaying: Bool. Data

Views are a function of state, not of a sequence of events.

Page 45: Data Flow Through SwiftUI · 2019-11-07 · Tools for Data Flow Property @Binding BindableObject @Environment @State. Data Access as a Dependency PlayerView isPlaying: Bool. Data

!

Page 46: Data Flow Through SwiftUI · 2019-11-07 · Tools for Data Flow Property @Binding BindableObject @Environment @State. Data Access as a Dependency PlayerView isPlaying: Bool. Data

!

SwiftUI

Page 47: Data Flow Through SwiftUI · 2019-11-07 · Tools for Data Flow Property @Binding BindableObject @Environment @State. Data Access as a Dependency PlayerView isPlaying: Bool. Data

!User Interaction

SwiftUI

Action

Page 48: Data Flow Through SwiftUI · 2019-11-07 · Tools for Data Flow Property @Binding BindableObject @Environment @State. Data Access as a Dependency PlayerView isPlaying: Bool. Data

!User Interaction

SwiftUI

Action

Page 49: Data Flow Through SwiftUI · 2019-11-07 · Tools for Data Flow Property @Binding BindableObject @Environment @State. Data Access as a Dependency PlayerView isPlaying: Bool. Data

!User Interaction

SwiftUI

Action

State

Mutation

Page 50: Data Flow Through SwiftUI · 2019-11-07 · Tools for Data Flow Property @Binding BindableObject @Environment @State. Data Access as a Dependency PlayerView isPlaying: Bool. Data

!User Interaction

SwiftUI

Action

State

Mutation

Page 51: Data Flow Through SwiftUI · 2019-11-07 · Tools for Data Flow Property @Binding BindableObject @Environment @State. Data Access as a Dependency PlayerView isPlaying: Bool. Data

!User Interaction

SwiftUI

Action

State

Mutation

View

Updates

Page 52: Data Flow Through SwiftUI · 2019-11-07 · Tools for Data Flow Property @Binding BindableObject @Environment @State. Data Access as a Dependency PlayerView isPlaying: Bool. Data

!User Interaction

SwiftUI

Action

State

Mutation

View

Updates

Page 53: Data Flow Through SwiftUI · 2019-11-07 · Tools for Data Flow Property @Binding BindableObject @Environment @State. Data Access as a Dependency PlayerView isPlaying: Bool. Data

!User Interaction

SwiftUI

Action

State

Mutation

View

Updates

Render

Page 54: Data Flow Through SwiftUI · 2019-11-07 · Tools for Data Flow Property @Binding BindableObject @Environment @State. Data Access as a Dependency PlayerView isPlaying: Bool. Data

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)

Button(action: { self.isPlaying.toggle() }) { Image(systemName: isPlaying ? "pause.circle" : "play.circle") } } } }

Page 55: Data Flow Through SwiftUI · 2019-11-07 · Tools for Data Flow Property @Binding BindableObject @Environment @State. Data Access as a Dependency PlayerView isPlaying: Bool. Data

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)

Button(action: { self.isPlaying.toggle() }) { Image(systemName: isPlaying ? "pause.circle" : "play.circle") } } } }

Page 56: Data Flow Through SwiftUI · 2019-11-07 · Tools for Data Flow Property @Binding BindableObject @Environment @State. Data Access as a Dependency PlayerView isPlaying: Bool. Data

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)

Button(action: { self.isPlaying.toggle() }) { Image(systemName: isPlaying ? "pause.circle" : "play.circle") } } } }

Page 57: Data Flow Through SwiftUI · 2019-11-07 · Tools for Data Flow Property @Binding BindableObject @Environment @State. Data Access as a Dependency PlayerView isPlaying: Bool. Data

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)

Button(action: { self.isPlaying.toggle() }) { Image(systemName: isPlaying ? "pause.circle" : "play.circle") } } } }

Page 58: Data Flow Through SwiftUI · 2019-11-07 · Tools for Data Flow Property @Binding BindableObject @Environment @State. Data Access as a Dependency PlayerView isPlaying: Bool. Data

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() } } }

Page 59: Data Flow Through SwiftUI · 2019-11-07 · Tools for Data Flow Property @Binding BindableObject @Environment @State. Data Access as a Dependency PlayerView isPlaying: Bool. Data

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() } } }

Page 60: Data Flow Through SwiftUI · 2019-11-07 · Tools for Data Flow Property @Binding BindableObject @Environment @State. Data Access as a Dependency PlayerView isPlaying: Bool. Data

struct PlayButton : View { @State private var isPlaying: Bool = false

var body: some View { Button(action: { self.isPlaying.toggle() }) { Image(systemName: isPlaying ? "pause.circle" : "play.circle") } } }

Page 61: Data Flow Through SwiftUI · 2019-11-07 · Tools for Data Flow Property @Binding BindableObject @Environment @State. Data Access as a Dependency PlayerView isPlaying: Bool. Data

struct PlayButton : View { @State private var isPlaying: Bool = false

var body: some View { Button(action: { self.isPlaying.toggle() }) { Image(systemName: isPlaying ? "pause.circle" : "play.circle") } } }

Page 62: Data Flow Through SwiftUI · 2019-11-07 · Tools for Data Flow Property @Binding BindableObject @Environment @State. Data Access as a Dependency PlayerView isPlaying: Bool. Data

struct PlayButton : View { @State private var isPlaying: Bool = false

var body: some View { Button(action: { self.isPlaying.toggle() }) { Image(systemName: isPlaying ? "pause.circle" : "play.circle") } } }

Page 63: Data Flow Through SwiftUI · 2019-11-07 · Tools for Data Flow Property @Binding BindableObject @Environment @State. Data Access as a Dependency PlayerView isPlaying: Bool. Data

@Binding Property Wrapper

Read and write without ownership

Derivable from @State

@Binding var isPlaying: Bool

Page 64: Data Flow Through SwiftUI · 2019-11-07 · Tools for Data Flow Property @Binding BindableObject @Environment @State. Data Access as a Dependency PlayerView isPlaying: Bool. Data

struct PlayButton : View { @Binding var isPlaying: Bool var body: some View { Button(action: { self.isPlaying.toggle() }) { Image(systemName: isPlaying ? "pause.circle" : "play.circle") } } }

Page 65: Data Flow Through SwiftUI · 2019-11-07 · Tools for Data Flow Property @Binding BindableObject @Environment @State. Data Access as a Dependency PlayerView isPlaying: Bool. Data

struct PlayButton : View { @Binding var isPlaying: Bool var body: some View { Button(action: { self.isPlaying.toggle() }) { Image(systemName: isPlaying ? "pause.circle" : "play.circle") } } }

Page 66: Data Flow Through SwiftUI · 2019-11-07 · Tools for Data Flow Property @Binding BindableObject @Environment @State. Data Access as a Dependency PlayerView isPlaying: Bool. Data

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) } } }

Page 67: Data Flow Through SwiftUI · 2019-11-07 · Tools for Data Flow Property @Binding BindableObject @Environment @State. Data Access as a Dependency PlayerView isPlaying: Bool. Data

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) } } }

Page 68: Data Flow Through SwiftUI · 2019-11-07 · Tools for Data Flow Property @Binding BindableObject @Environment @State. Data Access as a Dependency PlayerView isPlaying: Bool. Data

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) } } }

Page 69: Data Flow Through SwiftUI · 2019-11-07 · Tools for Data Flow Property @Binding BindableObject @Environment @State. Data Access as a Dependency PlayerView isPlaying: Bool. Data

PlayerViewController

Page 70: Data Flow Through SwiftUI · 2019-11-07 · Tools for Data Flow Property @Binding BindableObject @Environment @State. Data Access as a Dependency PlayerView isPlaying: Bool. Data

PlayerView

PlayerViewController isPlaying

PlayButton

isPlaying

Page 71: Data Flow Through SwiftUI · 2019-11-07 · Tools for Data Flow Property @Binding BindableObject @Environment @State. Data Access as a Dependency PlayerView isPlaying: Bool. Data

PlayerView

PlayerViewController isPlaying

PlayButton

isPlaying

Page 72: Data Flow Through SwiftUI · 2019-11-07 · Tools for Data Flow Property @Binding BindableObject @Environment @State. Data Access as a Dependency PlayerView isPlaying: Bool. Data

PlayerView

PlayerViewController

isPlayingisPlaying

Page 73: Data Flow Through SwiftUI · 2019-11-07 · Tools for Data Flow Property @Binding BindableObject @Environment @State. Data Access as a Dependency PlayerView isPlaying: Bool. Data

PlayerView

PlayerViewController

isPlaying

PlayButton

isPlaying

Page 74: Data Flow Through SwiftUI · 2019-11-07 · Tools for Data Flow Property @Binding BindableObject @Environment @State. Data Access as a Dependency PlayerView isPlaying: Bool. Data

PlayerView

isPlaying

PlayButton

isPlaying

Page 75: Data Flow Through SwiftUI · 2019-11-07 · Tools for Data Flow Property @Binding BindableObject @Environment @State. Data Access as a Dependency PlayerView isPlaying: Bool. Data

API

Page 76: Data Flow Through SwiftUI · 2019-11-07 · Tools for Data Flow Property @Binding BindableObject @Environment @State. Data Access as a Dependency PlayerView isPlaying: Bool. Data

public struct Toggle<Label> : View { public init( isOn: Binding<Bool>, label: () -> Label ) }

public struct TextField : View { init( _ text: Binding<String> ) }

public struct Slider : View { public init<V : BinaryFloatingPoint>( value: Binding<V> ) }

API

Page 77: Data Flow Through SwiftUI · 2019-11-07 · Tools for Data Flow Property @Binding BindableObject @Environment @State. Data Access as a Dependency PlayerView isPlaying: Bool. Data

Views are for Data

Layout Visual Effects Navigation

Gestures Drawing Animations

Page 78: Data Flow Through SwiftUI · 2019-11-07 · Tools for Data Flow Property @Binding BindableObject @Environment @State. Data Access as a Dependency PlayerView isPlaying: Bool. Data

// Animated Changes

struct PlayButton : View { @Binding var isPlaying: Bool var body: some View { Button(action: { self.isPlaying.toggle() }) { Image(systemName: isPlaying ? "pause.circle" : "play.circle") } } }

Page 79: Data Flow Through SwiftUI · 2019-11-07 · Tools for Data Flow Property @Binding BindableObject @Environment @State. Data Access as a Dependency PlayerView isPlaying: Bool. Data

// Animated Changes

struct PlayButton : View { @Binding var isPlaying: Bool var body: some View { Button(action: { withAnimation { self.isPlaying.toggle() } }) { Image(systemName: isPlaying ? "pause.circle" : "play.circle") } } }

Page 80: Data Flow Through SwiftUI · 2019-11-07 · Tools for Data Flow Property @Binding BindableObject @Environment @State. Data Access as a Dependency PlayerView isPlaying: Bool. Data

// Animated Changes

struct PlayButton : View { @Binding var isPlaying: Bool var body: some View { Button(action: { withAnimation { self.isPlaying.toggle() } }) { Image(systemName: isPlaying ? "pause.circle" : "play.circle") } } }

Page 81: Data Flow Through SwiftUI · 2019-11-07 · Tools for Data Flow Property @Binding BindableObject @Environment @State. Data Access as a Dependency PlayerView isPlaying: Bool. Data

Raj Ramamurthy, SwiftUI Engineer

•Working With External Data

Page 82: Data Flow Through SwiftUI · 2019-11-07 · Tools for Data Flow Property @Binding BindableObject @Environment @State. Data Access as a Dependency PlayerView isPlaying: Bool. Data

Tools for Data Flow

@Binding

BindableObject

@Environment

@State

Property

Page 83: Data Flow Through SwiftUI · 2019-11-07 · Tools for Data Flow Property @Binding BindableObject @Environment @State. Data Access as a Dependency PlayerView isPlaying: Bool. Data

!

SwiftUI

Page 84: Data Flow Through SwiftUI · 2019-11-07 · Tools for Data Flow Property @Binding BindableObject @Environment @State. Data Access as a Dependency PlayerView isPlaying: Bool. Data

!User Interaction

SwiftUI

Action

State

Mutation

View

Updates

Render

Page 85: Data Flow Through SwiftUI · 2019-11-07 · Tools for Data Flow Property @Binding BindableObject @Environment @State. Data Access as a Dependency PlayerView isPlaying: Bool. Data

User Interaction

SwiftUI

Action

State

Mutation

View

Updates

Render

!🔔⏰

Page 86: Data Flow Through SwiftUI · 2019-11-07 · Tools for Data Flow Property @Binding BindableObject @Environment @State. Data Access as a Dependency PlayerView isPlaying: Bool. Data

User Interaction

SwiftUI

Action

State

Mutation

View

Updates

Render

!🔔⏰

Publisher

Page 87: Data Flow Through SwiftUI · 2019-11-07 · Tools for Data Flow Property @Binding BindableObject @Environment @State. Data Access as a Dependency PlayerView isPlaying: Bool. Data

Combine Publisher

Single abstraction

Main thread: use .receive(on:)

Introducing Combine and Advances in Foundation Thursday, 10:00

Combine in Practice Thursday, 2:00

Page 88: Data Flow Through SwiftUI · 2019-11-07 · Tools for Data Flow Property @Binding BindableObject @Environment @State. Data Access as a Dependency PlayerView isPlaying: Bool. Data

struct PlayerView : View { let episode: Episode @State private var isPlaying: Bool = true @State private var currentTime: TimeInterval = 0.0

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

PlayButton(isPlaying: $isPlaying)

Text("\(currentTime, formatter: currentTimeFormatter)") } } }

Page 89: Data Flow Through SwiftUI · 2019-11-07 · Tools for Data Flow Property @Binding BindableObject @Environment @State. Data Access as a Dependency PlayerView isPlaying: Bool. Data

struct PlayerView : View { let episode: Episode @State private var isPlaying: Bool = true @State private var currentTime: TimeInterval = 0.0

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

PlayButton(isPlaying: $isPlaying)

Text("\(currentTime, formatter: currentTimeFormatter)") } } }

Page 90: Data Flow Through SwiftUI · 2019-11-07 · Tools for Data Flow Property @Binding BindableObject @Environment @State. Data Access as a Dependency PlayerView isPlaying: Bool. Data

struct PlayerView : View { let episode: Episode @State private var isPlaying: Bool = true @State private var currentTime: TimeInterval = 0.0

var body: some View { VStack { // … Text("\(playhead, formatter: currentTimeFormatter)") } .onReceive(PodcastPlayer.currentTimePublisher) { newCurrentTime in self.currentTime = newCurrentTime } } }

Page 91: Data Flow Through SwiftUI · 2019-11-07 · Tools for Data Flow Property @Binding BindableObject @Environment @State. Data Access as a Dependency PlayerView isPlaying: Bool. Data

struct PlayerView : View { let episode: Episode @State private var isPlaying: Bool = true @State private var currentTime: TimeInterval = 0.0

var body: some View { VStack { // … Text("\(playhead, formatter: currentTimeFormatter)") } .onReceive(PodcastPlayer.currentTimePublisher) { newCurrentTime in self.currentTime = newCurrentTime } } }

Page 92: Data Flow Through SwiftUI · 2019-11-07 · Tools for Data Flow Property @Binding BindableObject @Environment @State. Data Access as a Dependency PlayerView isPlaying: Bool. Data

BindableObject Protocol

External

Reference type

Great for the model you already have

Page 93: Data Flow Through SwiftUI · 2019-11-07 · Tools for Data Flow Property @Binding BindableObject @Environment @State. Data Access as a Dependency PlayerView isPlaying: Bool. Data

class PodcastPlayerStore { var currentTime: TimeInterval var isPlaying: Bool var currentEpisode: Episode

func advance() { ... } func skipForward() { ... } func skipBackward() { ... } }

Page 94: Data Flow Through SwiftUI · 2019-11-07 · Tools for Data Flow Property @Binding BindableObject @Environment @State. Data Access as a Dependency PlayerView isPlaying: Bool. Data

class PodcastPlayerStore : BindableObject {

var didChange = PassthroughSubject<Void, Never>() // …

func advance() { currentEpisode = nextEpisode currentTime = 0.0 // Notify subscribers that the player changed didChange.send() } }

Page 95: Data Flow Through SwiftUI · 2019-11-07 · Tools for Data Flow Property @Binding BindableObject @Environment @State. Data Access as a Dependency PlayerView isPlaying: Bool. Data

class PodcastPlayerStore : BindableObject {

var didChange = PassthroughSubject<Void, Never>() // …

func advance() { currentEpisode = nextEpisode currentTime = 0.0 // Notify subscribers that the player changed didChange.send() } }

Page 96: Data Flow Through SwiftUI · 2019-11-07 · Tools for Data Flow Property @Binding BindableObject @Environment @State. Data Access as a Dependency PlayerView isPlaying: Bool. Data

Creating Dependencies on BindableObject

ViewModel

Page 97: Data Flow Through SwiftUI · 2019-11-07 · Tools for Data Flow Property @Binding BindableObject @Environment @State. Data Access as a Dependency PlayerView isPlaying: Bool. Data

Creating Dependencies on BindableObject

ViewModel

@ObjectBinding

Page 98: Data Flow Through SwiftUI · 2019-11-07 · Tools for Data Flow Property @Binding BindableObject @Environment @State. Data Access as a Dependency PlayerView isPlaying: Bool. Data

Creating Dependencies on BindableObject

ViewModel

@ObjectBinding

struct MyView :aView {a @ObjectBinding var model: MyModelObject ... }a

MyView(model: modelInstance)

Page 99: Data Flow Through SwiftUI · 2019-11-07 · Tools for Data Flow Property @Binding BindableObject @Environment @State. Data Access as a Dependency PlayerView isPlaying: Bool. Data

Creating Dependencies on BindableObject

ViewModel

@ObjectBinding

struct MyView :aView {a @ObjectBinding var model: MyModelObject ... }a

MyView(model: modelInstance)

Page 100: Data Flow Through SwiftUI · 2019-11-07 · Tools for Data Flow Property @Binding BindableObject @Environment @State. Data Access as a Dependency PlayerView isPlaying: Bool. Data

Creating Dependencies on BindableObject

View

@ObjectBinding

Model

struct MyView :aView {a @ObjectBinding var model: MyModelObject ... }a

MyView(model: modelInstance)

Page 101: Data Flow Through SwiftUI · 2019-11-07 · Tools for Data Flow Property @Binding BindableObject @Environment @State. Data Access as a Dependency PlayerView isPlaying: Bool. Data

Creating Dependencies on BindableObject

View

@ObjectBinding

Model

struct MyView :aView {a @ObjectBinding var model: MyModelObject ... }a

MyView(model: modelInstance)

Page 102: Data Flow Through SwiftUI · 2019-11-07 · Tools for Data Flow Property @Binding BindableObject @Environment @State. Data Access as a Dependency PlayerView isPlaying: Bool. Data

Creating Dependencies on BindableObject

View

@ObjectBinding

Model

Pass directly with @ObjectBinding

Automatic dependency tracking

struct MyView :aView {a @ObjectBinding var model: MyModelObject ... }a

MyView(model: modelInstance)

Page 103: Data Flow Through SwiftUI · 2019-11-07 · Tools for Data Flow Property @Binding BindableObject @Environment @State. Data Access as a Dependency PlayerView isPlaying: Bool. Data

Creating Dependencies Indirectly

View

View

View

Model

Page 104: Data Flow Through SwiftUI · 2019-11-07 · Tools for Data Flow Property @Binding BindableObject @Environment @State. Data Access as a Dependency PlayerView isPlaying: Bool. Data

Creating Dependencies Indirectly

View

View

View

Environment

Environment

Environment

Model

Page 105: Data Flow Through SwiftUI · 2019-11-07 · Tools for Data Flow Property @Binding BindableObject @Environment @State. Data Access as a Dependency PlayerView isPlaying: Bool. Data

Creating Dependencies Indirectly

Environment

Environment

Environment

.environmentObject()

Model

View

View

View

Page 106: Data Flow Through SwiftUI · 2019-11-07 · Tools for Data Flow Property @Binding BindableObject @Environment @State. Data Access as a Dependency PlayerView isPlaying: Bool. Data

Creating Dependencies Indirectly

Environment

Environment

Environment

@EnvironmentObject

.environmentObject()

Model

View

View

View

Page 107: Data Flow Through SwiftUI · 2019-11-07 · Tools for Data Flow Property @Binding BindableObject @Environment @State. Data Access as a Dependency PlayerView isPlaying: Bool. Data

Creating Dependencies Indirectly

Environment

Environment

Environment

.environmentObject()

Model

@EnvironmentObject

View

View

View@EnvironmentObject

Page 108: Data Flow Through SwiftUI · 2019-11-07 · Tools for Data Flow Property @Binding BindableObject @Environment @State. Data Access as a Dependency PlayerView isPlaying: Bool. Data

Creating Dependencies Indirectly

Environment

Environment

Environment

.environmentObject()

Model

@EnvironmentObject

View

View

View@EnvironmentObject

Page 109: Data Flow Through SwiftUI · 2019-11-07 · Tools for Data Flow Property @Binding BindableObject @Environment @State. Data Access as a Dependency PlayerView isPlaying: Bool. Data

struct PlayerView : View { @EnvironmentObject var player: PodcastPlayerStore var body: some View { VStack { Text(player.currentEpisode.title) .foregroundColor(isPlaying ? .white : .gray) Text(player.currentEpisode.showTitle) .font(.caption).foregroundColor(.gray) PlayButton(isPlaying: $player.isPlaying) Text("\(player.currentTime, formatter: playheadTimeFormatter)") } } }

Page 110: Data Flow Through SwiftUI · 2019-11-07 · Tools for Data Flow Property @Binding BindableObject @Environment @State. Data Access as a Dependency PlayerView isPlaying: Bool. Data

struct PlayerView : View { @EnvironmentObject var player: PodcastPlayerStore var body: some View { VStack { Text(player.currentEpisode.title) .foregroundColor(isPlaying ? .white : .gray) Text(player.currentEpisode.showTitle) .font(.caption).foregroundColor(.gray) PlayButton(isPlaying: $player.isPlaying) Text("\(player.currentTime, formatter: playheadTimeFormatter)") } } }

Page 111: Data Flow Through SwiftUI · 2019-11-07 · Tools for Data Flow Property @Binding BindableObject @Environment @State. Data Access as a Dependency PlayerView isPlaying: Bool. Data

@ObjectBinding

View View View View View View

Model

Page 112: Data Flow Through SwiftUI · 2019-11-07 · Tools for Data Flow Property @Binding BindableObject @Environment @State. Data Access as a Dependency PlayerView isPlaying: Bool. Data

@ObjectBinding

View View View View View View

Model

Page 113: Data Flow Through SwiftUI · 2019-11-07 · Tools for Data Flow Property @Binding BindableObject @Environment @State. Data Access as a Dependency PlayerView isPlaying: Bool. Data

@EnvironmentObject

View View View View View View

Model Environment

Page 114: Data Flow Through SwiftUI · 2019-11-07 · Tools for Data Flow Property @Binding BindableObject @Environment @State. Data Access as a Dependency PlayerView isPlaying: Bool. Data

@EnvironmentObject

View View View View View View

Model Environment

Page 115: Data Flow Through SwiftUI · 2019-11-07 · Tools for Data Flow Property @Binding BindableObject @Environment @State. Data Access as a Dependency PlayerView isPlaying: Bool. Data

Environment

•Data applicable to an entire hierarchy •Convenience for indirection •Accent color, right-to-left, and more

Page 116: Data Flow Through SwiftUI · 2019-11-07 · Tools for Data Flow Property @Binding BindableObject @Environment @State. Data Access as a Dependency PlayerView isPlaying: Bool. Data

Sources of Truth

@State BindableObject

View-local Value

Framework Managed

External Reference

Developer Managed

Page 117: Data Flow Through SwiftUI · 2019-11-07 · Tools for Data Flow Property @Binding BindableObject @Environment @State. Data Access as a Dependency PlayerView isPlaying: Bool. Data

Building Reusable Components

Read-only: Swift property, Environment

Read-write: @Binding

Prefer immutable access

Page 118: Data Flow Through SwiftUI · 2019-11-07 · Tools for Data Flow Property @Binding BindableObject @Environment @State. Data Access as a Dependency PlayerView isPlaying: Bool. Data

@Binding

First class reference to data

Great for reusability

Use $ to derive from source

@State @ObjectBinding

@Binding

@Binding

Page 119: Data Flow Through SwiftUI · 2019-11-07 · Tools for Data Flow Property @Binding BindableObject @Environment @State. Data Access as a Dependency PlayerView isPlaying: Bool. Data

Using State Effectively

Limit use if possible

Use derived Binding or value

Prefer BindableObject for persistence

Example: Button highlighting

Page 120: Data Flow Through SwiftUI · 2019-11-07 · Tools for Data Flow Property @Binding BindableObject @Environment @State. Data Access as a Dependency PlayerView isPlaying: Bool. Data

Next Steps

Minimize sources of truth

Understand your data

Build a great app!

Page 121: Data Flow Through SwiftUI · 2019-11-07 · Tools for Data Flow Property @Binding BindableObject @Environment @State. Data Access as a Dependency PlayerView isPlaying: Bool. Data

More Informationdeveloper.apple.com/wwdc19/226

SwiftUI Essentials WWDC 2019

Integrating SwiftUI Thursday, 3:00

Building Custom Views with SwiftUI Friday, 9:00

Page 122: Data Flow Through SwiftUI · 2019-11-07 · Tools for Data Flow Property @Binding BindableObject @Environment @State. Data Access as a Dependency PlayerView isPlaying: Bool. Data