SHOEISHA iD

※旧SEメンバーシップ会員の方は、同じ登録情報(メールアドレス&パスワード)でログインいただけます

DeveloperZine(デベロッパージン)- エンジニアの意思決定を支える技術情報メディア ProductZine

CodeZine編集部では、現場で活躍するデベロッパーをスターにするためのカンファレンス「Developers Summit」や、エンジニアの生きざまをブーストするためのイベント「Developers Boost」など、さまざまなカンファレンスを企画・運営しています。

iOSエンジニアたちと振り返るWWDC

【WWDC2022直前!】WWDC2021で発表されたSwift Concurrencyを振り返る


4種類目の型、Actorによる並行処理で競合状態を解決

 SwiftにActorが実装されました。Actorを使うと後述する並行処理の問題をより安全に解決することができます。

 Actorはclass、struct、およびenumに続く4種類目のSwiftの型です。Actorはclassと同じく参照型であり、またprotocolの適合やextensionによる拡張という他の型と同じ操作が可能です。Actorを定義する際には下記のように定義します。

actor Counter { ... }

Actorの利点

 まずは並行処理をプログラムする際の競合状態の問題と、Actorがどのようにその問題を解決するかを説明します。

競合状態の問題

 並行処理の歴史的な問題として競合状態があります。これは、異なる2つ以上のスレッドが同時に同じデータに読み書きをしようとするデータ競合と呼ばれる現象によって起こります。下記の例では、Counterインスタンスの2回目のincrement()メソッドの呼び出しによって、2が出力されることを期待していますが、2つのincrement()メソッドが同時に実行されたため1が出力されてしまったことを示しています。

 このような問題があるため複数のスレッドから同じ可変変数にアクセスする際にはAtomics、Locks、およびSerial dispatch queueという技術が使われていました。しかし、これらの解決方法にも安全に可変変数を読み書きできるかはプログラマー次第であり、慎重にコーディングする必要があるという課題がありました。

Actorによる解決

 Actorを使って先述したコードを書き直したのが下記のコードになります。このようにActorを使うと、Actorが持つプロパティやメソッドへのアクセスにはawaitキーワードが必要となり、非同期なアクセスとなります。これは、Actorへのアクセスは2つ以上のスレッドから同時に行えないというActorの特徴からくるものであり、現在アクセス中のスレッドがある場合に別のスレッドからアクセスするとそのアクセスを待機することを示しています。つまり、Actorを使うと同時に1つのスレッドからしかActor内の可変変数にアクセスできなくなるため、データ競合が発生しなくなります。

 さらに、Actorを使うとデータ競合が起こりそうなコードがコンパイルエラーとなるため、ランタイム時に意図しない挙動になるのを予防できます。例えば、Actor変数の更新を別スレッドから行おうとするとコンパイルエラーとなります。

MainActor

 MainActorと呼ばれる特別なActorが存在します。MainActorでは定義されたメソッドの実行やプロパティの読み書きが必ずメインスレッド上にて行われることを保証します。MainActorを使用するには、下記のように@MainActorを使って型をやメソッドを定義します。ある型に対して@MainActorを使った場合はその型のプロパティやメソッド全てに適応され、プロパティやメソッドに対して@MainActorを使った場合はその箇所だけに適応されます。

@MainActor class AnyUI { .... }

@MainActor func updateUI() { ... }

@MainActor var count = 0

 下記の2つの理由から標準APIにあるUIViewやUIViewControllerなどのクラスとMainActorは相性が良いです。実際に、今回のアップデートから標準でUIViewやUIViewControllerはMainActorでマークされています。

  • UIViewやUIViewControllerはUIの描画を行う
  • Viewの更新は必ずメインスレッドから行う必要がある

 なお、MainActorはメインスレッドが既に実行中の処理がある場合に、メインスレッド以外から受け取ったメッセージは直ちに実行せずに一旦待機させます。そのためMainActorの呼び出しは非同期処理となるため、await anyUI.updateUI()というようにawaitキーワードが必要です。

おわりに

 Swift Concurrencyと一口に言ってもasync/await構文やActorなど、内包する概念はいくつもあります。本記事はWWDC21にて発表されていた内容を基に、それぞれに対して背景や提供される機能についてまとめました。Swift Concurrencyによって今後の開発体験が向上する期待感が高まっただけではなく、今まで気づかなかった並行処理に関する問題について考える機会にもなったのではないでしょうか。

 次回の記事では、Xcode Cloud、およびSwiftUIについてWWDC21にて発表されている内容をまとめる予定です。お楽しみに。

引用文献

この記事は参考になりましたか?

連載通知を行うには会員登録(無料)が必要です。
既に会員の方はを行ってください。
iOSエンジニアたちと振り返るWWDC連載記事一覧

もっと読む

この記事の著者

k-kohey(STORES 株式会社)(k-kohey)

 STORES 株式会社テクノロジー部門モバイル本部にて、STORES 決済 のiOSアプリ開発に従事。

※プロフィールは、執筆時点、または直近の記事の寄稿時点での内容です

この記事は参考になりましたか?

この記事をシェア

CodeZine(コードジン)
https://codezine.jp/article/detail/15663 2022/06/10 21:29

イベント

CodeZine編集部では、現場で活躍するデベロッパーをスターにするためのカンファレンス「Developers Summit」や、エンジニアの生きざまをブーストするためのイベント「Developers Boost」など、さまざまなカンファレンスを企画・運営しています。

新規会員登録無料のご案内

  • ・全ての過去記事が閲覧できます
  • ・会員限定メルマガを受信できます

メールバックナンバー