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
710
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
How Swift's Type System Guides AI Agents
koher
0
470
Swift Updates - Learn Languages 2025
koher
2
800
Swiftのstructとイミュータビリティ
koher
4
810
Swift 6のTyped throwsとSwiftにおけるエラーハンドリングの全体像を学ぶ
koher
4
6.3k
Swift Concurrency時代のiOSアプリの作り方
koher
15
9.8k
async/awaitやactorでiOSアプリ開発がどう変わるか Before & Afterの具体例で学ぶ
koher
9
7.9k
Swift Language Updates - Learn Languages 2021
koher
8
1.9k
先取り! Swift 6 の async/await
koher
15
4.2k
SwiftUIで勘違いした話
koher
1
3.1k
Other Decks in Programming
See All in Programming
変化を抱擁するドキュメントの作り方 - ビジネスルール駆動開発がもたらす、コードとの新しい関係
ioki
2
130
{ Android | Kotlin } Gradle Plugin in 2026
ryunen344
1
300
XHTMLが残したもの
yosuke_furukawa
PRO
2
640
一参加者から『中の人』へ 〜全通PHPerがブースに立って学んだ、カンファレンスを100倍楽しむコツ〜
wp_daisuke
0
140
Seeing Through Serverless: Observability for AWS Lambda with ADOT and CloudWatch Application Signals
seike460
PRO
1
130
AWS Step Functions 大規模並列の壁を越える / jaws-sonic-2026-niigata-step-functions
kasacchiful
PRO
1
430
Kiroで創り、AgentCoreで繋ぐ!AWSで実践する「AI-DLC」から「AIエージェント統合」までの最新地図
licux
3
480
What We Talk About When We Talk About XP
m_seki
2
450
DroidKaigi 2026 「個人開発という実験場: Android エンジニアが手にする4つの自由」
slashnephy
0
230
iOS開発×AI駆動開発 〜最近使って便利だったスキルの話〜
nogu66
0
140
信頼性の目標を誰も求めてない
shubox
0
500
【高い買い物LT会】初任給で話題の国産フィジカルAIを買った話
akagami
PRO
0
130
Featured
See All Featured
Data-driven link building: lessons from a $708K investment (BrightonSEO talk)
szymonslowik
1
1.3k
StorybookのUI Testing Handbookを読んだ
zakiyama
31
6.9k
GraphQLの誤解/rethinking-graphql
sonatard
75
12k
Skip the Path - Find Your Career Trail
mkilby
1
220
Un-Boring Meetings
codingconduct
0
410
No one is an island. Learnings from fostering a developers community.
thoeni
21
3.8k
Navigating Team Friction
lara
192
16k
A designer walks into a library…
pauljervisheath
211
25k
Distributed Sagas: A Protocol for Coordinating Microservices
caitiem20
333
23k
ラッコキーワード サービス紹介資料
rakko
1
4.8M
Save Time (by Creating Custom Rails Generators)
garrettdimon
PRO
32
4.7k
Neural Spatial Audio Processing for Sound Field Analysis and Control
skoyamalab
0
480
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: ղྫ