今回はメインビューとなるContentView.swiftから、サブビュー(TaskEditView.swift)へ、CoreDataで取得したデータを渡す方法を紹介する。

ここで使用するサンプルアプリは以下の記事で紹介している。

サブビューを用意する

まず、サブビューとしてTaskEditView.swiftを作成する。

import SwiftUI
import CoreData

struct TaskEditView: View {
  @ObservedObject var task: Task
  
  var body: some View {
    VStack {
      Text(task.name)
    }.padding()
      .navigationBarTitle("編集画面")
  }
}

CoreDataのエンティティを受け取る場合に必要なのが、5行目の宣言。

@ObservedObjectを付けることで、インスタンスがSwiftUIの監視対象となり、プロパティが更新されると参照されているViewも自動的に更新されるようになる。

NavigationLinkでサブビューにエンティティを渡す

次にメインビューとなるContentView.swiftを以下のとおり編集する。

コード全文

import SwiftUI
import CoreData

struct ContentView: View {
  @FetchRequest(
    sortDescriptors: [NSSortDescriptor(keyPath: \Task.date, ascending: false)],
    animation: .default
  )
  var tasks: FetchedResults<Task>
  
  @Environment(\.managedObjectContext) var viewContext
  @State var new = ""
  
  var body: some View {
    NavigationView {
      VStack {
        HStack {
          TextField("Input here", text: $new)
            .textFieldStyle(RoundedBorderTextFieldStyle())
          Button(action: {
            let newTask = Task(context: self.viewContext)
            newTask.name = self.new
            newTask.date = Date()
            self.saveCoreData()
            
            self.new = ""
          }) {
            Text("追加")
          }
        }
        
        List {
          ForEach(tasks.indices, id: \.self) { index in
            NavigationLink(destination: TaskEditView(task: self.tasks[index])) {
              Text("\(self.tasks[index].name)")
            }
          }.onDelete(perform: removeTask)
        }
      }.padding()
        .navigationBarTitle("タスク一覧")
    }
  }
  
  private func removeTask(at offsets: IndexSet) {
    for index in offsets {
      let putTask = tasks[index]
      viewContext.delete(putTask)
    }
    saveCoreData()
  }
  
  private func saveCoreData() {
    do {
      try self.viewContext.save()
    } catch {
      let nsError = error as NSError
      fatalError("Unresolved error \(nsError), \(nsError.userInfo)")
    }
  }
}

少し長いコードだが、エンティティの受け渡しはこちらの部分。

List {
  ForEach(tasks.indices, id: \.self) { index in
    NavigationLink(destination: TaskEditView(task: self.tasks[index])) {
      Text("\(self.tasks[index].name)")
    }
  }.onDelete(perform: removeTask)
}

NavigationLinkを使って、遷移先のビューにエンティティを渡している。

アプリを実行し、テスト用にいくつかのタスクを登録した画面がこちら。

タスク名をタップするとサブビューに遷移し、選択したタスク名が表示される。