本記事は、Swift Advent Calendar 2024の8日目です。
7日目は、@hinakkoさんのSplit Viewを考慮したSize Classを使用したiPad対応です。
HealthCare Innovation Group(HIG)1の橋本です。
先日参加したSwiftZoomin#20の内容から、Swift6移行に向けて理解が必要なSwift Concurrencyの重要な概念について簡単にまとめました。
SwiftZoomin#20の動画は、次のリンク先からYoutube上で視聴可能です。
Swift6移行に向けて、重要な概念3つ
以下3つの概念についてまとめいきます。
- Isolation domain
- Isolation boundary
- Sendable
Isolation domain
隔離=Isolationする領域のことをIsolation domainと呼びます。Isolation domainの重要な特性は、一つのIsolation domainのなかでは同時に一つの処理しか実行されないことです。(=一つのIsolation domainの中で並行実行されることはないことと同義)
参考
actor
actorというのは、一つの領域で隔離(Isolation)することでデータ競合を防いでいます。
最も馴染み深いのは、MainActorのIsolation domainであり、actorのインスタンスに紐づいたIsolation domainも存在します。
MainActorのIsolation domainはMain Actorで保護された領域を表します。Actorの場合は、ActorのインスタンスごとにIsolation domainをもち、同じactorでもインスタンスが異なれば、それぞれ異なるIsolation domainを持ちます。
actor Counter {...} |
参考
Isolation boundary
Isolation domainが複数存在しているときのそれぞれのIsolation domainの間の境界のことをIsolation boundaryと呼びます。
アプリにおいては、それぞれのIsolation domain間でIsolation boundaryを超えて情報のやり取りをしないといけない場面が多々あります。
このIsolation boundaryを超えて値を受け渡すために、次のSendableが必要になってきます。
Sendable
Sendable 並行にアクセスされても安全な型だけが準拠できるプロトコルSendableの特徴は、Sendableに準拠した型の値だけがIsolation boudnaryを超えられるようになります。
つまり、Sendableを使うことで実行時にデータ競合が起こらないことをコンパイル時にチェックできるように、型の問題とすることで実現しています。
non-Sendable
Sendableに対して、non-Sendableな値は、Isolation boundaryを超えることができません。
- Sendable | Apple Developer Documentation
- Sendable Types | Migrating to Swift 6
- Sendable Types | The Swift Programming Language
Sendableを体感する
上記のBoxクラスをSendableに準拠させて、並行にアクセス可能にさせてみる。
final class Box: Sendable { |
そうすると、次のようにSendableに準拠すること自体がエラーであることがわかります。Box型のプロパティValueが可変状態のため、並行にアクセスすると危険である旨のメッセージが出てきます。
Stored property 'value' of 'Sendable'-conforming class 'Box' is mutable |
ここで、varではなく、letだったらどうなるか考えてみます。
final class Box: Sendable { |
letにすることで、Boxクラスのエラーは解消されます。
valueプロパティが定数になるため、run()メソッド内でbox.balue = -1で書き込みをしていた箇所がコンパイルエラーになります。
この部分を読み込むだけのprint(box.value)とすれば、データ競合を起こさない安全なコードとすることができます。データ競合は、並行にアクセスする少なくとも1つで書き換えが起こっているときに生じるものであるため、今回のように読み込むだけであれば、データ競合の危険性はありません。
func run() { |
Isolation boundaryを体感する
Sendableに準拠していないnon-SendableなBoxクラスがIsolation boundaryを超えるとコンパイルエラーが出る例を示します。
final class Box { |
Sendableに準拠していないBoxクラスのboxインスタンスがIsolaton boudaryを超えたため、このエラーがでてきます。
このように、Isolaton boudaryが存在していることを体験することができました。
おわりに
SwiftZoomin#20(感覚的に理解するConcurrency: Swift 6はIsolationとSendableを用いてどのようにデータ競合を防止するか)動画前半の内容について私なりにまとめさせていただきました。(@koherさん、大変わかりやすく説明いただきありがとうございました。)
Swift6への移行は、コンパイル時にデータ競合が起こる可能性のある箇所を事前につぶすことができるので、アプリの品質向上に直結するため、ビジネス的にもとても有用なものだと思っております。
本記事がSwift6移行に向けて、少しでも参考になれば幸いです。