本記事は、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移行に向けて、少しでも参考になれば幸いです。