【2024年4月】弊社では、基本リモートワークで一緒に成長してくださるメンバーを広く募集させていただいております。 詳細はこちら

【Swift】非同期処理とエラーハンドリングをSwift Concurrency(async/await)を使って実装する方法を徹底解説!

【Swift】非同期処理とエラーハンドリングをSwift Concurrency(async/await)を使って実装する方法を徹底解説!
ふくしま

どうも〜、株式会社メモリアインクのふくしまです!
記事をご覧いただきありがとうございます!

今回はSwift 5.5で導入されたasync/await を使って、非同期処理の実装の方法を解説していきます。

この記事を読んで分かること…
・Swift Concurrencyとは?
・async/awaitを使った非同期処理の実装方法
・エラー処理の定義方法
・並列処理の実行方法

目次

Swift Concurrencyとは?

Swift Concurrencyについて

Swift Concurrencyとは、Swift言語における非同期プログラミングを簡単に、安全に行うための機能群です。Swift 5.5で導入されたこの機能は、コードの可読性を保ちつつ、非同期処理を効率的に実行できるように設計されています。
async/awaitもその機能群の一つです。

async/awaitの基本

async/awaitは、非同期処理を「同期処理のように」書けるようにするSwiftの機能です。asyncキーワードを関数に追加することで、その関数は非同期関数となり、awaitキーワードを使ってその関数の実行結果を待つことができます。

async/awaitを使った非同期処理の実装方法

非同期処理の実装

次の例は、簡単な非同期関数の実装を示しています。この関数は、非同期にデータをフェッチし、結果をコンソールに表示します。
エラーハンドリングについては、次の項目で解説するとして、今回はエラーを出さないシナリオを想定します。

import Foundation

// 非同期関数の定義
func fetchData() async -> String {
    try? await Task.sleep(nanoseconds: 1_000_000_000) // 1秒(1,000,000,000ナノ秒)待つ
        return "データ取得完了"
}

// 非同期関数の使用
Task {
    let result = await fetchData()
    print(result) // コンソールに「データフェッチ完了」と表示される
}

コードの説明


非同期処理の実装は、func fetchData() async のようにして定義する関数名の後ろにasync キーワードをつけて、ブロック内に非同期処理を定義します。
ブロック内の非同期処理は、Task.sleep(nanoseconds:)を使用して、1秒間(ナノ秒で指定する)の待機を行っています。ここでは、fetchData() がエラーを出さないシナリオと想定して、try? を使って、待機中のエラーを無視しています。
定義した非同期関数を使用する場合は、10行目のようにTaskを使用してfetchData関数を実行し、その結果を待ちます。Task { ... }ブロック内でawaitを使用することで、非同期関数の呼び出しと結果の取得を行っています。
非同期処理が完了すると、変数result に結果が格納され、コンソールに「データフェッチ完了」と表示されます。

ログの出力結果:
データ取得完了

エラー処理の実装方法

非同期処理におけるエラー処理は、throwsキーワードとtry/catch構文を使用して行います。

import Foundation

// エラーを投げる可能性のある非同期関数
func fetchWithError() async throws -> String {
    try await Task.sleep(nanoseconds: 1_000_000_000) // 1秒待つ
    throw URLError(.badServerResponse) // 意図的にエラーを投げる
}

// エラー処理を含む非同期関数の使用
Task {
    do {
        let result = try await fetchWithError()
        print(result)
    } catch {
        print("エラー発生: \(error)")
    }
}

コードの説明

エラーを投げる可能性のある非同期関数を定義する場合、先ほど解説したエラーを出さない定義方法にthrows キーワードを追記して、呼び出し元にエラーハンドリングを委ねます。
fetchWithError() 関数ではthrow で意図的にエラーを投げています。
呼び出し側の処理(Task { ... }ブロック内)でdo-catch構文を利用して、doブロック内に非同期処理が正常終了した場合の処理、catchブロック内でエラーが発生した場合のハンドリングを定義しています。

出力結果:
エラー発生: Error Domain=NSURLErrorDomain Code=-1011 “(null)”

並列処理の実装方法

最後に複数の非同期タスクを並列に実行する方法を見てみましょう。

import Foundation

// 非同期関数の定義
func firstFetchData() async -> String {
        try? await Task.sleep(nanoseconds: 1_000_000_000) // 1秒待つ
        return "1つ目のデータフェッチ完了"
}

func secondFetchData() async -> String {
        try? await Task.sleep(nanoseconds: 2_000_000_000) // 2秒待つ
        return "2つ目のデータフェッチ完了"
}

// 非同期関数の並列実行の定義
func fetchMultipleData() async {
    await withTaskGroup(of: String.self) { group in
        group.addTask { await firstFetchData() }
        group.addTask { await secondFetchData() }
        
        for await result in group {
            print(result)
        }
    }
}

Task {
    await fetchMultipleData()
}

コードの説明

上記の例では、withTaskGroup(of:)を使用してfirstFetchData()secondFetchData() の2つの処理を並列に実行し、その結果を待っています。
この場合、1秒+2秒の待機の処理を並列に実行し、それらのタスクが完了次第、結果をコンソールに表示します。

出力結果:
1つ目のデータフェッチ完了
2つ目のデータフェッチ完了

まとめ

Swiftのasync/awaitは、非同期プログラミングをより簡単かつ直感的に行うための強力なツールです。この記事を通じて、async/awaitの基本的な使い方から、エラー処理、並列処理の実行方法までを学びました。async/awaitを使いこなすことで、より読みやすく、効率的な非同期コードを書くことができるようになります。
この記事が皆様の開発ライフの一助になれれば幸いです!

ふくしま

この記事があなたのスキルアップに役立ったなら、次のキャリアステップを踏み出す絶好の機会かもしれません。エンジニアとしてのさらなる成長と挑戦を求めるなら、
未経験からIT・Webエンジニアを目指すなら【ユニゾンキャリア】
をオススメします!

よかったらシェアしてね!
  • URLをコピーしました!
  • URLをコピーしました!

この記事を書いた人

コメント

コメントする

目次