DetailView中的SwiftUI核心数据绑定文本字段 [英] SwiftUI Core Data Binding TextFields in DetailView

查看:41
本文介绍了DetailView中的SwiftUI核心数据绑定文本字段的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有一个带有SwiftUI应用程序生命周期的SwiftUI应用程序,其中包括主从类型由CoreData驱动的列表.我在ContentView和NavigationLinks中有标准列表到DetailView.我将核心数据实体对象传递给Detailview.

I have a SwiftUI app with SwiftUI App lifecycle that includes a master-detail type list driven from CoreData. I have the standard list in ContentView and NavigationLinks to the DetailView. I pass a Core Data entity object to the Detailview.

我的工作是在DetailView中设置到TextField的绑定以进行数据输入并进行编辑.我试图创建一个无法使我工作的初始化器.我有只能使其与以下功能一起使用.分配初始值尽管它确实起作用,但似乎并不是体内最好的方法.

My struggle is setting-up bindings to TextFields in the DetailView for data entry and for editing. I tried to create an initializer which I could not make work. I have only been able to make it work with the following. Assigning the initial values inside the body does not seem like the best way to do this, though it does work.

由于核心数据实体是ObservableObjects,我认为我应该能够直接访问和更新绑定变量,但是我找不到任何引用的方法在ForEach循环中绑定到Core Data.

Since the Core Data entities are ObservableObjects I thought I should be able to directly access and update bound variables, but I could not find any way to reference a binding to Core Data in a ForEach loop.

有没有比我下面的代码更合适的方法了?

Is there a way to do this that is more appropriate than my code below?

简化示例:

struct DetailView: View {

    var thing: Thing
    var count: Int

    @State var localName: String = ""
    @State private var localComment: String = ""
    @State private var localDate: Date = Date()

    //this does not work - cannot assign String? to State<String>
//    init(t: Thing) {
//        self._localName = t.name
//        self._localComment = t.comment
//        self._localDate = Date()
//    }

    var body: some View {
        //this is the question - is this safe?
        DispatchQueue.main.async {
            self.localName = self.thing.name ?? "no name"
            self.localComment = self.thing.comment ?? "No Comment"
            self.localDate = self.thing.date ?? Date()
        }

        return VStack {
            Text("\(thing.count)")
                .font(.title)
            Text(thing.name ?? "no what?")
            TextField("name", text: $localName)
            Text(thing.comment ?? "no comment?")
            TextField("comment", text: $localComment)
            Text("\(thing.date ?? Date())")
            //TextField("date", text: $localDate)
        }.padding()
    }
}

为了完整起见,ContentView:

And for completeness, the ContentView:

struct ContentView: View {
    @Environment(\.managedObjectContext) private var viewContext
    @FetchRequest(sortDescriptors: [NSSortDescriptor(keyPath: \Thing.date, ascending: false)])
    private var things : FetchedResults<Thing>

    @State private var count: Int = 0
    @State private var coverDeletedDetail = false

    var body: some View {
        NavigationView {
            List {
                ForEach(things) { thing in
                    NavigationLink(destination: DetailView(thing: thing, count: self.count + 1)) {
                        HStack {
                            Image(systemName: "gear")
                                .resizable()
                                .frame(width: 40, height: 40)
                                .onTapGesture(count: 1, perform: {
                                    updateThing(thing)
                                })
                            Text(thing.name ?? "untitled")
                            Text("\(thing.count)")
                        }
                    }
                }
                .onDelete(perform: deleteThings)
                if UIDevice.current.userInterfaceIdiom == .pad {
                    NavigationLink(destination: WelcomeView(), isActive: self.$coverDeletedDetail) {
                        Text("")
                    }
                }
            }
            .navigationTitle("Thing List")
            .navigationBarItems(trailing: Button("Add Task") {
                addThing()
            })
        }
    }

    private func updateThing(_ thing: FetchedResults<Thing>.Element) {
        withAnimation {
            thing.name = "Updated Name"
            thing.comment = "Updated Comment"
            saveContext()
        }
    }

    private func deleteThings(offsets: IndexSet) {
        withAnimation {
            offsets.map { things[$0] }.forEach(viewContext.delete)
            saveContext()
            self.coverDeletedDetail = true
        }
    }

    private func addThing() {
        withAnimation {
            let newThing = Thing(context: viewContext)
            newThing.name = "New Thing"
            newThing.comment = "New Comment"
            newThing.date = Date()
            newThing.count = Int64(self.count + 1)
            self.count = self.count + 1
            saveContext()
        }
    }

    func saveContext() {
        do {
            try viewContext.save()
        } catch {
            print(error)
        }
    }
}

和核心数据:

extension Thing {
    @nonobjc public class func fetchRequest() -> NSFetchRequest<Thing> {
        return NSFetchRequest<Thing>(entityName: "Thing")
    }
    @NSManaged public var comment: String?
    @NSManaged public var count: Int64
    @NSManaged public var date: Date?
    @NSManaged public var name: String?
}

extension Thing : Identifiable {
}

任何指导将不胜感激.Xcode 12.2 iOS 14.2

Any guidance would be appreciated. Xcode 12.2 iOS 14.2

推荐答案

您已经提到了它.CoreData可与SwiftUI完美结合.

You already mentioned it. CoreData works great with SwiftUI.

只需将您的事物设置为ObservableObject

Just make your Thing as ObservableObject

@ObservedObject var thing: Thing

,然后您可以将事物的值作为Binding传递.这同样适用于ForEach

and then you can pass values from thing as Binding. This works in ForEach aswell

TextField("name", text: $thing.localName)

这篇关于DetailView中的SwiftUI核心数据绑定文本字段的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆