SIMPLE

SwiftDataとSwiftDependenciesを同時に使おうとしたら詰まった話

SwiftDataをSwiftUIのView外で使う方法SwiftDependenciesの相性問題が発生した話

SwiftDataのクエリはView上で定義したくないので、Managerクラスでクエリを実装していくことにすると、modelContainermodelContextをManagerに保持する必要がある。しかし、context.mainContainerはMain Actorの産物なので、Managerのinitメソッドに@MainActorを付与する必要がある。それが冒頭1つ目のリンクが示すソリューションなのだが…

この時、ManagerクラスをSwift-DependenciesのDIコンテナで保持しようとすると上手くいかない。

import Dependencies

private enum AppDataServiceKey: DependencyKey {
    static let liveValue: any AppDataServiceProtocol = AppDataService() // <- Syntax Error! "Call to main actor-isolated initializer 'init()' in a synchronous nonisolated context"
}

extension DependencyValues {
    var appDataService: any AppDataServiceProtocol {
        get { self[AppDataServiceKey.self] }
        set { self[AppDataServiceKey.self] = newValue }
    }
}

調べてみるとライブラリのリポジトリにディスカッションがあった。
https://github.com/pointfreeco/swift-dependencies/discussions/310

However, typically one does not need to make the dependency itself @MainActor, and instead it can hold onto something that is @MainActor and provide @MainActor endpoints for accessing its state. I would suggest exploring ways of designing your dependency that does not require a @MainActor initializer, and then things should work just fine.

とのことで、結論は、Dependency側に@MainActorを付与しなくてもいい方法を模索してね、とのこと。

対処療法としては、

  1. @EnvironmentプロパティラッパーをDIコンテナの代わりにする
  2. Viewのinit引数でバケツリレーする

のどちらかを採るしかない。

SwiftDataのmodelContainerをMainActorに依存せずに取得する方法は無いものか・・・。

nafell

大学生、26卒エンジニア志望。アプリ開発サークルを設立し、lounas.jpのバックエンド・DB設計を行いました。2年後期にインターンで設計の手法(要件定義~詳細設計)を学び、IoTシステムの調査・開発を行いました。