Closed5
Swift Strict Concurrency 対応のメモ
classの代わりにactor使うとテストでスタブ/モックの注入できなくない?継承によるテストダブルの実現が封じられてしまう。
Swift 6 への移行セッションでもLocationManagerとかはMainActorにしてたけど、xxContainerとかの「テストでサブクラスしたそうやけど、参照セマンティクスの必要そうなもの」は、classを維持しつつ、MainActorに準拠させるのが良さそう〜。
そもそもManager系クラスって、俺は恥ずかしながらスレッドセーフをあまり気にせず使ってたけど、これまで大概はメインスレッドから呼ばれていたはずだし、スレッドセーフを考えている方でもメインスレッドからのアクセスに限定するとかで、今はMainActorにしても9割5分のケースで何の問題もないと思うので、基本的にそうしちゃおうか
(ViewとかUIViewがMainActorなので、これはUIレイヤが適応するものでは?と構えちゃうのが良くないかも)
プライベートキューを使って排他制御を実装してた人も、今はactor
をマークするだけで良いし。
あと@MainActorをつけていても、その中でawaitキーワードをつけてメソッドを呼び出すと、明示的にMain Actorに隔離していない場合は別スレッドで動作するので、そこは安心して良い。
個人的なStrict Concurrency対応方針
基本
- 不必要な
var
をlet
にする - 基本的には値型を使う
- グローバル変数には注意する
- 自前で排他アクセスの仕組みを持っている場合は
Sendable
をマークする
応用
- 上記で対応しきれない
class
は基本的に@MainActor
をマークする.@MainActor class
は継承可能なので継承によるスタブ/モックの実現も楽にできる(重たい画像処理やAPIアクセスなどの非同期処理にすべきものを該当クラスでベタ書きしてないか気をつける.) - 特に継承によるテストダブルが必要ではない・独自スレッドで動作してほしい・参照セマンティクスが欲しい。が揃っていたら
actor
を使う - 外部モジュールや、まだ自分の実装がどうしてもStrict Concurrencyに対応できない場合は
preconcurrency
やMainActor.assumeIsolated
や@unchecked Sendable
を活用する - Swiftのasync/awaitはActor Reentrancyなので、サスペンド中でも同じメソッドが呼ばれうる。値を更新するようなメソッドは基本的に同期実装にしておけばセーフティ。もしくは、値を更新する箇所の処理を工夫して他の処理が並行して呼ばれていても問題ないようにしておく。
俺が「何の抽象化にもなっていないテスタビリティのためだけのインターフェース分離」が嫌いで、シンプルな継承とイニシャライザによる依存性注入でテストダブルを実現するのを好むので、1個目のコメントみたいな悩みが出たのかもしれない。
このスクラップは4ヶ月前にクローズされました