見出し画像

SwiftUIでいこう! - 非同期処理を考える。

JavaScriptの非同期処理を見てきましたがSwiftではどうでしょう。Swiftでもasync,awaitを使って非同期処理を行います。

同じようにasyncをつけた関数の中にawaitを着けて関数を指定します。

実際の使用例として上記参考サイトで例示してあります。

struct ContentView: View {
    
    @State var text = "Default"
    
    var body: some View {
        VStack {
            Text(self.text)
            Button("Wait"){
                self.text = "Waiting"
                Task{
                    self.text = await waitFunc()
                    print("waitFunc後に実行")
                }
                print("waitFuncと並列実行")
            }
        }
    }
    
    func waitFunc() async -> String {
        sleep(5)
        return "Finish"
    }
}

これを実行すると確かにボタン押せばうまく時間をおってコンソールに出力されます。

Swift Playgroundsで実行

下の方にコンソールの結果が出てきています。

同じことをDispatchQueueのコードも紹介されていて、実行すると同じように結果が出ることが確認できます。

Swiftの場合には安全に非同期処理をするために"Actor"というものを作っています。

SwiftUIで書く場合には

struct ContentView: View {
    
    @State var text = "Default"
    
    var body: some View {
        VStack {
            Text(self.text)
            Button("Wait"){
                self.text = "Waiting"
                Task{
                    let asyncClass = AsyncClass()
                    self.text = await asyncClass.waitFunc()
                    print("waitFunc後に実行")
                }
                print("waitFuncと並列実行")
            }
        }
    }
}

class AsyncClass{
    func waitFunc() async -> String {
        sleep(5)
        return "Finish"
    }
}

という感じでクラスを別立てで作ってそれを本体の"body"の中で使っていきます。

Task

上記サイトを参考に

func fetchHogeAPI() async throws -> Void {
    try await Task.sleep(nanoseconds: 1 * 1000 * 1000 * 1000)
    return ()
}

do {
    try await fetchHogeAPI()
} catch {
    print(error)
}

エラーが出ます。Taskを使います。

Task {
    do {
        try await fetchHogeAPI()
    } catch {
        print(error)
    }
    print("call2")
}

これでエラーが消えます。

Task.initで囲うとエラーが出なくなるのかですが、クロージャにはasyncがついているのでTaskのスコープの中ではawaitができると言うことになります。

"Task"とするとメインスレッドで実行されるがそれ以外で使いたいという場合は

Task.detached

を使う。

async let

並列で処理したい時に使うことができます。

基本の書き方は

async let resultNum1 = 実行したい関数1
async let resultNum2 = 実行したい関数2

let results = await (resultNum1, resultNum2)

async letで定義するところではawaitキーワードは不要で、その値を実際に使いたい時にawaitを記述します。


Task Group

Task Group の利用場面としては、
・実行時に決まる個数の処理を並行に行いたい
・それぞれの処理の結果の型がすべて同じ

https://qiita.com/maiyama18/items/a1aed9501b8ebfb94d5b

Task Group の生成にはwithTaskGroupと withThrowingTaskGroup があります。

async letとTask Groupの使い分け


上記以外でもいろんなところ、いろんな視点からまとめられていますのでご紹介。自分でわかりやすいところ、ポイントを掴んでいけば良いかなと思います。


この記事が気に入ったらサポートをしてみませんか?