はじめに
表題のエラーに関して、発生時の状況と解決方法を記事に残します。
開発環境
- macOS Big Sur 11.2.3
- Xcode 12.4
- Swift 5.3.2
本題
エラー発生時の状況
sheetでEnvironmentObjectのデータをListに表示した状態で、行を編集しようとするとアプリがクラッシュし、表題のエラーが発生。
文章だと伝わりにくいため、以下表題のエラーが発生する雑なサンプルを作りました笑
SceneDelegate
import UIKit import SwiftUI class SceneDelegate: UIResponder, UIWindowSceneDelegate { var window: UIWindow? func scene(_ scene: UIScene, willConnectTo session: UISceneSession, options connectionOptions: UIScene.ConnectionOptions) { let contentView = ContentView() .environmentObject(Region()) if let windowScene = scene as? UIWindowScene { let window = UIWindow(windowScene: windowScene) window.rootViewController = UIHostingController(rootView: contentView) self.window = window window.makeKeyAndVisible() } } }
ContentView.swift
import SwiftUI struct ContentView: View { @State private var isModalActive = false var body: some View { Button(action: { self.isModalActive.toggle() }) { Text("モーダルビューを表示する") } .sheet(isPresented: $isModalActive) { ModalView() } } } struct ContentView_Previews: PreviewProvider { static var previews: some View { ContentView() } }
ModalView.swift
import SwiftUI struct ModalView: View { @EnvironmentObject private var region: Region var body: some View { NavigationView { List { ForEach(region.names, id: \.self) { region in Text(region) } .onDelete { indexSet in region.names.remove(atOffsets: indexSet) } .onMove { indexSet, toOffset in region.names.move(fromOffsets: indexSet, toOffset: toOffset) } } .listStyle(InsetGroupedListStyle()) .navigationTitle("地方") .navigationBarTitleDisplayMode(.inline) .toolbar { EditButton() } } } } struct ModalView_Previews: PreviewProvider { static var previews: some View { ModalView() } }
Region.swift
import Foundation class Region: ObservableObject { @Published var names = ["北海道", "東北", "関東", "中部", "近畿", "中国", "四国", "九州"] }
エラーの解決方法
ContentView.swiftに実装されたsheetの実装を以下に変更する。
変更前
.sheet(isPresented: $isModalActive) { ModalView() }
変更後
.sheet(isPresented: $isModalActive) { ModalView() .environmentObject(Region()) }
まず、前提としてEnvironmentObjectは、親ビューまたは祖先のビューによって提供される監視可能なオブジェクトのプロパティラッパータイプです。
※参考:https://developer.apple.com/documentation/swiftui/environmentobject
今回のサンプルでは、ContentViewを親ビューと想定してEnvironmentObjectを利用していました。しかし、以下の記事を参考にすると、sheetはContentViewの子ビューにならない新たな階層になるとのことでした。確かに言われればそうですね・・・。
※参考:
おわりに
基本的な実装だけでなく、今回のようなエラーの解決方法もなるべく記事に残していこうと思います。