Slide 1

Slide 1 text

Swi$ Zoomin' #8 Actor ϋϯζΦϯ

Slide 2

Slide 2 text

Actor ͱ͸

Slide 3

Slide 3 text

ɾɾɾͷલʹ

Slide 4

Slide 4 text

Actor ͸ async/await Λଟ༻͢Δ

Slide 5

Slide 5 text

async/await ͷ؆୯ͳ෮श

Slide 6

Slide 6 text

ίʔϧόοΫʹΑΔඇಉظؔ਺ // એݴ func downloadData(from url: URL, completion: @escaping (Data) -> Void) // ར༻ downloadData(from: url) { data in // data Λ࢖͏ॲཧ }

Slide 7

Slide 7 text

async/await ʹΑΔඇಉظؔ਺ // એݴ func downloadData(from url: URL) async -> Data // ར༻ let data = await downloadData(from: url) // data Λ࢖͏ॲཧ

Slide 8

Slide 8 text

ίʔϧόοΫʹΑΔඇಉظؔ਺ // એݴ func downloadData(from url: URL, completion: @escaping (Result) -> Void) // ར༻ downloadData(from: url) { result in do { let data = try result.get() // data Λ࢖͏ॲཧ } catch { /* ΤϥʔϋϯυϦϯά */ } }

Slide 9

Slide 9 text

async/await ʹΑΔඇಉظؔ਺ // એݴ func downloadData(from url: URL) async throws -> Data // ར༻ do { let data = try await downloadData(from: url) // data Λ࢖͏ॲཧ } catch { /* ΤϥʔϋϯυϦϯά */ }

Slide 10

Slide 10 text

࿅श໰୊༻ϦϙδτϦ h"ps:/ /github.com/koher/swi4-zoomin-8

Slide 11

Slide 11 text

Q1: downloadData ίʔϧόοΫͰ݁ՌΛฦ͢ downloadData ؔ਺͕ Download.swi, ʹ࣮૷͞Ε͍ͯ·͢ɻ async/await Λར༻͠ ͯɺ໭Γ஋Ͱ݁ՌΛฦ͢ downloadData ؔ਺Λ࣮૷ͯ͠Լ͞ ͍ɻ ! iOS 15 ͔Β URLSession ʹ௥Ճ͞Εͨ࣍ͷϝιου͕໾ʹཱ ͪ·͢ɻ1 func data(from url: URL) async throws -> (Data, URLResponse) 1 h$ps:/ /developer.apple.com/documenta6on/founda6on/urlsession/3767353-data

Slide 12

Slide 12 text

Q1: ղ౴ྫ

Slide 13

Slide 13 text

async ؔ਺͸ async ؔ਺ͷதͰ͔͠ݺͼग़ͤͳ͍ func foo() async func bar() async { await foo() // ✅ OK }

Slide 14

Slide 14 text

async ؔ਺͸ async ؔ਺ͷதͰ͔͠ݺͼग़ͤͳ͍ func foo() async func bar() { await foo() // ⛔ NG }

Slide 15

Slide 15 text

async ؔ਺͸ async ؔ਺ͷதͰ͔͠ݺͼग़ͤͳ͍ func foo() async func bar() async { await foo() // ✅ OK } func baz() async { await bar() // ✅ OK } ...

Slide 16

Slide 16 text

async ؔ਺Λ࠷ॳʹݺͼग़͢ͱ͖͸ʁ

Slide 17

Slide 17 text

ಉظؔ਺͔Βͷ async ؔ਺ͷݺͼग़͠ override func viewDidAppear(_ animated: Bool) { super.viewDidAppear(animated) await foo() // ⛔ NG }

Slide 18

Slide 18 text

ಉظؔ਺͔Βͷ async ؔ਺ͷݺͼग़͠ override func viewDidAppear(_ animated: Bool) { super.viewDidAppear(animated) Task { await foo() // ✅ OK } }

Slide 19

Slide 19 text

ಉظؔ਺͔Βͷ async ؔ਺ͷݺͼग़͠ override func viewDidAppear(_ animated: Bool) { super.viewDidAppear(animated) Task(operation: { await foo() // ✅ OK }) }

Slide 20

Slide 20 text

Task.init 2 @discardableResult init( priority: TaskPriority? = nil, operation: @escaping @Sendable () async throws -> Success ) 2 h$ps:/ /developer.apple.com/documenta6on/swi9/task/3856790-init

Slide 21

Slide 21 text

Q2: UserViewController.viewDidAppear UserViewController ͸ User ͷ৘ใΛऔಘͯ͠දࣔ͢Δ View Controller Ͱ͢ɻ viewDidAppear ͷதͰ downloadData ؔ਺Λ ࢖͍ɺ User ͱΞΠίϯΛऔಘͯ͠දࣔ͠·͢ɻ ͜ΕΛɺ async/await Ͱ࣮૷͞Εͨ downloadData ؔ਺Λར ༻ͯ͠࠶࣮૷ͯ͠Լ͍͞ɻ

Slide 22

Slide 22 text

Q2: ղ౴ྫ

Slide 23

Slide 23 text

Actor ͱ͸

Slide 24

Slide 24 text

Actor ͸ΫϥεʹࣅͨࢀরܕͰɺσʔλڝ߹ Λ๷͙ͨΊͷϘΠϥʔϓϨʔτ͕ෆཁʹͳ Δɻ ͦͷͨΊɺίʔυ͕؆͔ܿͭ҆શʹͳΔɻ

Slide 25

Slide 25 text

σʔλڝ߹ͱ͸

Slide 26

Slide 26 text

Χ΢ϯλʔͷσʔλڝ߹ final class Counter { private var count: Int = 0 func increment() -> Int { count += 1 return count } }

Slide 27

Slide 27 text

Χ΢ϯλʔͷσʔλڝ߹ let counter: Counter = .init() Task { print(counter.increment()) // ? } Task { print(counter.increment()) // ? }

Slide 28

Slide 28 text

Χ΢ϯλʔͷσʔλڝ߹ let counter: Counter = .init() Task { print(counter.increment()) // 1 } Task { print(counter.increment()) // 2 }

Slide 29

Slide 29 text

Χ΢ϯλʔͷσʔλڝ߹ let counter: Counter = .init() Task { print(counter.increment()) // 2 } Task { print(counter.increment()) // 1 }

Slide 30

Slide 30 text

Χ΢ϯλʔͷσʔλڝ߹ let counter: Counter = .init() Task { print(counter.increment()) // 2 } Task { print(counter.increment()) // 2 }

Slide 31

Slide 31 text

Χ΢ϯλʔͷσʔλڝ߹ final class Counter { private var count: Int = 0 func increment() -> Int { count += 1 Thread.sleep(forTimeInterval: 1.0) return count } }

Slide 32

Slide 32 text

Χ΢ϯλʔͷσʔλڝ߹ let counter: Counter = .init() Task { print(counter.increment()) // 1 } Task { print(counter.increment()) // 1 }

Slide 33

Slide 33 text

final class Counter { private var count: Int = 0 func increment() -> Int { let count = self.count Thread.sleep(forTimeInterval: 1.0) self.count = count + 1 return self.count } }

Slide 34

Slide 34 text

σʔλڝ߹΁ͷରԠํ๏ • ϩοΫ • ʢ DispatchQueue ͷʣγϦΞϧΩϡʔ

Slide 35

Slide 35 text

γϦΞϧΩϡʔʹΑΔσʔλڝ߹ͷղফ final class Counter { private let queue: DispatchQueue = .init(label: "Counter") private var count: Int = 0 func increment(completion: @escaping (Int) -> Void) { queue.async { [self] in count += 1 completion(count) } } }

Slide 36

Slide 36 text

γϦΞϧΩϡʔʹΑΔσʔλڝ߹ͷղফ let counter: Counter = .init() Task { counter.increment { print($0) } // 1 } Task { counter.increment { print($0) } // 2 }

Slide 37

Slide 37 text

γϦΞϧΩϡʔʹΑΔσʔλڝ߹ͷղফ final class Counter { private let queue: DispatchQueue = .init(label: "Counter") private var count: Int = 0 func increment(completion: @escaping (Int) -> Void) { queue.async { [self] in count += 1 completion(count) } } }

Slide 38

Slide 38 text

σʔλڝ߹΁ͷରԠํ๏ • ϩοΫ • ʢ DispatchQueue ͷʣγϦΞϧΩϡʔ • Actor

Slide 39

Slide 39 text

Actor ʹΑΔσʔλڝ߹ͷղফ final class Counter { private var count: Int = 0 func increment() -> Int { count += 1 return count } }

Slide 40

Slide 40 text

Actor ʹΑΔσʔλڝ߹ͷղফ actor Counter { private var count: Int = 0 func increment() -> Int { count += 1 return count } }

Slide 41

Slide 41 text

Actor ʹΑΔσʔλڝ߹ͷղফ let counter: Counter = .init() Task { print(await counter.increment()) } Task { print(await counter.increment()) }

Slide 42

Slide 42 text

Q3: BankAccount.deposit ࣍ͷΑ͏ͳ BankAccount ΫϥεΛ࣮૷͠ɺฒߦʹ༬ۚ͢Δ͜ͱ Ͱσʔλڝ߹͕ൃੜ͢Δ͜ͱΛ֬ೝͯ͠Լ͍͞ɻͦͷޙɺ BankAccount Λ actor ʹมߋ͠ɺσʔλڝ߹͕๷ࢭ͞ΕΔ͜ͱ Λ֬ೝͯ͠Լ͍͞ɻ final class BankAccount { // ۜߦޱ࠲ var balance: Int = 0 // ༬ۚ࢒ߴ func deposit(_ amount: Int) -> Int // ೖۚʢ໭Γ஋͸࢒ߴʣ }

Slide 43

Slide 43 text

Q3: ղ౴ྫ

Slide 44

Slide 44 text

Actor ͷಉҰΠϯελϯε಺Ͱͷϝιουݺͼग़͠ actor A { func foo() { ... } func bar() { foo() // ಉظ } } await foo() // ඇಉظ

Slide 45

Slide 45 text

Q4: BankAccount.getInterest BankAccount ʹ getInterest ϝιουΛ࣮૷ͯ͠Լ͍͞ɻ getInterest ϝιου͸࣍ͷΑ͏ͳγάωνϟΛ࣋ͪɺҾ਺Ͱ ར཰Λड͚औΓɺͦΕΛݩʹརଉΛܭࢉͯ͠༬ۚ࢒ߴΛมಈͤ͞ ্ͨͰɺ৽͍͠༬ۚ࢒ߴΛฦ͢΋ͷͱ͠·͢ɻͨͩ͠ɺ༬ۚ࢒ߴ ͷมಈʹ͸ deposit ϝιουΛར༻͢Δ΋ͷͱ͠·͢ɻ func getInterest(with rate: Double) -> Int

Slide 46

Slide 46 text

Q4: ղ౴ྫ

Slide 47

Slide 47 text

Actor ͷΠϯελϯεؒͰͷϝιουݺͼग़͠ actor A { func foo() { ... } } actor B { func bar(a: A) async { await a.foo() // ඇಉظ } }

Slide 48

Slide 48 text

Actor ͷΠϯελϯεؒͰͷϝιουݺͼग़͠ actor A { func foo() { ... } func bar(a: A) async { foo() // ಉظ await a.foo() // ඇಉظ } }

Slide 49

Slide 49 text

Actor ͷΠϯελϯεؒͰͷϝιουݺͼग़͠ actor A { func foo() { ... } func bar(a: A) async { self.foo() // ಉظ await a.foo() // ඇಉظ } }

Slide 50

Slide 50 text

Actor ͷΠϯελϯεؒͰͷϝιουݺͼग़͠ actor A { func foo() { ... } func bar(a: A) async { foo() // ಉظ await a.foo() // ඇಉظ } }

Slide 51

Slide 51 text

Q5: BankAccount.transfer BankAccount ʹ࣍ͷೋͭͷϝιουΛ௥Ճͯ͠Լ͍͞ɻ • ޱ࠲͔Βग़ۚ͢ΔͨΊͷ withdraw ϝιου • ޱ࠲ؒͰૹۚ͢ΔͨΊͷ transfer ϝιου // ࢒ߴ͕଍Γͳ͍৔߹͸ΤϥʔΛ throw func withdraw(_ amount: Int) throws -> Int // ໭Γ஋͸࢒ߴ func transfer(_ amount: Int, to account: BankAccount) async throws

Slide 52

Slide 52 text

Q5: ղ౴ྫ

Slide 53

Slide 53 text

Sendable

Slide 54

Slide 54 text

Sendable 3 actor ڥքΛ௒͑ͯ΍ΓͱΓͰ͖Δ͜ͱΛද͢ϓϩτίϧ 3 h$ps:/ /github.com/apple/swi6-evolu9on/blob/main/proposals/0302-concurrent-value-and-concurrent- closures.md

Slide 55

Slide 55 text

final class User { let id: ID var name: String var age: Int ... }

Slide 56

Slide 56 text

actor A { let user: User = ... } let a: A = ... Task { let user = await a.user user.age += 1 // ⛔ } Actor ͷΩϡʔͷ֎Ͱ Actor ͷ಺෦ঢ়ଶΛมߋͰ͖ͯ͠·͏

Slide 57

Slide 57 text

final class User: Sendable { let id: ID var name: String var age: Int ... } ⛔ ࢀরܕͰ var ϓϩύςΟΛ࣋ͭͷͰίϯύΠϧΤϥʔ

Slide 58

Slide 58 text

struct User { let id: ID var name: String var age: Int ... } public Ͱͳ͍஋ܕ͸҉໧తʹద߹4 4 h$ps:/ /github.com/apple/swi6-evolu9on/blob/main/proposals/0302-concurrent-value-and-concurrent- closures.md#implicit-structenum-conformance-to-sendable

Slide 59

Slide 59 text

public struct User: Sendable { public let id: ID public var name: String public var age: Int ... } public ͩͱ໌ࣔతʹద߹ͤ͞Δඞཁ͋Γ

Slide 60

Slide 60 text

struct User: Sendable { let id: ID var name: NSString var age: Int ... } ⛔ Sendable Ͱͳ͍ϝϯόʔΛ࣋ͭͷͰίϯύΠϧΤϥʔ

Slide 61

Slide 61 text

final class User: Sendable { let id: ID let name: String let age: Int ... } ✅ ࢀরܕͰ΋ΠϛϡʔλϒϧͳΒ OK

Slide 62

Slide 62 text

final class User: Sendable { let id: ID let firstName: String let familyName: String let age: Int var name: String { "\(firstName) \(familyName)" } ... } ✅ Computed Property Λ͍࣋ͬͯͯ΋ΠϛϡʔλϒϧͳͷͰ OK

Slide 63

Slide 63 text

final class User: Sendable { let id: ID let firstName: String let familyName: String let age: Int private var _name: String? // var name: String { if _name == nil { _name = "\(firstName) \(familyName)" } return _name! } ... }

Slide 64

Slide 64 text

final class User: @unchecked Sendable { let id: ID let firstName: String let familyName: String let age: Int private var _name: String? // var name: String { if _name == nil { _name = "\(firstName) \(familyName)" } return _name! } ... }

Slide 65

Slide 65 text

actor Counter { private var count: Int = 0 func increment() -> Int { count += 1 return count } } actor ͸҉໧తʹ Sendable ʹద߹

Slide 66

Slide 66 text

ϓϩτίϧʹద߹ͤ͞ΒΕͳ͍৔߹͸ʁ

Slide 67

Slide 67 text

actor Foo { func bar(_ f: (String) -> Int) { // // ... } }

Slide 68

Slide 68 text

actor Foo { func bar(_ f: @Sendable (String) -> Int) { // // ... } } Ϋϩʔδϟ͸ϓϩτίϧʹద߹Ͱ͖ͳ͍ͷͰ @Sendable Λ࢖͏

Slide 69

Slide 69 text

final class User { var name: String ... } let user: User = ... Task { let name = user.name // } @Sendable Ϋϩʔδϟ͸ Sendable ͳ஋͔͠ΩϟϓνϟͰ͖ͳ ͍ʢ Task.init ʹ౉͢Ϋϩʔδϟ͸ @Sendable ʣ

Slide 70

Slide 70 text

var a = 42 Task { print(a) // ⛔ } @Sendable Ϋϩʔδϟ͸ม਺ΛΩϟϓνϟͰ͖ͳ͍

Slide 71

Slide 71 text

var a = 42 Task { [a] in print(a) // ✅ } by-value Ωϟϓνϟ͸Մೳ

Slide 72

Slide 72 text

No content

Slide 73

Slide 73 text

Actor-isolated Context ͷҾܧ͗

Slide 74

Slide 74 text

@nonescaping, non-@Sendable ʢ context ΛҾ͖ܧ͙ʣ actor A { func foo(values: [Int]) { // A values.forEach { value in // A } } }

Slide 75

Slide 75 text

@escaping, non-@Sendableʢ context ΛҾ͖ܧ͙ʣ actor A { func foo(value: Int) { // A let square: (Int) -> Int = { // @escaping // A $0 * $0 } print(square(value)) print(square(square(value))) } }

Slide 76

Slide 76 text

@Sendable ʢ context ΛҾ͖ܧ͕ͳ͍ʣ actor A { func foo() { // A let foo: Foo = .init() // Foo: Sendable DispatchQueue.global().async { [foo] in // @Sendable // not A foo.value = 2 } foo.value = 3 print(foo.value) } } ※ͨͩ͠ɺ Swi% 5.5 ݱࡏ͸ @Sendable Ͱͳ͍

Slide 77

Slide 77 text

Task.initʢ context ΛҾ͖ܧ͙ʣ actor A { func foo() { // A Task { // @Sendable // A } } }

Slide 78

Slide 78 text

@_inheritActorContext extension Task where Failure == Never { ... @discardableResult @_alwaysEmitIntoClient public init( priority: TaskPriority? = nil, @_inheritActorContext @_implicitSelfCapture operation: __owned @Sendable @escaping () async -> Success ) { ... } } 10 h%ps:/ /github.com/apple/swi7/blob/main/stdlib/public/Concurrency/Task.swi7

Slide 79

Slide 79 text

Task.initʢ context ΛҾ͖ܧ͙ʣ actor A { func foo() { // A Task { // @Sendable // A } } }

Slide 80

Slide 80 text

Task.detachedʢ context ΛҾ͖ܧ͕ͳ͍ʣ actor A { func foo() { // A Task.detached { // @Sendable // not A } } }

Slide 81

Slide 81 text

Actor-isolated Context ͷҾܧ͗ͷؔ͢Δ swi2-developers-japan Ͱͷ΍ΓͱΓ11 11 h$ps:/ /discord.com/channels/291054398077927425/291054454793306112/890858321693769748

Slide 82

Slide 82 text

UserViewController

Slide 83

Slide 83 text

No content

Slide 84

Slide 84 text

override func viewDidAppear(_ animated: Bool) { super.viewDidAppear(animated) Task { do { // User ͷ JSON ͷऔಘ let url: URL = ... let data = try await downloadData(from: url) ... // View ΁ͷ൓ө iconImageView.image = iconImage } catch { // ΤϥʔϋϯυϦϯά print(error) } } }

Slide 85

Slide 85 text

View Controller ʹϩδοΫΛॻ͖ͨ͘ͳ͍

Slide 86

Slide 86 text

ViewModel తͳΫϥεΛಋೖ

Slide 87

Slide 87 text

UserViewState final class UserViewState { let id: User.ID @Published private(set) var user: User? @Published private(set) var iconImage: UIImage? init(id: User.ID) { self.id = id } }

Slide 88

Slide 88 text

Q6: UserViewState UserViewState ʹ loadUser ϝιουΛ௥Ճ͠ɺϢʔβʔ͓Α ͼϢʔβʔΞΠίϯΛऔಘ͢ΔίʔυΛ UserViewController ͔Β෼཭ͯ͠Լ͍͞ɻ UserViewController ʹ͸ UserViewState ܕͷ state ϓϩύςΟΛ࣋ͨͤɺ state ͷঢ় ଶΛ View ʹ൓ө͢ΔΑ͏ʹͯ͠Լ͍͞ɻͳ͓ɺ͜ͷ໰୊͸ Actor ʹؔ܎͋Γ·ͤΜɻ ! state.user Ͱ͸ͳ͘ state.$user ͱॻ͘͜ͱͰɺ user Λ Publisher ͱͯ͠औಘ͢Δ͜ͱ͕Ͱ͖·͢ɻ

Slide 89

Slide 89 text

Q6: ղ౴ྫ

Slide 90

Slide 90 text

loadUser Λฒߦʹݺͼग़ͯ͠΋େৎ෉͔ʁ

Slide 91

Slide 91 text

loadUser Ͱى͜ΓಘΔσʔλڝ߹ let data = try await downloadData(from: url) let user = try JSONDecoder().decode(User.self, from: data) self.user = user // ͕͜͜ಉ࣌ʹ࣮ߦ͞ΕΔͱʁ

Slide 92

Slide 92 text

UserViewState Λ actor ʹ͍ͨ͠

Slide 93

Slide 93 text

Q7: actor UserViewState UserViewState Λ Actor ʹͯ͠Լ͍͞ɻ

Slide 94

Slide 94 text

Q7: ղ౴ྫ

Slide 95

Slide 95 text

Swi$ Concurrency Λ࢖ͬͯ Publisher ΛߪಡͰ͖Δ

Slide 96

Slide 96 text

Publisher.values 5 for await value in publisher.values { ... } 5 h$ps:/ /developer.apple.com/documenta6on/combine/publisher/values-1dm9r

Slide 97

Slide 97 text

AsyncSequence 6 protocol AsyncSequence { associatedtype AsyncIterator: AsyncIteratorProtocol where AsyncIterator.Element == Element associatedtype Element func makeAsyncIterator() -> AsyncIterator } protocol AsyncIteratorProtocol { associatedtype Element mutating func next() async throws -> Element? } 6 h$ps:/ /github.com/apple/swi6-evolu9on/blob/main/proposals/0298-asyncsequence.md

Slide 98

Slide 98 text

Q8: Publisher.values UserViewState ͷ user ΍ iconImage ͷߪಡΛɺ for await Λ࢖͏ܗͰॻ͖׵͑ͯԼ͍͞ɻ

Slide 99

Slide 99 text

Q8: ղ౴ྫ

Slide 100

Slide 100 text

await state ͷ await ͕ᓔಃ͍͠ for await user in await state.$user.values { ... }

Slide 101

Slide 101 text

state ͷΩϡʔ͕ϝΠϯΩϡʔͳΒɾɾɾ

Slide 102

Slide 102 text

ܕΛ௒͑ͯΩϡʔͰอޢ͍ͨ͠

Slide 103

Slide 103 text

Global Actor 7 7 h$ps:/ /github.com/apple/swi6-evolu9on/blob/main/proposals/0316-global-actors.md

Slide 104

Slide 104 text

MainActor 8 8 h$ps:/ /github.com/apple/swi6-evolu9on/blob/main/proposals/0316-global-actors.md#the-main-actor

Slide 105

Slide 105 text

@MainActor @MainActor func foo() { // isolated // ϝΠϯεϨου } @MainActor ͕෇༩͞Εͨؔ਺΍ϝιουɺϓϩύςΟ౳͸ MainActor ʹ actor-isolated

Slide 106

Slide 106 text

@MainActor @MainActor final class Foo { var value: Int = 42 // isolated func a() { // isolated // ϝΠϯεϨου } } @MainActor ͕෇༩͞ΕͨܕͷϝιουɺϓϩύςΟ౳͸ MainActor ʹ actor-isolated

Slide 107

Slide 107 text

Q9: @MainActor UserViewState ʹ @MainActor Λ෇༩ͯ͠ɺ UserViewController ͱͷ΍ΓͱΓΛ MainActor ಺ͷॲཧͱ ͯ͠ѻ͑ΔΑ͏ʹͯ͠Լ͍͞ɻ

Slide 108

Slide 108 text

Q9: ղ౴ྫ

Slide 109

Slide 109 text

ObservableObject

Slide 110

Slide 110 text

UserViewState Λ ObservableObject ʹ final class UserViewState: ObservableObject { ... }

Slide 111

Slide 111 text

UserViewState Λ ObservableObject ʹ • Swi%UI ΁ͷҠߦΛݟਾ͑ͯ • Computed Property ͸ @Published ʹͰ͖ͳ͍

Slide 112

Slide 112 text

UserViewState Λ ObservableObject ʹ • user ΍ iconImage Λݸผʹߪಡ͢ΔͷͰ͸ͳ͘ɺ objectWillChange9 Λߪಡ͢Δ 9 h$ps:/ /developer.apple.com/documenta6on/combine/observableobject/objectwillchange-2oa5v

Slide 113

Slide 113 text

Q10: ObservableObject UserViewState Λ ObservableObject ʹద߹ͤ͞ɺ user, iconImage Λݸผʹߪಡ͢ΔͷͰ͸ͳ͘ɺ objectWillChange Λߪಡͯ͠ View ʹ൓ө͢Δܗʹमਖ਼ͯ͠Լ͍͞ɻ

Slide 114

Slide 114 text

Q10: ղ౴ྫ

Slide 115

Slide 115 text

Q10 Ͱ࣮૷ͨ͠ UserViewState ͸ Swi(UI Ͱ΋ͦͷ··ར༻Մೳ

Slide 116

Slide 116 text

Q11: Swi(UI UserViewController ͱಉ༷ͷݟͨ໨ɾڍಈΛ࣮ݱ͢Δ UserView Λ Swi%UI Ͱ࣮૷ͯ͠Լ͍͞ɻ ! @StateObject Ͱ UserViewState Λอ࣋͠·͢ɻ @StateObject private var state: UserViewState

Slide 117

Slide 117 text

Q11: ղ౴ྫ