前提・実現したいこと
SwiftUIとCore Dataを使ったToDoアプリを作っています。
作っていく中でアプリの複数のViewからCore Dataにアクセスすることになったので、Core Dataへの追加や削除、情報の取得、保存などを共通化したいと思いました。(そのViewというのは具体的には、ToDoのタスクの一覧を表示するView、一覧のそれぞれの行のView、タスクの詳細を表示・編集するView、データを更新するボタンのViewなどです。)
変更を加えたものを保存するのはどのViewからも呼び出すのですが、それぞれのViewの中に全く同じ保存する関数を書くのは無駄な気がします。
そこで、別のファイルにCore Dataの処理をするクラスを書き、それぞれのViewからそのクラスへアクセスして保存や追加などをできるようにしたいと考えました。しかし、エラーが出てしまい、実行できませんでした。
何が理由でエラーが出てしまったのでしょうか。また、この別のクラスに書くというのが正しいのでしょうか。(Environment
などを使った方がいいのでしょうか)
よろしくお願いします。
発生している問題・エラーメッセージ
ビルドするときには何もエラーが出ないのですが、シミュレーターで実行するとForEachの行で以下のように表示されます。iPhoneの実機でも同様に表示されました。
Thread 1: EXC_BAD_INSTRUCTION (code=EXC_I386_INVOP, subcode=0x0)
該当のソースコード
問題が発生したプロジェクトは大きすぎたため、新しくプロジェクトを作成して、問題が発生している部分だけを書きました。
ContentView.swift
swift
1import SwiftUI 2 3struct ContentView: View { 4 var toDoHelper = ToDoHelper() 5 @State var taskName: String = "" 6 var body: some View { 7 List { 8 HStack { 9 TextField(taskName, text: $taskName) 10 Spacer() 11 Button(action: addTask) { 12 Image(systemName: "plus.circle") 13 } 14 } 15 16 ForEach(toDoHelper.tasks, id: .self) { task in 17 Text(task.name ?? "") 18 } 19 } 20 } 21 22 func addTask() { 23 toDoHelper.add(taskName: self.taskName) 24 taskName = "" 25 } 26}
ToDoHelper.swift
swift
1import SwiftUI 2import CoreData 3 4class ToDoHelper { 5 @Environment(.managedObjectContext) var context 6 @FetchRequest(entity: ToDo.entity(), sortDescriptors: [NSSortDescriptor(keyPath: \ToDo.createdAt, ascending: true)]) var tasks: FetchedResults<ToDo> 7 func save() { 8 do { 9 try self.context.save() 10 } catch { 11 print(error) 12 } 13 } 14 15 func add(taskName: String) { 16 let newTask = ToDo(context: self.context) 17 newTask.id = UUID() 18 newTask.name = taskName 19 newTask.createdAt = Date() 20 save() 21 } 22}
CoreDataはToDo
というエンティティの中に、Date型のcreatedAt
とUUID型のid
、String型のname
がAttributesに設定されています。
試したこと
classをstructにしてみたり、ObservableObjectにしてみたりしたのですが、解決しませんでした。また、似たような事例を探してみたのですが、見つかりませんでした。
ToDoHelper
クラスの中の処理をそのままContenteView
構造体の中に書くと問題なく動きます。
以下は正常に動いたプログラムです。
swift
1import SwiftUI 2 3struct ContentView: View { 4 @Environment(.managedObjectContext) var context 5 @FetchRequest(entity: ToDo.entity(), sortDescriptors: [NSSortDescriptor(keyPath: \ToDo.createdAt, ascending: true)]) var tasks: FetchedResults<ToDo> 6 var toDoHelper = ToDoHelper() 7 @State var taskName: String = "" 8 var body: some View { 9 List { 10 HStack { 11 TextField(taskName, text: $taskName) 12 Spacer() 13 Button(action: addTask) { 14 Image(systemName: "plus.circle") 15 } 16 } 17 18 ForEach(self.tasks, id: .self) { task in 19 Text(task.name ?? "") 20 } 21 } 22 } 23 24 func addTask() { 25 self.add(taskName: self.taskName) 26 taskName = "" 27 } 28 func save() { 29 do { 30 try self.context.save() 31 } catch { 32 print(error) 33 } 34 } 35 36 func add(taskName: String) { 37 let newTask = ToDo(context: self.context) 38 newTask.id = UUID() 39 newTask.name = taskName 40 newTask.createdAt = Date() 41 save() 42 } 43}
補足情報(FW/ツールのバージョンなど)
macOS 15.5
XCode 11.5
Swift 5.2.4
回答2件
あなたの回答
tips
プレビュー
バッドをするには、ログインかつ
こちらの条件を満たす必要があります。