気になる英文記事を引用して記事を書いてみました。
引用元の記事は、タイトルが「Getting Started with async/await in SwiftUI(SwiftUI Concurrency Essentials)」とありましたので、引用しながら考察してみます。
Without a doubt, one of the biggest announcements at WWDC21 was Swift Concurrency, most notably the support for async/await.
As developers, we’re constantly faced with the asynchronous nature of the apps we write. Reading a file from disk, fetching data from a remote API on the web, and even getting input from the user - all of these are asynchronous operations. Throughout the years, many different ways to deal with asynchronous code have been implemented - most iOS developers will be familiar with Grand Central Dispatch, completion handlers, or delegates.
The new Swift Concurrency model builds on threads, but abstracts away from them.
上記の部分は、記事の序論になります。箇条書きで要約すると、
- WWDC21での最大の発表の1つは、
Swift Concurrency
、特にasync/await
のサポートである - 長年にわたり、非同期コードを扱う多くの異なる方法が実装されてきていた
- 新しい
Swift Concurrency
モデルは、スレッドをベースにしているが、スレッドから抽象化されている
となりますでしょうか。引き続き、引用記事を見ていきます。
Using URLSession and async/await
URLSession is among the many APIs that have been upgraded to support async/await, so fetching data is now a simple one-liner:
let (data, response) = try await URLSession.shared.data(for: urlRequest)
With some minimal level of error handling and JSON parsing (powered by Codable), the code for fetching the details about a word looks like this:
private func search(for searchTerm: String) async -> Word {
// build the request
let request = buildURLRequest(for: searchTerm)
do {
let (data, response) = try await URLSession.shared.data(for: request)
guard let httpResponse = response as? HTTPURLResponse, httpResponse.statusCode == 200 else {
throw WordsAPI.invalidServerResponse
}
let word = try JSONDecoder().decode(Word.self, from: data)
return word
}
catch {
return Word.empty
}
}
Note that we marked our search(for searchTerm: String) method as asynchronous by appending async in the method signature. This means we’ll have to use await whenever we call this method. Doing so indicates a so-called suspension point, and gives the runtime the opportunity to suspend the currently executing function. A suspended function is “put on hold” until the function it called returns. While the function is suspended, the thread it was executing on can be used to execute other code in your application.
上記の部分は、URLSession
とasync/await
の使用法について、実際のコードを用いて、説明しています。
中身をかいつまんで箇条書きにすると、
-
URLSession
はasync/await
をサポートするためにアップグレードされた多くのAPIのうちの1つ - searchメソッドのsignatureに
async
を追加して、非同期としてマークすることが必要 - searchメソッドを呼び出すときは常に
await
を使用しなければならない。これはいわゆるsuspension pointであり、ランタイムに現在実行中の関数を一時停止させる機会を与えるものである - サスペンドされた関数は、それが呼び出した関数が戻るまで「保留」にされる
- 関数が一時停止している間、その関数が実行されていたスレッドは、アプリケーションの他のコードを実行するために使用することができる
といったところでしょうか。
Calling asynchronous code from SwiftUI …
The final piece of the puzzle is how to call our asychronous code from SwiftUI. There are many different places you might call from:
- When the view appears
- When the user taps on a button
- When the user pulls to refresh
- In response to a search request
- Based on a notification
- Based on a timer
Let’s look at a few of these to understand the different mechanisms we can use.
上記の分はこんな時に、SwiftUIから非同期コードを呼び出したいよねといった内容です。
- ビューが表示されたとき
- ユーザーがボタンをタップしたとき
などが挙げられています。
上記の2パターンに関して、実際のコードを交えた記載がありますので引用します。
… when the view appears
This is probably the most common time to fetch data, and you might have been using the onAppear view modifier in your existing SwiftUI apps to trigger fetching data. We can still use onAppear, but the compiler will complain that we cannot call an asynchronous function here.
One solution to this problem is to create a new Task:
struct WordDetailsView: View {
...
var body: some View {
List {
...
}
.navigationTitle(word)
.onAppear {
Task {
await viewModel.executeQuery(for: word)
}
}
}
}
This works well, but there is an even better solution: because fetching data when a view appears is so common, SwiftUI has a new view modifier that will automatically create a new Task and cancel the task when the view disappears:
struct WordDetailsView: View {
...
var body: some View {
List {
...
}
.navigationTitle(word)
.task {
await viewModel.executeQuery(for: word)
}
}
}
… when the user taps a button
Sometimes, we want to execute asynchronous code in response to a button tap. In Xcode 13b1, most of the button action handlers do not support calling asynchronous code, so we need to create a new asynchronous context by calling async ourselves:
.toolbar {
ToolbarItem(placement: .primaryAction) {
Button("Refresh") {
Task {
await viewModel.refresh()
}
}
}
}
上記の記載に関しては、コードを見れば内容が頭に入ってくる人も多いのではないでしょうか。とにかく、Task
を忘れないでねくらいのテンションで書かれている気がします。
非同期処理を行う上では、Rxswift
やCombine
を用いているエンジニアが圧倒的に多いかと思います。(コードが見やすいという点ではCombine
の方がちょっと上手かなと個人的には思っています)
しかしながら、最近英文記事を検索しているとasync/await
の記事をよく目にします。それほど、注目度が高いのであればしっかりと習得したいなと、今回の記事を読んで強く思いました。
引用文献
- 記事タイトル:Getting Started with async/await in SwiftUI
- 引用元URL:https://peterfriese.dev/posts/swiftui-concurrency-essentials-part1/
- 最終アクセス:2022.01.23