しめ鯖日記

swift, iPhoneアプリ開発, ruby on rails等のTipsや入門記事書いてます

Swift5.5のasync/awaitを試してみる

Swift5.5で登場したasync/awaitを試してみました。
async/awaitは非同期処理を簡単に書けるような機能で通信処理などの実装を書きやすくなります。

今までは通信などの非同期処理を実装する時、下のように完了後のメソッド(completion)を使って実装する事が主流でした。

func asyncMethod(completion: () -> ()) {
    // 通信などの非同期処理
    completion()
}

asyncMethod(completion: {
    // 完了後の処理
})

async/awaitを使って書き直すと下のようになります。
完了後の処理がcompletionではなくasyncMethodのすぐ下に書けるようになりました。

func asyncMethod() async {
    // 通信などの非同期処理
}

Task {
    await self.asyncMethod()
    // 完了後の処理
}

下のようにasyncMethodの戻り値を受け取る事もできます。

func asyncMethod() async -> String {
    return "OK"
}

Task {
    let result = await self.asyncMethod()
    print(result)
}

実行されるスレッドですが、Task内は元のスレッドとは別スレッドで実行されます。
具体的には下のようになります。

Task内のawaitまでの処理は同じスレッドで行われるという記述もあったのですが、検証したときは別スレッドになっていました。
この辺りは機会あれば詳しく調べてみようと思います。

func asyncMethod() async {
    print("asyncMethod: \(Thread.isMainThread)") // → false
}

print("1: \(Thread.isMainThread)") // → true
Task {
    print("2: \(Thread.isMainThread)") // → false
    await self.asyncMethod()
    print("3: \(Thread.isMainThread)") // → false
}

クラスに@MainActorを付けることでasyncのメソッドをメインスレッドで実行する事も可能です。

@MainActor
class Test {
    func test() {
        print("1: \(Thread.isMainThread)") // → true
        Task {
            print("2: \(Thread.isMainThread)") // → false
            await self.asyncMethod()
            print("3: \(Thread.isMainThread)") // → true
        }
    }
    
    func asyncMethod() async {
        print("asyncMethod: \(Thread.isMainThread)") // → true
    }
}