Swift5.5で非同期処理に大幅な追加が行われました。
非同期処理でお馴染みのasync、await、
そして非同期処理に欠かせない排他制御の為のactorです。
async/await
await
async/awaitとよく言われますがawaitから説明します。
awaitは非同期処理を実行する際に使用します。
await Task.sleep( 1 * 1000 * 1000 * 1000 )
awaitをつけて呼び出したメソッドは非同期処理されます。
メソッドを呼び出した側の処理は一時停止されメソッドの終了を待ちます。
呼び出されたメソッドは異なるスレッドで処理が行われます。
メソッドが終了し次第、元のスレッドに戻り続きの処理が行われます。
async
asyncは非同期処理を行うメソッドを宣言する際に使用します。
awaitを使用する場合はメソッドにasyncを付けなければなりません。
func sleep5sec() async {
await Task.sleep(5 * 1 * 1000 * 1000 * 1000)
}
※View内に宣言した場合は非同期で動作しますが、他で宣言した場合はactorも同時に必要になります。
Task
非同期処理を行うにあたってTaskというものがあります。
awaitを使用する際にasyncなメソッド外から呼び出す際はTaskで括る必要があります。
Task{
await Task.sleep(5 * 1 * 1000 * 1000 * 1000)
print("待つ")
}
print("待たない")
Task内の処理はawaitの待ちが発生しますが、
Task外はawaitの終了を待つことなく進行していきます。
async/awaitについて詳しくはこちら
Actor
actorを使うことで排他制御が行われます。
async/awaitを使う中で共に使っていく事になります。
actorとして宣言する方法と属性 (attribute) として扱う方法があります。
actorとして宣言する
まずは actorとして宣言する方法です。
このように宣言するとクラス内が同一Actorとして扱われます。
actor TestModel{
var count = 0
func countUp(){
sleep(5)
count += 1
}
}
このようにactorとして宣言された場合は、
actor外からアクセスする場合は非同期でなければなりません。
let testModel = TestModel()
await testModel.countUp()
await print(testModel.count)
属性 (attribute) として扱う
次に属性として扱う方法です。
@globalActor
actor MyActor {
static let shared = MyActor()
}
class TestModel2:ObservableObject{
@MainActor @Published var count = 0
@MyActor
func countUp() async {
sleep(5)
await MainActor.run{
count += 1
}
}
}
MainActorが用意されている事に加え、カスタム属性を用意することもできます。
@ActorNameの用にしてクラス、変数、メソッドをマークする事が出来ます。
こちらも同様に異なるActorからアクセスする場合は非同期でなければなりません。
Actorで重要なのは排他制御に関してです。
同一Actorの処理は同時に実行されません。
複数のスレッドから同時に呼び出しても同一Actorの処理は同時に進行せず、
順に処理が行われていきます。
Actorの詳細についてはこちら
非同期処理とシミュレータ
シミュレータで非同期処理を行うと想定と異なる動作をする場合があります。
なにかおかしいと思った場合は実機でも試してみましょう。
詳しくはこちら
最後に
非同期処理についてはしっかり説明すると長くなるので、
ざっくりとまとめた記事を用意しました。
async、await、actorはとても便利な機能であり、
上手く使うことでDispatchQueueなどより簡単に処理を書ける事も多いと思います。
iOS15からの機能なので、すぐに実用できるとは限りませんが、
使用できる機会があれば是非使ってみてください。
コメント
[…] 【Swift】非同期処理について(async、await、actor)Swift5.5で非同期処理に大幅… […]