Upgrade to Pro
— share decks privately, control downloads, hide ads and more …
Speaker Deck
Sign up for free
Menu
Search
Features
All features
Private URLs
Password Protection
Custom URLS
Scheduled publishing
Remove Branding
Restrict embedding
Deck Collections
Notes
Features
All features
Private URLs
Password Protection
Custom URLS
Scheduled publishing
Remove Branding
Restrict embedding
Deck Collections
Notes
Explore
Featured decks
Featured speakers
Programming
Technology
Storyboards
Explore
Featured decks
Featured speakers
Programming
Technology
Storyboards
Pricing
Search
Sign in
Sign up for free
Swift Zoomin' #8
Search
Yuta Koshizawa
October 23, 2021
Programming
720
2
Share
Embed
Copy iframe code
Copy JS code
Copy link
Start on current slide
Swift Zoomin' #8
Yuta Koshizawa
October 23, 2021
More Decks by Yuta Koshizawa
See All by Yuta Koshizawa
Heart of Swift Concurrency
koher
0
1.2k
How Swift's Type System Guides AI Agents
koher
0
490
Swift Updates - Learn Languages 2025
koher
2
830
Swiftのstructとイミュータビリティ
koher
4
820
Swift 6のTyped throwsとSwiftにおけるエラーハンドリングの全体像を学ぶ
koher
4
6.4k
Swift Concurrency時代のiOSアプリの作り方
koher
15
9.8k
async/awaitやactorでiOSアプリ開発がどう変わるか Before & Afterの具体例で学ぶ
koher
9
8k
Swift Language Updates - Learn Languages 2021
koher
8
1.9k
先取り! Swift 6 の async/await
koher
15
4.2k
Other Decks in Programming
See All in Programming
大喜利で理解するLLM as a Judge / Understanding LLM-as-a-Judge through Ogiri
rockname
0
190
AI が書く Go コードの品質を劇的に向上させる Linter: “declscope”
mpyw
0
470
iOS 27でニュースアプリはどう変わる!? 〜日経電子版の新機能対応と、開発事例から〜
lynnswap
7
13k
Workers Cache を知る
syumai
0
320
C#の現在地 進化の歴史と、AI時代の.NET Everywhere
neuecc
5
4.8k
Augmenting AI with the Power of Jakarta EE
ivargrimstad
0
470
AHC070解法紹介
eijirou
0
150
Unity6 URPによる海底をテーマにしたVJシステムの解説 | Unity Shader 完全に理解した 勉強会
gam0022
0
310
モジュールの視点からSwiftを読み解く #iosdc
s_shimotori
0
310
Augmenting AI with the Power of Jakarta EE
ivargrimstad
0
400
Everything will be SERVERLESS — 信じて運用した10年の経験値 / Everything Will be Serverless — Lessons Learned from 10 Years of Operational Experience
seike460
PRO
1
690
Ghostty + Neovimで作る 透明でカッコ良い開発環境
j341nono
0
150
Featured
See All Featured
SEO for Brand Visibility & Recognition
aleyda
0
4.8k
Performance Is Good for Brains [We Love Speed 2024]
tammyeverts
12
1.9k
CSS Pre-Processors: Stylus, Less & Sass
bermonpainter
360
31k
End of SEO as We Know It (SMX Advanced Version)
ipullrank
3
4.4k
Designing for humans not robots
tammielis
254
26k
DevOps and Value Stream Thinking: Enabling flow, efficiency and business value
helenjbeal
1
390
Building an army of robots
kneath
307
47k
Mobile First: as difficult as doing things right
swwweet
225
10k
How Fast Is Fast Enough? [PerfNow 2025]
tammyeverts
3
910
Lightning Talk: Beautiful Slides for Beginners
inesmontani
PRO
2
710
StorybookのUI Testing Handbookを読んだ
zakiyama
31
6.9k
A Guide to Academic Writing Using Generative AI - A Workshop
ks91
PRO
1
500
Transcript
Swi$ Zoomin' #8 Actor ϋϯζΦϯ
Actor ͱ
ɾɾɾͷલʹ
Actor async/await Λଟ༻͢Δ
async/await ͷ؆୯ͳ෮श
ίʔϧόοΫʹΑΔඇಉظؔ // એݴ func downloadData(from url: URL, completion: @escaping (Data)
-> Void) // ར༻ downloadData(from: url) { data in // data Λ͏ॲཧ }
async/await ʹΑΔඇಉظؔ // એݴ func downloadData(from url: URL) async ->
Data // ར༻ let data = await downloadData(from: url) // data Λ͏ॲཧ
ίʔϧόοΫʹΑΔඇಉظؔ // એݴ func downloadData(from url: URL, completion: @escaping (Result<Data,
Error>) -> Void) // ར༻ downloadData(from: url) { result in do { let data = try result.get() // data Λ͏ॲཧ } catch { /* ΤϥʔϋϯυϦϯά */ } }
async/await ʹΑΔඇಉظؔ // એݴ func downloadData(from url: URL) async throws
-> Data // ར༻ do { let data = try await downloadData(from: url) // data Λ͏ॲཧ } catch { /* ΤϥʔϋϯυϦϯά */ }
࿅श༻ϦϙδτϦ h"ps:/ /github.com/koher/swi4-zoomin-8
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
Q1: ղྫ
async ؔ async ؔͷதͰ͔͠ݺͼग़ͤͳ͍ func foo() async func bar() async
{ await foo() // ✅ OK }
async ؔ async ؔͷதͰ͔͠ݺͼग़ͤͳ͍ func foo() async func bar() {
await foo() // ⛔ NG }
async ؔ async ؔͷதͰ͔͠ݺͼग़ͤͳ͍ func foo() async func bar() async
{ await foo() // ✅ OK } func baz() async { await bar() // ✅ OK } ...
async ؔΛ࠷ॳʹݺͼग़͢ͱ͖ʁ
ಉظ͔ؔΒͷ async ؔͷݺͼग़͠ override func viewDidAppear(_ animated: Bool) { super.viewDidAppear(animated)
await foo() // ⛔ NG }
ಉظ͔ؔΒͷ async ؔͷݺͼग़͠ override func viewDidAppear(_ animated: Bool) { super.viewDidAppear(animated)
Task { await foo() // ✅ OK } }
ಉظ͔ؔΒͷ async ؔͷݺͼग़͠ override func viewDidAppear(_ animated: Bool) { super.viewDidAppear(animated)
Task(operation: { await foo() // ✅ OK }) }
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
Q2: UserViewController.viewDidAppear UserViewController User ͷใΛऔಘͯ͠දࣔ͢Δ View Controller Ͱ͢ɻ viewDidAppear
ͷதͰ downloadData ؔΛ ͍ɺ User ͱΞΠίϯΛऔಘͯ͠දࣔ͠·͢ɻ ͜ΕΛɺ async/await Ͱ࣮͞Εͨ downloadData ؔΛར ༻ͯ͠࠶࣮ͯ͠Լ͍͞ɻ
Q2: ղྫ
Actor ͱ
Actor ΫϥεʹࣅͨࢀরܕͰɺσʔλڝ߹ Λ͙ͨΊͷϘΠϥʔϓϨʔτ͕ෆཁʹͳ Δɻ ͦͷͨΊɺίʔυ͕؆͔ܿͭ҆શʹͳΔɻ
σʔλڝ߹ͱ
Χϯλʔͷσʔλڝ߹ final class Counter { private var count: Int =
0 func increment() -> Int { count += 1 return count } }
Χϯλʔͷσʔλڝ߹ let counter: Counter = .init() Task { print(counter.increment()) //
? } Task { print(counter.increment()) // ? }
Χϯλʔͷσʔλڝ߹ let counter: Counter = .init() Task { print(counter.increment()) //
1 } Task { print(counter.increment()) // 2 }
Χϯλʔͷσʔλڝ߹ let counter: Counter = .init() Task { print(counter.increment()) //
2 } Task { print(counter.increment()) // 1 }
Χϯλʔͷσʔλڝ߹ let counter: Counter = .init() Task { print(counter.increment()) //
2 } Task { print(counter.increment()) // 2 }
Χϯλʔͷσʔλڝ߹ final class Counter { private var count: Int =
0 func increment() -> Int { count += 1 Thread.sleep(forTimeInterval: 1.0) return count } }
Χϯλʔͷσʔλڝ߹ let counter: Counter = .init() Task { print(counter.increment()) //
1 } Task { print(counter.increment()) // 1 }
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 } }
σʔλڝ߹ͷରԠํ๏ • ϩοΫ • ʢ DispatchQueue ͷʣγϦΞϧΩϡʔ
γϦΞϧΩϡʔʹΑΔσʔλڝ߹ͷղফ 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) } } }
γϦΞϧΩϡʔʹΑΔσʔλڝ߹ͷղফ let counter: Counter = .init() Task { counter.increment {
print($0) } // 1 } Task { counter.increment { print($0) } // 2 }
γϦΞϧΩϡʔʹΑΔσʔλڝ߹ͷղফ 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) } } }
σʔλڝ߹ͷରԠํ๏ • ϩοΫ • ʢ DispatchQueue ͷʣγϦΞϧΩϡʔ • Actor
Actor ʹΑΔσʔλڝ߹ͷղফ final class Counter { private var count: Int
= 0 func increment() -> Int { count += 1 return count } }
Actor ʹΑΔσʔλڝ߹ͷղফ actor Counter { private var count: Int =
0 func increment() -> Int { count += 1 return count } }
Actor ʹΑΔσʔλڝ߹ͷղফ let counter: Counter = .init() Task { print(await
counter.increment()) } Task { print(await counter.increment()) }
Q3: BankAccount.deposit ࣍ͷΑ͏ͳ BankAccount ΫϥεΛ࣮͠ɺฒߦʹ༬ۚ͢Δ͜ͱ Ͱσʔλڝ߹͕ൃੜ͢Δ͜ͱΛ֬ೝͯ͠Լ͍͞ɻͦͷޙɺ BankAccount Λ actor ʹมߋ͠ɺσʔλڝ߹͕ࢭ͞ΕΔ͜ͱ
Λ֬ೝͯ͠Լ͍͞ɻ final class BankAccount { // ۜߦޱ࠲ var balance: Int = 0 // ༬ۚߴ func deposit(_ amount: Int) -> Int // ೖۚʢΓߴʣ }
Q3: ղྫ
Actor ͷಉҰΠϯελϯεͰͷϝιουݺͼग़͠ actor A { func foo() { ... }
func bar() { foo() // ಉظ } } await foo() // ඇಉظ
Q4: BankAccount.getInterest BankAccount ʹ getInterest ϝιουΛ࣮ͯ͠Լ͍͞ɻ getInterest ϝιου࣍ͷΑ͏ͳγάωνϟΛ࣋ͪɺҾͰ རΛड͚औΓɺͦΕΛݩʹརଉΛܭࢉͯ͠༬ۚߴΛมಈͤ͞ ্ͨͰɺ৽͍͠༬ۚߴΛฦ͢ͷͱ͠·͢ɻͨͩ͠ɺ༬ۚߴ
ͷมಈʹ deposit ϝιουΛར༻͢Δͷͱ͠·͢ɻ func getInterest(with rate: Double) -> Int
Q4: ղྫ
Actor ͷΠϯελϯεؒͰͷϝιουݺͼग़͠ actor A { func foo() { ... }
} actor B { func bar(a: A) async { await a.foo() // ඇಉظ } }
Actor ͷΠϯελϯεؒͰͷϝιουݺͼग़͠ actor A { func foo() { ... }
func bar(a: A) async { foo() // ಉظ await a.foo() // ඇಉظ } }
Actor ͷΠϯελϯεؒͰͷϝιουݺͼग़͠ actor A { func foo() { ... }
func bar(a: A) async { self.foo() // ಉظ await a.foo() // ඇಉظ } }
Actor ͷΠϯελϯεؒͰͷϝιουݺͼग़͠ actor A { func foo() { ... }
func bar(a: A) async { foo() // ಉظ await a.foo() // ඇಉظ } }
Q5: BankAccount.transfer BankAccount ʹ࣍ͷೋͭͷϝιουΛՃͯ͠Լ͍͞ɻ • ޱ࠲͔Βग़ۚ͢ΔͨΊͷ withdraw ϝιου • ޱ࠲ؒͰૹۚ͢ΔͨΊͷ
transfer ϝιου // ߴ͕Γͳ͍߹ΤϥʔΛ throw func withdraw(_ amount: Int) throws -> Int // Γߴ func transfer(_ amount: Int, to account: BankAccount) async throws
Q5: ղྫ
Sendable
Sendable 3 actor ڥքΛ͑ͯΓͱΓͰ͖Δ͜ͱΛද͢ϓϩτίϧ 3 h$ps:/ /github.com/apple/swi6-evolu9on/blob/main/proposals/0302-concurrent-value-and-concurrent- closures.md
final class User { let id: ID var name: String
var age: Int ... }
actor A { let user: User = ... } let
a: A = ... Task { let user = await a.user user.age += 1 // ⛔ } Actor ͷΩϡʔͷ֎Ͱ Actor ͷ෦ঢ়ଶΛมߋͰ͖ͯ͠·͏
final class User: Sendable { let id: ID var name:
String var age: Int ... } ⛔ ࢀরܕͰ var ϓϩύςΟΛ࣋ͭͷͰίϯύΠϧΤϥʔ
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
public struct User: Sendable { public let id: ID public
var name: String public var age: Int ... } public ͩͱ໌ࣔతʹద߹ͤ͞Δඞཁ͋Γ
struct User: Sendable { let id: ID var name: NSString
var age: Int ... } ⛔ Sendable Ͱͳ͍ϝϯόʔΛ࣋ͭͷͰίϯύΠϧΤϥʔ
final class User: Sendable { let id: ID let name:
String let age: Int ... } ✅ ࢀরܕͰΠϛϡʔλϒϧͳΒ OK
final class User: Sendable { let id: ID let firstName:
String let familyName: String let age: Int var name: String { "\(firstName) \(familyName)" } ... } ✅ Computed Property Λ͍࣋ͬͯͯΠϛϡʔλϒϧͳͷͰ OK
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! } ... }
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! } ... }
actor Counter { private var count: Int = 0 func
increment() -> Int { count += 1 return count } } actor ҉తʹ Sendable ʹద߹
ϓϩτίϧʹద߹ͤ͞ΒΕͳ͍߹ʁ
actor Foo { func bar(_ f: (String) -> Int) {
// // ... } }
actor Foo { func bar(_ f: @Sendable (String) -> Int)
{ // // ... } } Ϋϩʔδϟϓϩτίϧʹద߹Ͱ͖ͳ͍ͷͰ @Sendable Λ͏
final class User { var name: String ... } let
user: User = ... Task { let name = user.name // } @Sendable Ϋϩʔδϟ Sendable ͳ͔͠ΩϟϓνϟͰ͖ͳ ͍ʢ Task.init ʹ͢Ϋϩʔδϟ @Sendable ʣ
var a = 42 Task { print(a) // ⛔ }
@Sendable ΫϩʔδϟมΛΩϟϓνϟͰ͖ͳ͍
var a = 42 Task { [a] in print(a) //
✅ } by-value ΩϟϓνϟՄೳ
None
Actor-isolated Context ͷҾܧ͗
@nonescaping, non-@Sendable ʢ context ΛҾ͖ܧ͙ʣ actor A { func foo(values:
[Int]) { // A values.forEach { value in // A } } }
@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))) } }
@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 Ͱͳ͍
Task.initʢ context ΛҾ͖ܧ͙ʣ actor A { func foo() { //
A Task { // @Sendable // A } } }
@_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
Task.initʢ context ΛҾ͖ܧ͙ʣ actor A { func foo() { //
A Task { // @Sendable // A } } }
Task.detachedʢ context ΛҾ͖ܧ͕ͳ͍ʣ actor A { func foo() { //
A Task.detached { // @Sendable // not A } } }
Actor-isolated Context ͷҾܧ͗ͷؔ͢Δ swi2-developers-japan ͰͷΓͱΓ11 11 h$ps:/ /discord.com/channels/291054398077927425/291054454793306112/890858321693769748
UserViewController
None
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) } } }
View Controller ʹϩδοΫΛॻ͖ͨ͘ͳ͍
ViewModel తͳΫϥεΛಋೖ
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 } }
Q6: UserViewState UserViewState ʹ loadUser ϝιουΛՃ͠ɺϢʔβʔ͓Α ͼϢʔβʔΞΠίϯΛऔಘ͢ΔίʔυΛ UserViewController ͔Βͯ͠Լ͍͞ɻ UserViewController
ʹ UserViewState ܕͷ state ϓϩύςΟΛ࣋ͨͤɺ state ͷঢ় ଶΛ View ʹө͢ΔΑ͏ʹͯ͠Լ͍͞ɻͳ͓ɺ͜ͷ Actor ʹؔ͋Γ·ͤΜɻ ! state.user Ͱͳ͘ state.$user ͱॻ͘͜ͱͰɺ user Λ Publisher ͱͯ͠औಘ͢Δ͜ͱ͕Ͱ͖·͢ɻ
Q6: ղྫ
loadUser Λฒߦʹݺͼग़ͯ͠େৎ͔ʁ
loadUser Ͱى͜ΓಘΔσʔλڝ߹ let data = try await downloadData(from: url) let
user = try JSONDecoder().decode(User.self, from: data) self.user = user // ͕͜͜ಉ࣌ʹ࣮ߦ͞ΕΔͱʁ
UserViewState Λ actor ʹ͍ͨ͠
Q7: actor UserViewState UserViewState Λ Actor ʹͯ͠Լ͍͞ɻ
Q7: ղྫ
Swi$ Concurrency Λͬͯ Publisher ΛߪಡͰ͖Δ
Publisher.values 5 for await value in publisher.values { ... }
5 h$ps:/ /developer.apple.com/documenta6on/combine/publisher/values-1dm9r
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
Q8: Publisher.values UserViewState ͷ user iconImage ͷߪಡΛɺ for await
Λ͏ܗͰॻ͖͑ͯԼ͍͞ɻ
Q8: ղྫ
await state ͷ await ͕ᓔಃ͍͠ for await user in await
state.$user.values { ... }
state ͷΩϡʔ͕ϝΠϯΩϡʔͳΒɾɾɾ
ܕΛ͑ͯΩϡʔͰอޢ͍ͨ͠
Global Actor 7 7 h$ps:/ /github.com/apple/swi6-evolu9on/blob/main/proposals/0316-global-actors.md
MainActor 8 8 h$ps:/ /github.com/apple/swi6-evolu9on/blob/main/proposals/0316-global-actors.md#the-main-actor
@MainActor @MainActor func foo() { // isolated // ϝΠϯεϨου }
@MainActor ͕༩͞ΕͨؔϝιουɺϓϩύςΟ MainActor ʹ actor-isolated
@MainActor @MainActor final class Foo { var value: Int =
42 // isolated func a() { // isolated // ϝΠϯεϨου } } @MainActor ͕༩͞ΕͨܕͷϝιουɺϓϩύςΟ MainActor ʹ actor-isolated
Q9: @MainActor UserViewState ʹ @MainActor Λ༩ͯ͠ɺ UserViewController ͱͷΓͱΓΛ MainActor ͷॲཧͱ
ͯ͠ѻ͑ΔΑ͏ʹͯ͠Լ͍͞ɻ
Q9: ղྫ
ObservableObject
UserViewState Λ ObservableObject ʹ final class UserViewState: ObservableObject { ...
}
UserViewState Λ ObservableObject ʹ • Swi%UI ͷҠߦΛݟਾ͑ͯ • Computed Property
@Published ʹͰ͖ͳ͍
UserViewState Λ ObservableObject ʹ • user iconImage Λݸผʹߪಡ͢ΔͷͰͳ͘ɺ objectWillChange9
Λߪಡ͢Δ 9 h$ps:/ /developer.apple.com/documenta6on/combine/observableobject/objectwillchange-2oa5v
Q10: ObservableObject UserViewState Λ ObservableObject ʹద߹ͤ͞ɺ user, iconImage Λݸผʹߪಡ͢ΔͷͰͳ͘ɺ objectWillChange
Λߪಡͯ͠ View ʹө͢Δܗʹमਖ਼ͯ͠Լ͍͞ɻ
Q10: ղྫ
Q10 Ͱ࣮ͨ͠ UserViewState Swi(UI Ͱͦͷ··ར༻Մೳ
Q11: Swi(UI UserViewController ͱಉ༷ͷݟͨɾڍಈΛ࣮ݱ͢Δ UserView Λ Swi%UI Ͱ࣮ͯ͠Լ͍͞ɻ ! @StateObject
Ͱ UserViewState Λอ࣋͠·͢ɻ @StateObject private var state: UserViewState
Q11: ղྫ