Slide 1

Slide 1 text

Copyright © 2024 treastrain / Tanaka RyogaɹAll rights reserved. #iosdc #a ࢖͏ɾ࡞ΔɾଞͷσβΠϯύλʔϯʢΫϩʔδϟɺDelegate ͳͲʣ͔ΒҠߦ͢Δ Mastering AsyncSequence 1 iOSDC Japan 2024 Day 2 #iosdc #a treastrain / Tanaka Ryoga

Slide 2

Slide 2 text

Copyright © 2024 treastrain / Tanaka RyogaɹAll rights reserved. #iosdc #a About me treastrain / Tanaka Ryoga Swift 🦅 / Core NFC 📶 - Japan NFC Reader 💳 / PadDisplay 📺 @treastrain https://tret.jp DeNA Co., Ltd. - iOS App Developer ( April 2021 - Current) 2

Slide 3

Slide 3 text

Copyright © 2024 treastrain / Tanaka RyogaɹAll rights reserved. #iosdc #a My Previous Talks at iOSDC Japan Not a Sequel to Today’s Talk 3

Slide 4

Slide 4 text

Copyright © 2024 treastrain / Tanaka RyogaɹAll rights reserved. #iosdc #a AsyncSequence 4

Slide 5

Slide 5 text

Copyright © 2024 treastrain / Tanaka RyogaɹAll rights reserved. #iosdc #a 5 AsyncSequence | Apple Developer Documentation https://developer.apple.com/documentation/swift/asyncsequence ~ 5.10

Slide 6

Slide 6 text

Copyright © 2024 treastrain / Tanaka RyogaɹAll rights reserved. #iosdc #a 6 AsyncSequence | Apple Developer Documentation https://developer.apple.com/documentation/swift/asyncsequence ~ 5.10

Slide 7

Slide 7 text

Copyright © 2024 treastrain / Tanaka RyogaɹAll rights reserved. #iosdc #a Outline • What is AsyncSequence? • Usage • Adopting AsyncSequence • Swift 6.0 Updates 7

Slide 8

Slide 8 text

Copyright © 2024 treastrain / Tanaka RyogaɹAll rights reserved. #iosdc #a AsyncSequence 8

Slide 9

Slide 9 text

Copyright © 2024 treastrain / Tanaka RyogaɹAll rights reserved. #iosdc #a Sequence 9

Slide 10

Slide 10 text

Copyright © 2024 treastrain / Tanaka RyogaɹAll rights reserved. #iosdc #a 10 Sequence | Apple Developer Documentation https://developer.apple.com/documentation/swift/sequence

Slide 11

Slide 11 text

Copyright © 2024 treastrain / Tanaka RyogaɹAll rights reserved. #iosdc #a Sequence 🙋 11

Slide 12

Slide 12 text

Copyright © 2024 treastrain / Tanaka RyogaɹAll rights reserved. #iosdc #a Conforming Types Sequence Array Dictionary Range / ClosedRange Set String 12 …etc.

Slide 13

Slide 13 text

Copyright © 2024 treastrain / Tanaka RyogaɹAll rights reserved. #iosdc #a for-in Syntax 13 for year in 2016...2024 { print("iOSDC Japan \(year)") } // iOSDC Japan 2016 // iOSDC Japan 2017 // ... // iOSDC Japan 2023 // iOSDC Japan 2024

Slide 14

Slide 14 text

Copyright © 2024 treastrain / Tanaka RyogaɹAll rights reserved. #iosdc #a for-in Syntax with where Clause 14 let string = "DeNA" for character in string where character.isUppercase { print(character) } // D // N // A

Slide 15

Slide 15 text

Copyright © 2024 treastrain / Tanaka RyogaɹAll rights reserved. #iosdc #a Built-in Sequence Implementations 15 let odds = [1, 3, 5, 7, 9] let evens = odds.map { $0 + 1 } print(evens) // [2, 4, 6, 8, 10] let fullName = "Tanaka Ryoga" let initials = fullName.filter(\.isUppercase) print(initials) // TR

Slide 16

Slide 16 text

Copyright © 2024 treastrain / Tanaka RyogaɹAll rights reserved. #iosdc #a Sequence 🙋 16

Slide 17

Slide 17 text

Copyright © 2024 treastrain / Tanaka RyogaɹAll rights reserved. #iosdc #a Sequence 🙋 🙋 17

Slide 18

Slide 18 text

Copyright © 2024 treastrain / Tanaka RyogaɹAll rights reserved. #iosdc #a Sequence 🙋 🙋 🙋 18

Slide 19

Slide 19 text

Copyright © 2024 treastrain / Tanaka RyogaɹAll rights reserved. #iosdc #a Conforming to the Sequence 19 struct Countdown { // ... }

Slide 20

Slide 20 text

Copyright © 2024 treastrain / Tanaka RyogaɹAll rights reserved. #iosdc #a Conforming to the Sequence 20 struct Countdown: Sequence { // ... }

Slide 21

Slide 21 text

Copyright © 2024 treastrain / Tanaka RyogaɹAll rights reserved. #iosdc #a Conforming to the Sequence 21 struct Countdown: Sequence { struct Iterator { // ... } // ... }

Slide 22

Slide 22 text

Copyright © 2024 treastrain / Tanaka RyogaɹAll rights reserved. #iosdc #a Conforming to the Sequence 22 struct Countdown: Sequence { struct Iterator: IteratorProtocol { // ... } // ... }

Slide 23

Slide 23 text

Copyright © 2024 treastrain / Tanaka RyogaɹAll rights reserved. #iosdc #a Conforming to the Sequence 23 struct Countdown: Sequence { struct Iterator: IteratorProtocol { var count: UInt mutating func next() -> UInt? { guard count > 0 else { return nil } defer { count -= 1 } return count } } // ... }

Slide 24

Slide 24 text

Copyright © 2024 treastrain / Tanaka RyogaɹAll rights reserved. #iosdc #a Conforming to the Sequence 24 struct Countdown: Sequence { struct Iterator: IteratorProtocol { // ... } func makeIterator() -> Iterator { Iterator(count: count) } let count: UInt }

Slide 25

Slide 25 text

Copyright © 2024 treastrain / Tanaka RyogaɹAll rights reserved. #iosdc #a Conforming to the Sequence 25 struct Countdown: Sequence { // ... let count: UInt } for remaining in Countdown(count: 3) { print(remaining) } // 3 // 2 // 1

Slide 26

Slide 26 text

Copyright © 2024 treastrain / Tanaka RyogaɹAll rights reserved. #iosdc #a for-in Syntax → while Syntax 26 for remaining in Countdown(count: 3) { print(remaining) } var iterator = Countdown(count: 3).makeIterator() while let remaining = iterator.next() { print(remaining) }

Slide 27

Slide 27 text

Copyright © 2024 treastrain / Tanaka RyogaɹAll rights reserved. #iosdc #a Overview Sequence • Arrays, dictionaries, strings, and other types conform to the Sequence • Instances that conform to Sequence can be used in a for-in loop • The Sequence provides many built-in methods for manipulating elements • Creating a custom type that conforms to Sequence requires implementing an Iterator 27

Slide 28

Slide 28 text

Copyright © 2024 treastrain / Tanaka RyogaɹAll rights reserved. #iosdc #a Sequence 28

Slide 29

Slide 29 text

Copyright © 2024 treastrain / Tanaka RyogaɹAll rights reserved. #iosdc #a Sequence 🫱 🫲 AsyncSequence 29

Slide 30

Slide 30 text

Copyright © 2024 treastrain / Tanaka RyogaɹAll rights reserved. #iosdc #a AsyncSequence 30

Slide 31

Slide 31 text

Copyright © 2024 treastrain / Tanaka RyogaɹAll rights reserved. #iosdc #a 31 AsyncSequence | Apple Developer Documentation https://developer.apple.com/documentation/swift/asyncsequence ~ 5.10

Slide 32

Slide 32 text

Copyright © 2024 treastrain / Tanaka RyogaɹAll rights reserved. #iosdc #a Providing async-iterated Access 32 struct Countdown: Sequence { struct Iterator: IteratorProtocol { var count: UInt mutating func next() -> UInt? { guard count > 0 else { return nil } defer { count -= 1 } return count } } // ... }

Slide 33

Slide 33 text

Copyright © 2024 treastrain / Tanaka RyogaɹAll rights reserved. #iosdc #a Providing async-iterated Access 33 struct Countdown: Sequence { struct Iterator: IteratorProtocol { var count: UInt mutating func next() async -> UInt? { guard count > 0 else { return nil } defer { count -= 1 } return count } } // ... }

Slide 34

Slide 34 text

Copyright © 2024 treastrain / Tanaka RyogaɹAll rights reserved. #iosdc #a Conforming to the AsyncSequence 34 struct Countdown: AsyncSequence { struct AsyncIterator: AsyncIteratorProtocol { var count: UInt mutating func next() async -> UInt? { guard count > 0 else { return nil } defer { count -= 1 } return count } } // ... }

Slide 35

Slide 35 text

Copyright © 2024 treastrain / Tanaka RyogaɹAll rights reserved. #iosdc #a Conforming to the AsyncSequence 35 struct Countdown: AsyncSequence { struct AsyncIterator: AsyncIteratorProtocol { var count: UInt mutating func next() async -> UInt? { guard count > 0 else { return nil } defer { count -= 1 } try? await Task.sleep(for: .seconds(1)) return count } } // ... }

Slide 36

Slide 36 text

Copyright © 2024 treastrain / Tanaka RyogaɹAll rights reserved. #iosdc #a Conforming to the AsyncSequence 36 struct Countdown: AsyncSequence { struct AsyncIterator: AsyncIteratorProtocol { // ... } func makeAsyncIterator() -> AsyncIterator { AsyncIterator(count: count) } let count: UInt }

Slide 37

Slide 37 text

Copyright © 2024 treastrain / Tanaka RyogaɹAll rights reserved. #iosdc #a while Syntax 37 var iterator = Countdown(count: 3).makeIterator() while let remaining = iterator.next() { print(remaining) }

Slide 38

Slide 38 text

Copyright © 2024 treastrain / Tanaka RyogaɹAll rights reserved. #iosdc #a while Syntax 38 var iterator = Countdown(count: 3).makeAsyncIterator() while let remaining = await iterator.next() { print(remaining) }

Slide 39

Slide 39 text

Copyright © 2024 treastrain / Tanaka RyogaɹAll rights reserved. #iosdc #a for-await-in Syntax ← while Syntax 39 for await remaining in Countdown(count: 3) { print(remaining) } var iterator = Countdown(count: 3).makeAsyncIterator() while let remaining = await iterator.next() { print(remaining) }

Slide 40

Slide 40 text

Copyright © 2024 treastrain / Tanaka RyogaɹAll rights reserved. #iosdc #a for-await-in Syntax 40 // Swift 5.5 <= 5.10 let sequence: some AsyncSequence = ... for await element in sequence { print(element) }

Slide 41

Slide 41 text

Copyright © 2024 treastrain / Tanaka RyogaɹAll rights reserved. #iosdc #a for-await-in Syntax 41 // Swift 5.5 <= 5.10 let sequence: some AsyncSequence = ... for await element in sequence { if condition { break } }

Slide 42

Slide 42 text

Copyright © 2024 treastrain / Tanaka RyogaɹAll rights reserved. #iosdc #a for-await-in Syntax 42 // Swift 5.5 <= 5.10 let sequence: some AsyncSequence = ... for await element in sequence { if condition { continue } }

Slide 43

Slide 43 text

Copyright © 2024 treastrain / Tanaka RyogaɹAll rights reserved. #iosdc #a for-await-in Syntax with where Clause 43 // Swift 5.5 <= 5.10 let sequence: some AsyncSequence = ... for await element in sequence where condition { print(element) }

Slide 44

Slide 44 text

Copyright © 2024 treastrain / Tanaka RyogaɹAll rights reserved. #iosdc #a Built-in AsyncSequence Implementations 44 // Swift 5.5 <= 5.10 var sequence: some AsyncSequence { ... } let mapped = sequence.map { transform } let filtered = sequence.filter { isIncluded }

Slide 45

Slide 45 text

Copyright © 2024 treastrain / Tanaka RyogaɹAll rights reserved. #iosdc #a AsyncSequence 45 !

Slide 46

Slide 46 text

Copyright © 2024 treastrain / Tanaka RyogaɹAll rights reserved. #iosdc #a Throwing Errors 46 struct AsyncStorageDataSequence: AsyncSequence { struct AsyncIterator: AsyncIteratorProtocol { let storage: Storage mutating func next() async -> Data? { try? await Task.sleep(for: .seconds(1)) return await storage.data() } } // ... }

Slide 47

Slide 47 text

Copyright © 2024 treastrain / Tanaka RyogaɹAll rights reserved. #iosdc #a Throwing Errors 47 struct AsyncStorageDataSequence: AsyncSequence { struct AsyncIterator: AsyncIteratorProtocol { let storage: Storage mutating func next() async -> Data? { try? await Task.sleep(for: .seconds(1)) return await storage.data() } } // ... } struct Storage { func data() async throws -> Data { ... } }

Slide 48

Slide 48 text

Copyright © 2024 treastrain / Tanaka RyogaɹAll rights reserved. #iosdc #a Throwing Errors 48 struct AsyncStorageDataSequence: AsyncSequence { struct AsyncIterator: AsyncIteratorProtocol { let storage: Storage mutating func next() async throws -> Data? { try await Task.sleep(for: .seconds(1)) return try await storage.data() } } // ... } struct Storage { func data() async throws -> Data { ... } }

Slide 49

Slide 49 text

Copyright © 2024 treastrain / Tanaka RyogaɹAll rights reserved. #iosdc #a while Syntax 49 var iterator = AsyncStorageDataSequence(storage: ...).makeAsyncIterator() while let data = await iterator.next() { print(data) }

Slide 50

Slide 50 text

Copyright © 2024 treastrain / Tanaka RyogaɹAll rights reserved. #iosdc #a while Syntax 50 var iterator = AsyncStorageDataSequence(storage: ...).makeAsyncIterator() while let data = try await iterator.next() { print(data) }

Slide 51

Slide 51 text

Copyright © 2024 treastrain / Tanaka RyogaɹAll rights reserved. #iosdc #a for-await-in Syntax ← while Syntax 51 for await data in AsyncStorageDataSequence(storage: ...) { print(data) } var iterator = AsyncStorageDataSequence(storage: ...).makeAsyncIterator() while let data = try await iterator.next() { print(data) }

Slide 52

Slide 52 text

Copyright © 2024 treastrain / Tanaka RyogaɹAll rights reserved. #iosdc #a for-try-await-in Syntax ← while Syntax 52 for try await data in AsyncStorageDataSequence(storage: ...) { print(data) } var iterator = AsyncStorageDataSequence(storage: ...).makeAsyncIterator() while let data = try await iterator.next() { print(data) }

Slide 53

Slide 53 text

Copyright © 2024 treastrain / Tanaka RyogaɹAll rights reserved. #iosdc #a do-catch + for-try-await-in 53 do { for try await data in AsyncStorageDataSequence(storage: ...) { print(data) } } catch { // Error handling }

Slide 54

Slide 54 text

Copyright © 2024 treastrain / Tanaka RyogaɹAll rights reserved. #iosdc #a Overview AsyncSequence • AsyncSequence is just like Sequence, except elements are provided asynchronously • Instances that conform to AsyncSequence can be used in a for-await-in loop • The AsyncSequence provides many of the same built-in methods for manipulating elements as Sequence • May throw error 54

Slide 55

Slide 55 text

Copyright © 2024 treastrain / Tanaka RyogaɹAll rights reserved. #iosdc #a AsyncSequence APIs in Apple SDK 55 What’s new for Apple developers - Apple Developer https://developer.apple.com/whats-new/

Slide 56

Slide 56 text

Copyright © 2024 treastrain / Tanaka RyogaɹAll rights reserved. #iosdc #a 56 ncLineSequenceɹURLSession.AsyncBytesɹActivity.ContentUpda e.MessagesɹTaskGroupɹThrowingTaskGroupɹTransaction.Trans FrameProvider.CameraFrameUpdatesɹTranslationSession.BatchRe ManagedAppsɹAsyncStreamɹAsyncThrowingStreamɹDockAcce AssetImageGenerator.ImagesɹNWPathMonitorɹARKitSession.Eve ate.UpdatesɹAsyncPublisherɹAsyncThrowingPublisher ɹCSSearc Session.EventStreamɹMusicSubscription.UpdatesɹSHSession.Re aracterSequenceɹNotificationCenter.NotificationsɹFileHandle.As

Slide 57

Slide 57 text

Copyright © 2024 treastrain / Tanaka RyogaɹAll rights reserved. #iosdc #a Types of Apple’s AsyncSequence APIs Based on My Perspective • Adopted as an interface for entirely new functionality • Added the interfaces to existing APIs: • Closure-based • Delegate-based • Selector-based • Observer-based • As a Combine Publisher 57

Slide 58

Slide 58 text

Copyright © 2024 treastrain / Tanaka RyogaɹAll rights reserved. #iosdc #a Types of Apple’s AsyncSequence APIs Based on My Perspective • Adopted as an interface for entirely new functionality • Added the interfaces to existing APIs: • Closure-based • Delegate-based • Selector-based • Observer-based • As a Combine Publisher 58

Slide 59

Slide 59 text

Copyright © 2024 treastrain / Tanaka RyogaɹAll rights reserved. #iosdc #a TranslationSession.translations(from:) Sequence - [ TranslationSession.Response] 59 import Translation import SwiftUI struct ContentView: View { let contents: [String] = ["Jelly Bean", "KitKat", "Lollipop"] @State private var translated: [Int : String] = [:] var body: some View { List(contents.indices, id: \.self) { index in Text(translated[index] ?? contents[index]) } .translationTask { session in let requests: [TranslationSession.Request] = contents.indices.map { let content = contents[$0] return .init(sourceText: content, clientIdentifier: "\($0)") } do { let responses = try await session.translations(from: requests) for response in responses { let index = Int(response.clientIdentifier!)! translated[index] = response.targetText } } catch { // Error handling } } } } let responses = try await session.translations(from: requests) for response in responses { let index = Int(response.clientIdentifier!)! translated[index] = response.targetText }

Slide 60

Slide 60 text

Copyright © 2024 treastrain / Tanaka RyogaɹAll rights reserved. #iosdc #a TranslationSession.translations(from:) Sequence - [ TranslationSession.Response] 60 let responses = try await session.translations(from: requests) for response in responses { let index = Int(response.clientIdentifier!)! translated[index] = response.targetText } Jelly Bean KitKat Lollipop translations(from:) δΣϦʔϏʔϯ ΩοτΧοτ ๮͖ͭΞΠεΩϟϯσΟ

Slide 61

Slide 61 text

Copyright © 2024 treastrain / Tanaka RyogaɹAll rights reserved. #iosdc #a TranslationSession.translate(batch:) AsyncSequence - TranslationSession.BatchResponse 61 for try await response in session.translate(batch: requests) { let index = Int(response.clientIdentifier!)! translated[index] = response.targetText } Jelly Bean KitKat Lollipop translate(batch:) δΣϦʔϏʔϯ ΩοτΧοτ ๮͖ͭΞΠεΩϟϯσΟ

Slide 62

Slide 62 text

Copyright © 2024 treastrain / Tanaka RyogaɹAll rights reserved. #iosdc #a Types of Apple’s AsyncSequence APIs Based on My Perspective • Adopted as an interface for entirely new functionality • Added the interfaces to existing APIs: • Closure-based • Delegate-based • Selector-based • Observer-based • As a Combine Publisher 62

Slide 63

Slide 63 text

Copyright © 2024 treastrain / Tanaka RyogaɹAll rights reserved. #iosdc #a NWPathMonitor Closure-based 63 import Network import SwiftUI struct ContentView: View { @State private var interface: String = "Checking..." @State private var monitor: NWPathMonitor! var body: some View { Text(interface) .onAppear { monitor = NWPathMonitor() monitor.pathUpdateHandler = { path in if path.usesInterfaceType(.wifi) { interface = "Wi-Fi" } else if path.usesInterfaceType(.cellular) { interface = "Cellular" } else if path.status == .satisfied { interface = "Others" } else { interface = "No available" } } monitor.start(queue: .main) } } } monitor = NWPathMonitor() monitor.pathUpdateHandler = { path in if path.usesInterfaceType(.wifi) { interface = "Wi-Fi" } else if path.usesInterfaceType(.cellular) { interface = "Cellular" } else if path.status == .satisfied { interface = "Others" } else { interface = "No available" } } monitor.start(queue: .main)

Slide 64

Slide 64 text

Copyright © 2024 treastrain / Tanaka RyogaɹAll rights reserved. #iosdc #a NWPathMonitor Closure - pathUpdateHandler: ( ( NWPath) -> Void)? 64 monitor = NWPathMonitor() monitor.pathUpdateHandler = { path in if path.usesInterfaceType(.wifi) { interface = "Wi-Fi" } else if path.usesInterfaceType(.cellular) { interface = "Cellular" } else if path.status == .satisfied { interface = "Others" } else { interface = "No available" } } monitor.start(queue: .main)

Slide 65

Slide 65 text

Copyright © 2024 treastrain / Tanaka RyogaɹAll rights reserved. #iosdc #a NWPathMonitor AsyncSequence - NWPathMonitor 65 for await path in NWPathMonitor() { if path.usesInterfaceType(.wifi) { interface = "Wi-Fi" } else if path.usesInterfaceType(.cellular) { interface = "Cellular" } else if path.status == .satisfied { interface = "Others" } else { interface = "No available" } }

Slide 66

Slide 66 text

Copyright © 2024 treastrain / Tanaka RyogaɹAll rights reserved. #iosdc #a NWPathMonitor Closure-based → AsyncSequence 66 import Network import SwiftUI struct ContentView: View { @State private var interface: String = "Checking..." var body: some View { Text(interface) .task { for await path in NWPathMonitor() { if path.usesInterfaceType(.wifi) { interface = "Wi-Fi" } else if path.usesInterfaceType(.cellular) { interface = "Cellular" } else if path.status == .satisfied { interface = "Others" } else { interface = "No available" } } } } } for await path in NWPathMonitor() { if path.usesInterfaceType(.wifi) { interface = "Wi-Fi" } else if path.usesInterfaceType(.cellular) { interface = "Cellular" } else if path.status == .satisfied { interface = "Others" } else { interface = "No available" } }

Slide 67

Slide 67 text

Copyright © 2024 treastrain / Tanaka RyogaɹAll rights reserved. #iosdc #a Types of Apple’s AsyncSequence APIs Based on My Perspective • Adopted as an interface for entirely new functionality • Added the interfaces to existing APIs: • Closure-based • Delegate-based • Selector-based • Observer-based • As a Combine Publisher 67

Slide 68

Slide 68 text

Copyright © 2024 treastrain / Tanaka RyogaɹAll rights reserved. #iosdc #a Handling Location Updates Delegate - CLLocationManagerDelegate 68 import CoreLocation final class LocationHelper: NSObject { let manager = CLLocationManager() override init() { super.init() manager.delegate = self // ... } func listen() { manager.startUpdatingLocation() } } extension LocationHelper: CLLocationManagerDelegate { func locationManager(_ manager: CLLocationManager, didUpdateLocations locations: [CLLocation]) { print("Current locations:", locations) } func locationManager(_ manager: CLLocationManager, didFailWithError error: any Error) { // Error handling } // ... }

Slide 69

Slide 69 text

Copyright © 2024 treastrain / Tanaka RyogaɹAll rights reserved. #iosdc #a Handling Location Updates AsyncSequence - CLLocationUpdate.Updates 69 import CoreLocation final class LocationHelper: NSObject { override init() { super.init() // ... } func listen() async { do { for try await update in CLLocationUpdate.liveUpdates() { print("Current location:", update.location) // ... } } catch { // Error handling } } } func listen() async { do { for try await update in CLLocationUpdate.liveUpdates() { print("Current location:", update.location) // ... } } catch { // Error handling } }

Slide 70

Slide 70 text

Copyright © 2024 treastrain / Tanaka RyogaɹAll rights reserved. #iosdc #a Handling Location Updates AsyncSequence - CLLocationUpdate.Updates 70 func listen() async { do { for try await update in CLLocationUpdate.liveUpdates() { print("Current location:", update.location) // ... } } catch { // Error handling } }

Slide 71

Slide 71 text

Copyright © 2024 treastrain / Tanaka RyogaɹAll rights reserved. #iosdc #a Types of Apple’s AsyncSequence APIs Based on My Perspective • Adopted as an interface for entirely new functionality • Added the interfaces to existing APIs: • Closure-based • Delegate-based • Selector-based • Observer-based • As a Combine Publisher 71

Slide 72

Slide 72 text

Copyright © 2024 treastrain / Tanaka RyogaɹAll rights reserved. #iosdc #a AsyncPublisher / AsyncThrowingPublisher Publisher.values 72 import Combine let publisher = CurrentValueSubject(2024) let cancellable = publisher.sink { value in print(value) } // 2024 let task = Task { for await value in publisher.values { print(value) } // 2024 }

Slide 73

Slide 73 text

Copyright © 2024 treastrain / Tanaka RyogaɹAll rights reserved. #iosdc #a Different Results Publisher.sink(receiveValue:) vs. Publisher.values 73 import Combine let publisher = CurrentValueSubject(0) let cancellable = publisher.sink { value in print(value) } // 0 1 2 3 let task = Task { for await value in publisher.values { print(value) } // 0 1 3 } // after the value is ready to be received publisher.send(1) publisher.send(2) publisher.send(3)

Slide 74

Slide 74 text

Copyright © 2024 treastrain / Tanaka RyogaɹAll rights reserved. #iosdc #a 74 https://x.com/shimastriper/status/1782505026503753951

Slide 75

Slide 75 text

Copyright © 2024 treastrain / Tanaka RyogaɹAll rights reserved. #iosdc #a Different Results Publisher.sink(receiveValue:) vs. Publisher.values 75 import Combine let publisher = CurrentValueSubject(0) let cancellable = publisher.sink { value in print(value) } // 0 1 2 3 let task = Task { for await value in publisher .values { print(value) } // 0 1 3 } // after the value is ready to be received publisher.send(1) publisher.send(2) publisher.send(3)

Slide 76

Slide 76 text

Copyright © 2024 treastrain / Tanaka RyogaɹAll rights reserved. #iosdc #a Same Results Publisher.sink(receiveValue:) vs. Publisher.values 76 import Combine let publisher = CurrentValueSubject(0) let cancellable = publisher.sink { value in print(value) } // 0 1 2 3 let task = Task { for await value in publisher .buffer(size: 100, prefetch: .keepFull, whenFull: .dropOldest) .values { print(value) } // 0 1 2 3 } // after the value is ready to be received publisher.send(1) publisher.send(2) publisher.send(3)

Slide 77

Slide 77 text

Copyright © 2024 treastrain / Tanaka RyogaɹAll rights reserved. #iosdc #a Same Results Publisher.sink(receiveValue:) vs. Publisher.values 77 import Combine let publisher = CurrentValueSubject(0) let cancellable = publisher.sink { value in print(value) } // 0 1 2 3 let task = Task { for await value in publisher .buffer(size: 100, prefetch: .keepFull, whenFull: .dropOldest) .values { print(value) } // 0 1 2 3 } // after the value is ready to be received publisher.send(1) publisher.send(2) publisher.send(3) unlimited

Slide 78

Slide 78 text

Copyright © 2024 treastrain / Tanaka RyogaɹAll rights reserved. #iosdc #a Any Other Way? Publisher.sink(receiveValue:) 78 import Combine let publisher = CurrentValueSubject(0) let cancellable = publisher.sink { value in print(value) } // ??????????? // after the value is ready to be received publisher.send(1) publisher.send(2) publisher.send(3)

Slide 79

Slide 79 text

Copyright © 2024 treastrain / Tanaka RyogaɹAll rights reserved. #iosdc #a Adapting Existing Code ( Closure-based) 79

Slide 80

Slide 80 text

Copyright © 2024 treastrain / Tanaka RyogaɹAll rights reserved. #iosdc #a Adapting Existing Code From Closure-based 80 import Combine let publisher = CurrentValueSubject(0) var cancellable: AnyCancellable? let value = await withCheckedContinuation { continuation in cancellable = publisher.sink { value in continuation.resume(returning: value) } } print(value) // after the value is ready to be received publisher.send(1) publisher.send(2) publisher.send(3)

Slide 81

Slide 81 text

Copyright © 2024 treastrain / Tanaka RyogaɹAll rights reserved. #iosdc #a Adapting Existing Code From Closure-based 81 import Combine let publisher = CurrentValueSubject(0) var cancellable: AnyCancellable? let value = await withCheckedContinuation { continuation in cancellable = publisher.sink { value in continuation.resume(returning: value) } } print(value) // after the value is ready to be received publisher.send(1) publisher.send(2) publisher.send(3) Thread 1 : Fatal error: SWIFT TASK CONTINUATION MISUSE : * tried to resume its continuation more than once, returning 1!

Slide 82

Slide 82 text

Copyright © 2024 treastrain / Tanaka RyogaɹAll rights reserved. #iosdc #a Produce the Result • For emitting a single value • withCheckedContinuation(function:_:) withCheckedThrowingContinuation(function:_:) • For emitting a multiple value • AsyncSequence 82

Slide 83

Slide 83 text

Copyright © 2024 treastrain / Tanaka RyogaɹAll rights reserved. #iosdc #a AsyncStream AsyncThrowingStream 83

Slide 84

Slide 84 text

Copyright © 2024 treastrain / Tanaka RyogaɹAll rights reserved. #iosdc #a Adapting Existing Code From Closure-based 84 import Combine let publisher = CurrentValueSubject(0) let (stream, continuation) = AsyncStream.makeStream(of: Int.self) let cancellable = publisher.sink { value in continuation.yield(value) } continuation.onTermination = { _ in cancellable.cancel() } let task = Task { for await value in stream { print(value) } // 0 1 2 3 } // after the value is ready to be received publisher.send(1) publisher.send(2) publisher.send(3) let task = Task { for await value in stream { print(value) } // 0 1 2 3 } // after the value is ready to be received publisher.send(1) publisher.send(2) publisher.send(3)

Slide 85

Slide 85 text

Copyright © 2024 treastrain / Tanaka RyogaɹAll rights reserved. #iosdc #a Adapting Existing Code ( Delegate-based) 85

Slide 86

Slide 86 text

Copyright © 2024 treastrain / Tanaka RyogaɹAll rights reserved. #iosdc #a Adapting Existing Code From Delegate-based 86 protocol MyDelegate { func didUpdate(value: Int) func didFinish() func didFail(with error: any Error) } final class MyController { ... } extension MyController: MyDelegate { func didUpdate(value: Int) { ... } func didFinish() { ... } func didFail(with error: any Error) { ... } }

Slide 87

Slide 87 text

Copyright © 2024 treastrain / Tanaka RyogaɹAll rights reserved. #iosdc #a Adapting Existing Code From Delegate-based 87 protocol MyDelegate { ... } final class MyController { private var continuation: AsyncThrowingStream.Continuation? var stream: AsyncThrowingStream { let (stream, continuation) = AsyncThrowingStream.makeStream(of: Int.self) self.continuation = continuation return stream } } extension MyController: MyDelegate { ... }

Slide 88

Slide 88 text

Copyright © 2024 treastrain / Tanaka RyogaɹAll rights reserved. #iosdc #a Adapting Existing Code From Delegate-based 88 protocol MyDelegate { ... } final class MyController { ... } extension MyController: MyDelegate { func didUpdate(value: Int) { continuation?.yield(value) } func didFinish() { ... } func didFail(with error: any Error) { ... } }

Slide 89

Slide 89 text

Copyright © 2024 treastrain / Tanaka RyogaɹAll rights reserved. #iosdc #a Adapting Existing Code From Delegate-based 89 protocol MyDelegate { ... } final class MyController { ... } extension MyController: MyDelegate { func didUpdate(value: Int) { ... } func didFinish() { continuation?.finish() continuation = nil } func didFail(with error: any Error) { ... } }

Slide 90

Slide 90 text

Copyright © 2024 treastrain / Tanaka RyogaɹAll rights reserved. #iosdc #a Adapting Existing Code From Delegate-based 90 protocol MyDelegate { ... } final class MyController { ... } extension MyController: MyDelegate { func didUpdate(value: Int) { ... } func didFinish() { ... } func didFail(with error: any Error) { continuation?.finish(throwing: error) continuation = nil } }

Slide 91

Slide 91 text

Copyright © 2024 treastrain / Tanaka RyogaɹAll rights reserved. #iosdc #a Adapting Existing Code From Delegate-based 91 protocol MyDelegate { func didUpdate(value: Int) func didFinish() func didFail(with error: any Error) } final class MyController { private var continuation: AsyncThrowingStream.Continuation? var stream: AsyncThrowingStream { let (stream, continuation) = AsyncThrowingStream.makeStream(of: Int.self) self.continuation = continuation return stream } } extension MyController: MyDelegate { func didUpdate(value: Int) { continuation?.yield(value) } func didFinish() { continuation?.finish() continuation = nil } func didFail(with error: any Error) { continuation?.finish(throwing: error) continuation = nil } }

Slide 92

Slide 92 text

Copyright © 2024 treastrain / Tanaka RyogaɹAll rights reserved. #iosdc #a Practical Guide 92

Slide 93

Slide 93 text

Copyright © 2024 treastrain / Tanaka RyogaɹAll rights reserved. #iosdc #a Naming Tips 93

Slide 94

Slide 94 text

Copyright © 2024 treastrain / Tanaka RyogaɹAll rights reserved. #iosdc #a Swift Concurrency Naming async/await • noun • e.g. URLSession.data(from:delegate:) • No verbs used • 🙅 URLSession.getData(from:delegate:) 94

Slide 95

Slide 95 text

Copyright © 2024 treastrain / Tanaka RyogaɹAll rights reserved. #iosdc #a AsyncSequence Variable Naming Apple SDK • bytes • updates • events • messages • *Stream 95

Slide 96

Slide 96 text

Copyright © 2024 treastrain / Tanaka RyogaɹAll rights reserved. #iosdc #a AsyncSequence Type Naming Apple SDK • Updates: ActivityStateUpdates, DeviceMotionUpdates • Statuses: Product.SubscriptionInfo.Status.Statuses • Results: CSSearchQuery.Results, HKWorkoutRouteQueryDescriptor.Results • Messages: GroupSessionMessenger.Messages, Transaction.Transactions • Events: AccessoryEvents, CLMonitor.Events • Transactions: Transaction.Transactions • Notifications: NotificationCenter.Notifications 96

Slide 97

Slide 97 text

Copyright © 2024 treastrain / Tanaka RyogaɹAll rights reserved. #iosdc #a AsyncSequence Type Naming Apple SDK • AsyncBytes • AsyncCharacterSequence • AsyncLineSequence 97

Slide 98

Slide 98 text

Copyright © 2024 treastrain / Tanaka RyogaɹAll rights reserved. #iosdc #a Example of iOS App 98

Slide 99

Slide 99 text

Copyright © 2024 treastrain / Tanaka RyogaɹAll rights reserved. #iosdc #a NotificationCenter.Notifications UIResponder.keyboardWillShowNotification 99 NotificationCenter .default .notifications(named: UIResponder.keyboardWillShowNotification)

Slide 100

Slide 100 text

Copyright © 2024 treastrain / Tanaka RyogaɹAll rights reserved. #iosdc #a Subscribe viewDidLoad() 100 import UIKit final class ViewController: UIViewController { let presenter = Presenter() override func viewDidLoad() { super.viewDidLoad() Task { for await notification in NotificationCenter .default .notifications( named: UIResponder.keyboardWillShowNotification ) { presenter.didReceiveKeyboardWillShowNotification() } } } }

Slide 101

Slide 101 text

Copyright © 2024 treastrain / Tanaka RyogaɹAll rights reserved. #iosdc #a Stopping Event Listening Prevent Memory Leaks in for-await-in 101 import UIKit final class ViewController: UIViewController { let presenter = Presenter() override func viewDidLoad() { super.viewDidLoad() Task { for await notification in NotificationCenter .default .notifications( named: UIResponder.keyboardWillShowNotification ) { presenter.didReceiveKeyboardWillShowNotification() } } } } ⏳

Slide 102

Slide 102 text

Copyright © 2024 treastrain / Tanaka RyogaɹAll rights reserved. #iosdc #a Cancel at deinit For Stopping for-await-in 102 import UIKit final class ViewController: UIViewController { let presenter = Presenter() private var task: Task<(), Never>? deinit { task?.cancel() } override func viewDidLoad() { super.viewDidLoad() task = Task { for await notification in NotificationCenter { ... } } } }

Slide 103

Slide 103 text

Copyright © 2024 treastrain / Tanaka RyogaɹAll rights reserved. #iosdc #a deinit May not be Called Strong Reference Capturing in the Task 103 final class ViewController: UIViewController { let presenter = Presenter() private var task: Task<(), Never>? deinit { ... } override func viewDidLoad() { super.viewDidLoad() task = Task { for await ... in ... { presenter.didReceiveKeyboardWillShowNotification() } } } }

Slide 104

Slide 104 text

Copyright © 2024 treastrain / Tanaka RyogaɹAll rights reserved. #iosdc #a deinit May not be Called Strong Reference Capturing in the Task 104 final class ViewController: UIViewController { let presenter = Presenter() private var task: Task<(), Never>? deinit { ... } override func viewDidLoad() { super.viewDidLoad() task = Task { for await ... in ... { presenter.didReceiveKeyboardWillShowNotification() } } } } Where is “self.” ...?

Slide 105

Slide 105 text

Copyright © 2024 treastrain / Tanaka RyogaɹAll rights reserved. #iosdc #a deinit May not be Called Strong Reference Capturing in the Task 105 final class ViewController: UIViewController { let presenter = Presenter() private var task: Task<(), Never>? deinit { ... } override func viewDidLoad() { super.viewDidLoad() task = Task { for await ... in ... { presenter.didReceiveKeyboardWillShowNotification() } } } } Where is “self.” ...? @_implicitSelfCapture

Slide 106

Slide 106 text

Copyright © 2024 treastrain / Tanaka RyogaɹAll rights reserved. #iosdc #a [weak self] with self?.* 106 final class ViewController: UIViewController { let presenter = Presenter() var anotherValue = 0 private var task: Task<(), Never>? deinit { ... } override func viewDidLoad() { super.viewDidLoad() task = Task { [weak self] in for await ... in ... { self?.presenter.didReceiveKeyboardWillShowNotification() anotherValue = 10 } } } } 🚨

Slide 107

Slide 107 text

Copyright © 2024 treastrain / Tanaka RyogaɹAll rights reserved. #iosdc #a [weak object] Capturing the target property 107 final class ViewController: UIViewController { let presenter = Presenter() private var task: Task<(), Never>? deinit { ... } override func viewDidLoad() { super.viewDidLoad() task = Task { [weak presenter] in for await ... in ... { presenter?.didReceiveKeyboardWillShowNotification() } } } }

Slide 108

Slide 108 text

Copyright © 2024 treastrain / Tanaka RyogaɹAll rights reserved. #iosdc #a Static Analyzer…? It’s pernickety… 108 final class ViewController: UIViewController { let presenter = Presenter() private var task: Task<(), Never>? deinit { ... } override func viewDidLoad() { super.viewDidLoad() task = Task { for await ... in ... { presenter.didReceiveKeyboardWillShowNotification() } } } }

Slide 109

Slide 109 text

Copyright © 2024 treastrain / Tanaka RyogaɹAll rights reserved. #iosdc #a 109 https://github.com/treastrain/AsyncSequenceSubscription treastrain/AsyncSequenceSubscription

Slide 110

Slide 110 text

Copyright © 2024 treastrain / Tanaka RyogaɹAll rights reserved. #iosdc #a Like the Combine sink treastrain/AsyncSequenceSubscription 110 import AsyncSequenceSubscription import Foundation let sequence: some AsyncSequence = ... let task = sequence .sink { [weak self] element in await self?.didReceived(element) }

Slide 111

Slide 111 text

Copyright © 2024 treastrain / Tanaka RyogaɹAll rights reserved. #iosdc #a Can Call Cancel Using the Task treastrain/AsyncSequenceSubscription 111 import AsyncSequenceSubscription import Foundation let sequence: some AsyncSequence = ... let task = sequence .sink { [weak self] element in await self?.didReceived(element) } // ... task.cancel()

Slide 112

Slide 112 text

Copyright © 2024 treastrain / Tanaka RyogaɹAll rights reserved. #iosdc #a Auto Cancelling storeWhileInstanceActive(_:) 112 import AsyncSequenceSubscription import Foundation let sequence: some AsyncSequence = ... sequence .sink { [weak self] element in await self?.didReceived(element) } .storeWhileInstanceActive(self)

Slide 113

Slide 113 text

Copyright © 2024 treastrain / Tanaka RyogaɹAll rights reserved. #iosdc #a SwiftUI Easy Cancelling 113 import SwiftUI struct ContentView: View { var body: some View { Text("Hello") .task { for await notification in NotificationCenter .default .notifications( named: UIResponder.keyboardWillShowNotification ) { // ... } } } }

Slide 114

Slide 114 text

Copyright © 2024 treastrain / Tanaka RyogaɹAll rights reserved. #iosdc #a 114 task(priority:_ : ) | Apple Developer Documentation https://developer.apple.com/documentation/swiftui/view/task(priority:_:)

Slide 115

Slide 115 text

Copyright © 2024 treastrain / Tanaka RyogaɹAll rights reserved. #iosdc #a Benefits of moving to AsyncSequence 115

Slide 116

Slide 116 text

Copyright © 2024 treastrain / Tanaka RyogaɹAll rights reserved. #iosdc #a Benefits of moving to AsyncSequence Swift Everywhere 116 🚜 Apple Platforms Only

Slide 117

Slide 117 text

Copyright © 2024 treastrain / Tanaka RyogaɹAll rights reserved. #iosdc #a Benefits of moving to AsyncSequence Simplifying Async Method Calls • Calling async methods from closures, delegate methods, or Combine publishers required creating a Task • This was necessary because these contexts are not within the async/await world • With AsyncSequence, using a for-await-in loop means you’re already within a Task, so no need to create one 117

Slide 118

Slide 118 text

Copyright © 2024 treastrain / Tanaka RyogaɹAll rights reserved. #iosdc #a 118 https://speakerdeck.com/treastrain/subscribe-closure-when-calling-an-async-method-there-d11f9679 - 7abe-4c29-b837-eca98ef9a985

Slide 119

Slide 119 text

Copyright © 2024 treastrain / Tanaka RyogaɹAll rights reserved. #iosdc #a Benefits of moving to AsyncSequence Navigating Threading Rules with async/await • Delegate methods may be called from threads other than the main thread, as documented • In Combine, values may arrive on a non-main thread, requiring the following processing on the main thread • Violating this rule could result in runtime warnings from the Main Thread Checker or unexpected behavior 119

Slide 120

Slide 120 text

Copyright © 2024 treastrain / Tanaka RyogaɹAll rights reserved. #iosdc #a Benefits of moving to AsyncSequence DispatchQueue.async & Publisher.receive(on:) 120 import Combine // Needs to be called from the main thread func mainFunc(value: Int) {} func exec() { let cancellable1 = Just(10).sink { value in DispatchQueue.main.async { mainFunc(value: value) } } let cancellable2 = Just(10).receive(on: DispatchQueue.main).sink { value in mainFunc(value: value) } // ... }

Slide 121

Slide 121 text

Copyright © 2024 treastrain / Tanaka RyogaɹAll rights reserved. #iosdc #a Benefits of moving to AsyncSequence Async/await & @ MainActor 121 import Combine @MainActor func mainFunc(value: Int) {} func exec() { let task = Task { for await value in Just(10).values { await mainFunc(value: value) } } // ... }

Slide 122

Slide 122 text

Copyright © 2024 treastrain / Tanaka RyogaɹAll rights reserved. #iosdc #a Swift 6.0 Updates 122

Slide 123

Slide 123 text

Copyright © 2024 treastrain / Tanaka RyogaɹAll rights reserved. #iosdc #a Built-in AsyncSequence Implementations 123 // Swift 5.5 <= 5.10 var sequence: some AsyncSequence { ... } let mapped = sequence.map { transform } let filtered = sequence.filter { isIncluded }

Slide 124

Slide 124 text

Copyright © 2024 treastrain / Tanaka RyogaɹAll rights reserved. #iosdc #a 124 https://github.com/treastrain/AsyncSequenceSubscription apple/swift-async-algorithms

Slide 125

Slide 125 text

Copyright © 2024 treastrain / Tanaka RyogaɹAll rights reserved. #iosdc #a Loooooong Type Name Methods return a type specific to the method’s semantics 125 // Countdown let sequence1 = Countdown(count: 1) // AsyncMapSequence let sequence2 = sequence1.map { $0 * 2 } // AsyncFilterSequence> let sequence3 = sequence2.filter { $0 > 6 } // AsyncDropFirstSequence

Slide 126

Slide 126 text

Copyright © 2024 treastrain / Tanaka RyogaɹAll rights reserved. #iosdc #a Type Erasure SwiftUI / Combine 126 🚜 AnyPublisher eraseToAnyPublisher() AnyView some View

Slide 127

Slide 127 text

Copyright © 2024 treastrain / Tanaka RyogaɹAll rights reserved. #iosdc #a AnyAsyncSequence 127

Slide 128

Slide 128 text

Copyright © 2024 treastrain / Tanaka RyogaɹAll rights reserved. #iosdc #a AsyncSequence next() async or next() async throws 128 struct MyAsyncSequence: AsyncSequence { struct AsyncIterator: AsyncIteratorProtocol { mutating func next() async -> Element? { } } func makeAsyncIterator() -> AsyncIterator { AsyncIterator() } } struct MyAsyncSequence: AsyncSequence { struct AsyncIterator: AsyncIteratorProtocol { mutating func next() async throws -> Element? { } } func makeAsyncIterator() -> AsyncIterator { AsyncIterator() } }

Slide 129

Slide 129 text

Copyright © 2024 treastrain / Tanaka RyogaɹAll rights reserved. #iosdc #a 129 AsyncSequence | Apple Developer Documentation https://developer.apple.com/documentation/swift/asyncsequence ~ 5.10

Slide 130

Slide 130 text

Copyright © 2024 treastrain / Tanaka RyogaɹAll rights reserved. #iosdc #a some AsyncSequence It's not cool to use 130 // Countdown (no-throwing) let sequence: some AsyncSequence = Countdown(count: 1) // ❌ Call can throw, but the error is not handled - Insert 'try' for try await remaining in sequence { // ❌ Cannot convert value of type '(some AsyncSequence).Element' to specified type 'UInt' - Insert ' as! UInt' let num: UInt = remaining print(remaining) }

Slide 131

Slide 131 text

Copyright © 2024 treastrain / Tanaka RyogaɹAll rights reserved. #iosdc #a 131 AsyncSequence | Apple Developer Documentation https://developer.apple.com/documentation/swift/asyncsequence ~ 5.10

Slide 132

Slide 132 text

Copyright © 2024 treastrain / Tanaka RyogaɹAll rights reserved. #iosdc #a 132 AsyncSequence | Apple Developer Documentation https://developer.apple.com/documentation/swift/asyncsequence 6.0

Slide 133

Slide 133 text

Copyright © 2024 treastrain / Tanaka RyogaɹAll rights reserved. #iosdc #a Generalize Effect Polymorphism SE - 0421 • SE - 0388 : Convenience Async[Throwing]Stream.makeStream methods • SE - 0413 : Typed throws • SE - 0414 : Region based Isolation 133 struct MyAsyncSequence: AsyncSequence { struct AsyncIterator: AsyncIteratorProtocol { mutating func next() async throws(Failure) -> Element? { } } func makeAsyncIterator() -> AsyncIterator { AsyncIterator() } } throws(Never)

Slide 134

Slide 134 text

Copyright © 2024 treastrain / Tanaka RyogaɹAll rights reserved. #iosdc #a some AsyncSequence Opaque types are practical 134 // Countdown (no-throwing) let sequence: some AsyncSequence = Countdown(count: 1) .map { $0 * 2 } .filter { $0 > 6 } .dropFirst() .prefix(1) // ✅ for await remaining in Countdown(count: 1) { print(remaining) // UInt }

Slide 135

Slide 135 text

Copyright © 2024 treastrain / Tanaka RyogaɹAll rights reserved. #iosdc #a Recap • Sequence 🫱 🫲 AsyncSequence • AsyncSequence APIs included in Apple's SDK • Closure → AsyncSequence / Delegate → AsyncSequence • Practical Guide 135

Slide 136

Slide 136 text

Copyright © 2024 treastrain / Tanaka RyogaɹAll rights reserved. #iosdc #a References • SE - 0298 : Async/Await: Sequences https://github.com/swiftlang/swift-evolution/blob/main/proposals/0298- asyncsequence.md • SE - 0388 : Convenience Async[Throwing]Stream.makeStream methods https://github.com/swiftlang/swift- evolution/blob/main/proposals/0388-async-stream-factory.md • SE - 0421 : Generalize effect polymorphism for AsyncSequence and AsyncIteratorProtocol https://github.com/ swiftlang/swift-evolution/blob/main/proposals/0421-generalize-async-sequence.md • AsyncSequence | Apple Developer Documentation https://developer.apple.com/documentation/Swift/ AsyncSequence • Sequence | Apple Developer Documentation https://developer.apple.com/documentation/swift/sequence • SE - 0297 : Concurrency Interoperability with Objective-C https://github.com/swiftlang/swift-evolution/blob/main/ proposals/0297-concurrency-objc.md • SE - 0413 : Typed throws https://github.com/swiftlang/swift-evolution/blob/main/proposals/0413-typed- throws.md • SE - 0414 : Region based Isolation https://github.com/swiftlang/swift-evolution/blob/main/proposals/0414-region- based-isolation.md 136

Slide 137

Slide 137 text

Copyright © 2024 treastrain / Tanaka RyogaɹAll rights reserved. #iosdc #a ࢖͏ɾ࡞ΔɾଞͷσβΠϯύλʔϯʢΫϩʔδϟɺDelegate ͳͲʣ͔ΒҠߦ͢Δ Mastering AsyncSequence 137 iOSDC Japan 2024 Day 2 #iosdc #a Happy async iterating! ࢿྉ͸ tret.jp ʹܝࡌ ⏩