SwiftUI / CoreData / Master / Detail (with editing

2020-02-08 21:28发布

Working on a sample app. The goal is to have a list pulled up from CoreData in a Master, and then click on one to go to a detail, where you can edit the information and save. When you edit the "name" in the detail, it not only updates the detail to reflect the change, but it also reflects the change on the master as well. I've tried numerous ways to accomplish this, but so far have not come up with an answer.

// Code generation is turned OFF in the xcdatamodeld file

public class EntityName: NSManagedObject, Identifiable {
   @NSManaged public var name: String
   @NSManaged public var active: Bool
}

extension EntityName {
    static func allEntityNameFetchRequest() -> NSFetchRequest<EntityName> {
        let request: NSFetchRequest<EntityName> = EntityName.fetchRequest() as! NSFetchRequest<EntityName>
        request.sortDescriptors = [NSSortDescriptor(key: "name", ascending: true)]
        return request
   }
}


struct MasterView: View {

    @Environment(\.managedObjectContext) var managedObjectContext
    @FetchRequest(fetchRequest: EntityName.allEntityNameFetchRequest()) var allEntityNames: FetchedResults<EntityName>


    var body: some View {
        NavigationView {
            List {
                ForEach(self.allEntityNames) { entityName in
                NavigationLink(destination: DetailView(entityName: entityName)) {
                    VStack(alignment: .leading) {
                        Text(entityName.name)
                            .font(.headline)
                        Text(String(entityName.active))
                            .font(.subheadline)
                    }
                }
            }
        }
    }
    .onAppear() {
        // Just want to populate the Core Data to have a few to work with
        if self.allEntityNames.count == 0 {
            for _ in 1...3 {
                let newEntry = EntityName(context: self.managedObjectContext)
                newEntry.name = "New Entry"

                try! self.managedObjectContext.save()
            }
         }
      }
   }
}

struct DetailView: View {

   var entityName = EntityName()

   var body: some View {
       VStack {
           Text("Name: \(entityName.name)")
           Text("Active: \(String(entityName.active))")

           // What I'd like to do now:
              //TextField("", text: $entityName.name)
              //Toggle(isOn: $entityName.active)
       }
   }
}

3条回答
Melony?
2楼-- · 2020-02-08 22:15

As @trapper explained, the entityName has to be bound the the MasterView.

Updates are reflected when you add @ObservedObject in the DetailView as follows:

@ObservedObject var entityName:EntityName
查看更多
混吃等死
3楼-- · 2020-02-08 22:25

As promised, here is a link to sample SwiftUI program that uses CoreData. The current version compiles and runs on the GM release. It does not use the new @FetchRequest property wrapper because it does not suit all of my needs. I wrote a CoreDataDataSource class that does basically the same thing plus a lot more.

https://github.com/Whiffer/SwiftUI-Core-Data-Test

查看更多
爷的心禁止访问
4楼-- · 2020-02-08 22:26

You need to bind the entity in DetailView to the entity passed in from MasterView. Declare it like @Binding var entityName: EntityName

查看更多
登录 后发表回答