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 Concurrency / Introducing Swift...
Search
giginet
PRO
September 28, 2021
Technology
420
1
Share
Embed
Copy iframe code
Copy JS code
Copy link
Start on current slide
今日から使える実践的Swift Concurrency / Introducing Swift Concurrency
giginet
PRO
September 28, 2021
More Decks by giginet
See All by giginet
🀄️ on swiftc
giginet
PRO
0
630
15年メンテしてきたdotfilesから開発トレンドを振り返る 2011 - 2026
giginet
PRO
2
510
Claude Codeログ基盤の構築
giginet
PRO
7
4.8k
Inside of Swift Export
giginet
PRO
1
3.6k
Swiftビルド弾丸ツアー - Swift Buildが作る新しいエコシステム
giginet
PRO
0
3k
SwiftでMCPサーバーを作ろう!
giginet
PRO
3
500
Creating Intuitive Developer Tool in Swift
giginet
PRO
0
1.7k
Mergeable Libraryで 高速なアプリ起動を実現しよう!
giginet
PRO
2
8.8k
5分でわかるExplicitly Built Modules
giginet
PRO
2
2k
Other Decks in Technology
See All in Technology
【dbts2026】AIエージェントの 判断と探索を変える、 データベース エンジニアリング― 既存DBの処理と依存関係から作る、オペレーショナルオントロジー ―
shisyu_gaku
0
280
思考過程から秘密が漏れる:Amazon Bedrock上のKimi K3を5つの方法で攻めたら、25回中22回漏洩した話
yama3133
1
120
The Author Pays
hiccupps
0
150
An Introduction to Context Ontology Accelerator (teaching AI agents what your data means)
inariku
PRO
1
200
続・ソフトウェアアーキテクトのための意思決定術: Decision Readiness, Revisited — When AI Changes the Economics of Software Architecture
snoozer05
PRO
9
2.9k
Bots in Kiro Crew (One point of contact for ongoing work) | Kiro: Zero to Hero 12
inariku
PRO
1
120
Context Ontology Accelerator 入門 (業務データの意味を、AI エージェントに渡す)
inariku
PRO
3
620
業務でAWSをあまり使っていない私が、AWSへのモチベを保つ方法
smt7174
0
190
アラートを見直していたら営業組織への理解にちょっとだけ繋がった話
z63d
0
170
Content Mapper APIの応用例~CSS Modules、言語ファイル~
uhyo
2
640
cdkd (CDK Direct)
gotok365
4
290
evcc & Home Assistant
naltatis
0
530
Featured
See All Featured
Are puppies a ranking factor?
jonoalderson
2
4.2k
The Director’s Chair: Orchestrating AI for Truly Effective Learning
tmiket
1
350
How to Align SEO within the Product Triangle To Get Buy-In & Support - #RIMC
aleyda
2
1.9k
KATA
mclloyd
PRO
35
16k
Game over? The fight for quality and originality in the time of robots
wayneb77
1
330
Faster Mobile Websites
deanohume
310
32k
How to Think Like a Performance Engineer
csswizardry
28
2.9k
Into the Great Unknown - MozCon
thekraken
41
2.8k
Building Experiences: Design Systems, User Experience, and Full Site Editing
marktimemedia
1
660
Gemini Prompt Engineering: Practical Techniques for Tangible AI Outcomes
mfonobong
2
630
Bash Introduction
62gerente
615
220k
Accessibility Awareness
sabderemane
1
290
Transcript
ࠓ͔Β͑Δ࣮ફతSwift Concurrency @giginet 1
ࣗݾհ • @giginet • Core Contributor of Carthage/fastlane/ XcodeGen etc...
• https://github.com/giginet • https://twitter.com/giginet • ΫοΫύου(2015/4~) ϞόΠϧج൫ ෦ • ؾܰʹmention͍ͯͩ͘͠͞ʂ 2
iOSDC ͠·ͨ͠ େنͳΞϓϦͷϚϧνϞδϡʔϧߏͷ࣮ફ by giginet | τʔΫ | iOSDC Japan
2021 #iosdc - fortee.jp 3
ٕज़ސgiginet͞ΜΠϯλϏϡʔ ίϛϡχςΟ׆ಈOSS׆ಈͷ ൿ݃Λฉ͍ͯΈ·ͨ͠ | Money Forward Engineers' Blog 4
Agenda • Swift Concurrency·ͱΊ • جຊฤ • Structured Concurrency •
actor 5
• ࣮ફతSwift Concurrency • طଘͷΞϓϦͷҠߦ • Α͋͘Δ࣮ΛConcurrencyԽͯ͠ΈΑ͏ • callbackύλʔϯ •
Delegateύλʔϯ • RxSwiftͱͷڠௐ • σΟεΧογϣϯ 6
Swift Concurrency·ͱΊ ͍Ζ͍Ζࢿྉ͕͋ΔͷͰجຊͦͪΒΛݟΕྑ͍ɻࠓճ͠ ͍ํ͚ʹ͜ΕΛϕʔεʹ؆୯ʹઆ໌͍͖ͯ͠·͢ɻ • WWDC 2021ͷSwiftͷฒߦॲཧؔ࿈ͷηογϣϯҰཡ - Qiita •
async/awaitactorͰiOSΞϓϦ։ൃ͕Ͳ͏มΘΔ͔ Before & Afterͷ۩ମྫͰֶͿ - Speaker Deck • Swift Concurrency νʔτγʔτ 7
Swift Concurrencyجຊฤ 8
• Α͋͘ΔͭɻcallbackΛड͚औͬͯResultͰΒ͏ Before func downloadData(from url: URL, completion:@escaping (Result<Data, Error>)
-> Void) downloadData(from: url) { result in switch result { case .success(let data): // data Λ͏ॲཧ case .failure(let error): // ΤϥʔϋϯυϦϯά } } 9
After func downloadData(from url: URL) async throws -> Data do
{ let data = try await downloadData(from: url) // data Λ͏ॲཧ } catch { // ΤϥʔϋϯυϦϯά } 10
ྫ2 • ·ͣϢʔβʔσʔλͷJSONΛΒͬͯɺͦͷJSONΛσίʔ υɺͦͷதʹ͋ΔURL͔Βը૾Λऔಘ͢Δ 11
func fetchUserIcon(for id: User.ID, completion: @escaping (Result<Data, Error>) -> Void)
{ let url: URL = .init(string: "https://koherent.org/fake-service/api/user?id=\(id)")! downloadData(from: url) { data in // (1) do { let data = try data.get() let user = try JSONDecoder().decode(User.self, from: data) downloadData(from: user.iconURL) { icon in // (2) do { let icon = try icon.get() completion(.success(icon)) } catch { completion(.failure(error)) } } } catch { completion(.failure(error)) } } } 12
After func fetchUserIcon(for id: User.ID) async throws -> Data {
let url: URL = .init(string: "https://koherent.org/fake-service/api/user?id=\(id)")! let data = try await downloadData(from: url) let user = try JSONDecoder().decode(User.self, from: data) let icon = try await downloadData(from: user.iconURL) return icon } • Θ͔Γ͍͢ • खଓ͖తʹॻ͚Δ 13
ྫ3 • JSONͷதʹ2ͭͷը૾URLؚ͕·Ε͍ͯΔ(smallIconImage, largeIconImage) • ·ͣJSONΛऔಘ͠ɺؚ·ΕΔը૾Λฒߦ(Parallel)ͯ͠μϯ ϩʔυ͍ͨ͠ 14
• JSONͷऔಘޙʹը૾ͷऔಘʢґଘؔˠίʔϧόοΫͷ࿈ʣ • 2ͭͷը૾Parallelʹऔಘ͢Δඞཁ͕͋Δ • GCDͷDispatchGroupͳͲΛར༻ 15
! func fetchUserIcons(for id: User.ID, completion: @escaping (Result<(small: Data, large:
Data), Error>) -> Void) { downloadData(from: url) { data in // (1) do { let data = try data.get() let user = try JSONDecoder().decode(User.self, from: data) let group: DispatchGroup = .init() var smallIcon: Result<Data, Error>! group.enter() downloadData(from: user.smallURL) { icon in smallIcon = icon group.leave() } var largeIcon: Result<Data, Error>! group.enter() downloadData(from: user.largeURL) { icon in largeIcon = icon group.leave() } group.notify(queue: .global()) { do { let icons = try (small: smallIcon.get(), large: largeIcon.get()) completion(.success(icons)) } catch { completion(.failure(error)) } } } catch { completion(.failure(error)) } } } 16
After let url: URL = .init(string: "https://koherent.org/fake-service/api/user?id=\(id)")! let data =
try await downloadData(from: url) let user = try JSONDecoder().decode(User.self, from: data) async let smallIcon = try await downloadData(from: user.smallURL) async let largeIcon = try await downloadData(from: user.largeURL) let icons = try await (small: smallIcon, large: largeIcon) 17
Structured Concurrency • ෳͷasyncॲཧΛߏԽ࣮ͯ͠ߦ͢ΔΈ • Task • ্هͷྫͷΑ͏ʹෳͷλεΫΛฒߦͯ͠ߦͬͨΓ • ࢠλεΫΛ࡞ͬͨΓ
• Ωϟϯηϧͨ͠Γ • ͕ՄೳʹͳΔ 18
• swift-evolution/0304-structured-concurrency.md at main · apple/swift-evolution • Explore structured concurrency
in Swift - WWDC21 - Videos - Apple Developer 19
async-let • 1ͭͷTaskͰෳͷඇಉظॲཧ(ࢠλεΫ)ΛΒͤͯͪड͚ Ͱ͖Δ async let smallIcon = try await
downloadData(from: user.smallIconURL) // (foo) async let largeIcon = try await downloadData(from: user.largeIconURL) // (bar) // ͳΜ͔͍ॲཧ (Task) let icons = try await (small: smallIcon, large: largeIcon) 20
21
Task • ඇಉظؔTaskͰϥοϓ͢Δ͜ͱͰಉظͷੈք͔ΒͰ࣮ߦ Ͱ͖Δ • ಉظੈքͱඇಉظੈքͷڮ͠ʹ͑Δ func syncMethod() { Task
{ await doSomething() } } 22
Cancel func syncMethod() { let task = Task { await
doSomething() } task.cancel() } • TaskcancelͰ͖Δ • ϘλϯΛԡͨ͠ΒTaskΛൃՐ͢Δ͕ɺऴΘΔલʹΩϟϯηϧϘ λϯΛԡͨ͠ΒऴྃΈ͍ͨͳͷ͕ग़དྷΔ • ࢠλεΫ·ͱΊͯΩϟϯηϧ͞ΕΔ 23
AsyncSequence • asyncʹ͕औΕΔiterator • ϑΝΠϧI/Oͱ͔ • streamͱ͔(WebSocketͱ͔) • ࢠλεΫΛಈతʹ૿ͯ͠ɺiteratorͷΑ͏ʹѻ͑Δ Meet
AsyncSequence - WWDC21 - Videos - Apple Developer 24
actor • ඇಉظͷσʔλڝ߹Λղܾ͢Δ͘͠Έ • ॲཧΛඇಉظʹͨ͠ΓɺΩϡʔΛ੍ͨ͠ΓɺϩοΫͷऔಘΛ ࣗಈతʹͬͯ͘ΕΔ 25
σʔλڝ߹ͱ • ҎԼͷ߹ɺյΕͯ͠·͏ let counter: Counter = .init() DispatchQueue.global().async {
print(counter.increment()) // ? } DispatchQueue.global().async { print(counter.increment()) // ? } 26
actor Counter { private var count: Int = 0 func
increment() -> Int { count += 1 return count } } 27
• actorͷશͯͷϓϩύςΟϝιου͕ඇಉظʹͳΔͨΊɺ σʔλڝ߹͔ΒकΒΕΔ • actor෦ʹઐ༻ͷΩϡʔ(serial executor)Λอ͓࣋ͯ͠ΓɺӅ ṭ͞ΕΔ await counter.increment() 28
• GCDͰ࣮ݱ͠Α͏ͱ͢ΔͱɺϩοΫsemaphore͕ඞཁʹͳΔ final class Counter { private let queue: DispatchQueue
= .init(label: ...) private var count: Int = 0 func increment(completion: @escaping (Int) -> Void) { queue.async { [self] in count += 1 completion(count) } } } 29
Global Actor • actorͷ༻ΩϡʔΛಛఆͷΩϡʔʹ੍ݶ͢ΔͨΊͷ͘͠Έ • SEͰҙΩϡʔ͕ఏҊ͞Ε͍ͯΔ͕ɺݱࡏMainActorͷ Έ 30
@MainActor final class MyViewController: UIViewController { func doSomething() { }
} • actorͰͳ͘ɺطଘͷΫϥεʹ@MainActorΛ͚Δͱϝϯό͕ શ෦asyncʹͳΓϝΠϯεϨουͰ࣮ߦ͞ΕΔ 31
• ֎͔ΒϝιουϓϩύςΟ͕asyncʹݟ͑Δ • MainActorʹ͍Δͷͷத͔Β͔͋ͨಉظతʹݺΔ • MainActorҎ֎͔Βͷ࣮ߦΛ͋Δఔ͙͜ͱ͕ग़དྷΔ • UIͷߋ৽ͳͲɺϝΠϯεϨουҎ֎Ͱ࣮ߦ͞Εͯཉ͘͠ͳ͍ ͷΛؒҧͬͯݺͳ͍Α͏ʹίϯύΠϧ࣌ʹอޢ͢Δ͜ͱ ͕Ͱ͖Δ
32
@MainActor func reloadData() { // ϝΠϯεϨουͰ࣮ߦͯ͠ཉ͍͠ॲཧ } @MainActor final class
SomeViewController: UIViewController { override func viewDidLoad() { reloadData() } } func callReloadData() { let vc = SomeViewController() vc.reloadData() // ϝΠϯεϨουอূ͕ͳ͍ͷͰasync͡Όͳ͍ͱݺͳ͍ } 33
UIViewController • υΩϡϝϯτΛݟΔײ͡ɺUIViewControllerશͯ@MainActor ʹͳ͍ͬͯΔ • https://developer.apple.com/documentation/uikit/ uiviewcontroller?changes=latest_minor • ࣮ࡍʹ͜ΕΛΔͱଟ͘ͷϓϩμΫτͰޓੑ͕ҡ࣋Ͱ͖ͳ͘ ͳΔΑͳͱࢥ͍ͬͯΔɻͳΜ͔Έͨײ͡దԠ͞Εͯແͦ͞͏
ͰΑ͘Θ͔Βͳ͍ ! 34
35
class User { var name: String var age: Int }
actor Session { var currentUser: User? } 36
func run() async { let session = Session() let user
= await session.currentUser user?.age += 1 } 37
38
ͳͥʁ • UserࢀরܕͰࢀরઌͰ͕มΘΓ͏Δ • ෳͷλεΫͰࢀর͍ͯ͠Δؒʹ1ܦͬͯage͕૿͑ΔՄೳੑ ͕͋Δ • σʔλڝ߹ͷةݥੑ͕͋Δ 39
Sendable • ͜ͷܕ͕actorؒͰΓͱΓͰ͖Δ͜ͱΛprotocolʹ௨͢Δ protocol(marker protocol) • swift-evolution/0302-concurrent-value-and-concurrent- closures.md at main
· apple/swift-evolution 40
class User: Sendable { let user: String let age: Int
} • Sendableʹద߹͢Δ͜ͱͰίϯύΠϥʹ҆શʹड͚͠Ͱ͖Δ ܕͰ͋Δ͜ͱΛ௨ • ্هͷΑ͏ͳΠϛϡʔλϒϧΫϥε(varΛ࣋ͨͣʹҰ࡞ͬͨ ΒมΘΒͳ͍)SendableʹͰ͖Δ 41
• ͜ͷܯࠂXcode 13.0(Swift 5.5)ͷ࣌Ͱແޮʹͳ͍ͬͯΔ (؇͔ͳҠߦͷͨΊ) • Swift 6.0͔Βܯࠂ͕ඪ४Ͱग़ΔΑ͏ʹͳΔͷͰিܸʹඋ͑Δ • -warn-concurencyΦϓγϣϯͰܯࠂΛ༗ޮԽͰ͖Δ
42
• Swift ConcurrencyͷwithTaskCancellationHandlerͱSendable - cockscomblog? • Concurrency in Swift 5
and 6 - Evolution / Discussion - Swift Forums 43
Concurrencyͷར • ॲཧͷߏԽ • ॲཧͷྲྀΕΛಡΈԼ͍͍ͤͯ͢ • ݕࠪྫ֎ͷੵۃతͳ༻ • σʔλڝ߹ͷίϯύΠϧ࣌νΣοΫ •
࣮ߦεϨουͷίϯύΠϧ࣌νΣοΫ 44
Special Thanks • ͜͜·ͰͷεϥΠυͷ΄ͱΜͲ @koher ͞Μͷࢿྉͷ௨ΓͰ ͢ ! • ૉΒ͍͠ͷͰαϙʔτ͠·ͨ͠ɻ͋Γ͕ͱ͏͍͟͝·͢
45
໌͔Β͑ΔSwift Concurrency • طଘͷΞϓϦΛ෦తʹSwift ConcurrencyରԠ͍ͯ͘͠ςΫ χοΫ 46
Swift Concurrency backport • ݱࡏɺConcurrencyiOS 15Ҏ্Ͱ͔͠༻Ͱ͖ͳ͍͕ɺiOS 13 Ҏ্Ͱ༻Ͱ͖ΔΑ͏ʹ͢Δܭը͕͋Δ(backport) • swiftcʹϚʔδ͞Ε͍ͯΔ͕ɺXcode
13.0ͷஈ֊Ͱ༻ Ͱ͖ͳ͍ • ΞϓϦʹConcurrencyʹඞཁͳϥϯλΠϜΛΈࠐΜͰ͠· ͍ɺiOS 15ະຬͰ࣮ߦͰ͖ΔΑ͏ʹ͍ͯ͠ΔΒ͍͠ Add an option to build the concurrency library for back 47
Xcode 13 Release Notes | Apple Developer Documentation 48
طଘͷΞϓϦͷ࣮ફతͳasync/awaitԽ ͜ͷηογϣϯ͕ྑ͔ͬͨ Swift concurrency: Update a sample app - WWDC21
- Videos - Apple Developer 49
ߟ͑Δ͜ͱ • εϨουຖʹactorΛ • ϝΠϯεϨουͰͷ࣮ߦΛڧ੍͍ͨ͠ॲཧ(UI) • backgroundʹڲਖ਼͍ͨ͠ॲཧʢI/Oॏ͍ॲཧʣ • Ͳ͜ͰΑ͍ॲཧ •
asyncΠϯλʔϑΣΠεରԠ 50
51
52
53
• UIViewMainActorʹ • ֎෦ͱͷI/O(͜͜ͰHealthKit)actorʹͯ͠ඇಉظͰѻ͏ • ͲͷεϨουͰॲཧ͖͔͢Λ೦಄ʹΈସ͑Δͷ͕େࣄ 54
طଘͷ࣮ͷasyncԽ • Α͋͘Δૉͳඇಉظϝιου(completion) struct ImageDownloader { func downloadImage(url: URL, completion:
@escaping (Result<UIImage, Error>) -> Void) { var request = URLRequest(url: url) request.httpMethod = "GET" let task = URLSession.shared.dataTask(with: request) { (data, response, error) in if let error = error { completion(.failure(error)) } else { let image = data.flatMap(UIImage.init(data:)) ?? UIImage() completion(.success(image)) } } task.resume() } } 55
• withCheckedContinuation asyncͰͳ͍࣮Λϥοϓͯ͠؆୯ ʹasyncΠϯλʔϑΣΠεʹมͰ͖Δ public func withCheckedContinuation<T>(_ body: (CheckedContinuation<T, Never>)
-> Void) async -> T public func withCheckedThrowingContinuation<T>(_ body: (CheckedContinuation<T, Error>) -> Void) async throws -> T 56
@available(iOS 15.0, *) extension ImageDownloader { func downloadImage(url: URL) async
throws -> UIImage { try await withCheckedThrowingContinuation { continuation in downloadImage(url: url) { result in continuation.resume(with: result) } } } } 57
ࣗಈੜͯ͘͠ΕΔ • Editor > Refactor > Add Async Wrapper •
completion൛ͷϝιουʹasync interfaceΛੜ͢ • Editor > Refactor > Add Async Alternative • async൛ͷϝιουʹલํޓ༻ͷcompletion handlerΛੜ ͢ 58
59
Delegateύλʔϯͷasync/awaitԽ • جຊతʹಉ͡ͰCheckedContinuationΛอ࣋͢Δͱྑͦ͞͏ ྫɿURLSessionDataDelegateͷasync/awaitԽ 60
struct HTTPRedirectResolver { func resolve(_ url: URL) async throws ->
URL? { try await withCheckedThrowingContinuation { (continuation: CheckedContinuation<URL?, Error>) in let delegate = Delegate(activeContinuation: continuation) let urlSession = URLSession(configuration: .default, delegate: delegate, delegateQueue: nil) let request = URLRequest(url: url) urlSession.dataTask(with: request).resume() } } private class Delegate: NSObject, URLSessionDataDelegate { private let activeContinuation: CheckedContinuation<URL?, Error> init(activeContinuation: CheckedContinuation<URL?, Error>) { self.activeContinuation = activeContinuation } func urlSession(_ session: URLSession, task: URLSessionTask, willPerformHTTPRedirection response: HTTPURLResponse, newRequest request: URLRequest, completionHandler: @escaping (URLRequest?) -> Void) { let newURL = request.url activeContinuation.resume(returning: newURL) completionHandler(nil) } func urlSession(_ session: URLSession, dataTask: URLSessionDataTask, didReceive data: Data) { activeContinuation.resume(returning: dataTask.currentRequest?.url) } func urlSession(_ session: URLSession, task: URLSessionTask, didCompleteWithError error: Error?) { guard let error = error else { return activeContinuation.resume(returning: nil) } activeContinuation.resume(throwing: error) } } } 61
let resolver = URLRedirectResolver() let url = "http://moved-url.com" // redirect͢Δ
let redirectedURL = try await resolver.resolve(url) 62
RxͰͷ༻ • async/awaitΛObservableʹมͯ͠ڠௐͯ͑͠ΔΑ͏ʹ͢Δ 63
extension ObservableType { public static func create(throwingAsync callee: @escaping ()
async throws -> Element) -> Observable<Element> { Observable<Element>.create { observer in let task = Task { do { let result = try await callee() observer.onNext(result) } catch { observer.onError(error) } } return Disposables.create { task.cancel() } } } } 64
Observable.create { try async doSomething() } // Observable<T> .asDriver(onErrorJustReturn: [])
.drive(onNext: { _ in }) .dispose(by: disposeBag) • TaskΛ͏͜ͱͰasyncΛӅṭ͍ͯ͠Δɻಉظͷੈք͔Β͑Δ 65
ײɺٞ • ͍͑͟ΔΑ͏ʹͳͬͨΒ෦తʹऔΓೖΕ͍ͯ͘ͷ༰қͦ ͏ • VS Rx • ௨৴ͷͪड͚ͳͲʹRxΛར༻͍ͯ͠Δ߹ͳͲasync/ awaitʹஔ͖͑ͯγϯϓϧʹॻ͚ͦ͏͕ͩɺશʹஔ͖͑
ΒΕΔΘ͚Ͱແͦ͞͏ 66
• Actor • ࠓҎ্ʹUIͱͦΕҎ֎ͷͷ֊Խ͕ॏཁʹࢥ͑Δ • Viewશͯ MainActor ʹͯ͠͠·͍ɺnonisolatedͳॲཧ ࣋ͨͤͳ͍ੈք͕ΩϨΠͦ͏ 67
• ࠓback portͷ͕͋ͬͯɺطଘͷΞϓϦͰࠓ͙͢͏ͷ ͍͠ • Xcode 13.1ͱ͔ૣ͍ஈ֊Ͱಈ͘Α͏ʹͳΓͦ͏ͳ༧ײ • Development TargetΛiOS
15ʹͯ͠༡Ϳ͜ͱͰ͖ͨ 68
͝ਗ਼ௌ͋Γ͕ͱ͏͍͟͝·ͨ͠ 69