SwiftUIでコアデータを使用することは不可能であることがわかりました。コアデータをビューの監視対象オブジェクト変数に渡すと、ナビゲーションリンクビューはビューが消えた後もオブジェクトへの参照を保持するため、削除するとすぐにエラーメッセージなしで、アプリがクラッシュするコンテキストのオブジェクト。
コアデータオブジェクト変数をオプションとしてビューモデルにラップし、コンテキスト削除アクションの直後にオブジェクトをnilに設定してアプリが正常に動作することでこれを確認しましたが、コアデータオブジェクトが必要なため、これは解決策ではありません迅速なuiビューにバインドし、真実のソースになります。これはどのように機能すると想定されていますか?SwiftUIを使用してリモートで複雑なことを真剣に行うことはできないようです。
渡されたコアデータオブジェクトをオプションの@Stateに割り当てようとしましたが、これは機能しません。@Bindingはフェッチされたオブジェクトなので使用できません。また、swiftuiコントロールにはバインディングが必要なため、変数を使用できません。@ObservedObjectを使用することは意味がありますが、これはオプションにすることはできません。つまり、それに割り当てられたオブジェクトが削除されると、アプリがクラッシュします。これをnilに設定できないためです。
これがコアデータオブジェクトです。これはデフォルトで監視可能なオブジェクトです。
class Entry: NSManagedObject, Identifiable {
@NSManaged public var date: Date
}
以下は、コアデータエントリオブジェクトを別のビューに渡すビューです。
struct JournalView: View {
@Environment(\.managedObjectContext) private var context
@FetchRequest(
entity: Entry.entity(),
sortDescriptors: [],
predicate: nil,
animation: .default
) var entries: FetchedResults<Entry>
var body: some View {
NavigationView {
List {
ForEach(entries.indices) { index in
NavigationLink(destination: EntryView(entry: self.entries[index])) {
Text("Entry")
}
}.onDelete { indexSet in
for index in indexSet {
self.context.delete(self.entries[index])
}
}
}
}
}
}
これが、渡されたコアデータエントリオブジェクトのすべての属性にアクセスするビューです。いったんこのエントリを削除すると、ところで、どのビューからもこのエントリがまだ参照されているため、アプリがすぐにクラッシュします。これは、ナビゲーションリンクがアクセスされる前にすべての宛先ビューを初期化することにも関係していると思います。それがなぜそれをするのか、それは意味がありません。これはバグですか、これを達成するためのより良い方法はありますか?
私は成功せずにonDisappearの削除を試みました。JournalViewから削除しても、NavigationLinkがまだオブジェクトを参照しているため、クラッシュします。まだクリックされていないNavigationLinkを削除しても、興味深いことにクラッシュしません。
struct EntryView: View {
@Environment(\.managedObjectContext) private var context
@Environment(\.presentationMode) private var presentationMode
@ObservedObject var entry: Entry
var body: some View {
Form {
DatePicker(selection: $entry.date) {
Text("Date")
}
Button(action: {
self.context.delete(self.entry)
self.presentationMode.wrappedValue.dismiss()
}) {
Text("Delete")
}
}
}
}
更新
クラッシュにより、EntryViewでのエントリの最初の使用に私を連れて行き、Thread 1:EXC_BAD_INSTRUCTION(code = EXC_I386_INVOP、subcode = 0x0)を読み取ります。それがスローされる唯一のメッセージです。
考えられる唯一の回避策は、コアデータオブジェクト「isDeleted」にプロパティを追加し、コンテキストから削除しようとするのではなく、trueに設定することです。次に、アプリが終了したとき、または起動時に、isDeletedであるすべてのエントリをクリーンアップして削除できますか?理想的ではなく、ここで何が問題なのかを理解することを好むでしょう。私は、MasterDetailAppサンプルと何も変わらないように見えるので、機能しているようです。