SwiftUI Core Data 在 DetailView 中绑定 TextFields
Posted
技术标签:
【中文标题】SwiftUI Core Data 在 DetailView 中绑定 TextFields【英文标题】:SwiftUI Core Data Binding TextFields in DetailView 【发布时间】:2020-12-09 22:28:38 【问题描述】:我有一个 SwiftUI 应用程序,其 SwiftUI 应用程序生命周期包括一个主从类型 从 CoreData 驱动的列表。我在 ContentView 和 NavigationLinks 中有标准列表 到细节视图。我将一个 Core Data 实体对象传递给 Detailview。
我的困难是在 DetailView 中设置与 TextFields 的绑定以进行数据输入 并用于编辑。我试图创建一个我无法工作的初始化程序。我有 只能使其与以下内容一起使用。分配初始值 尽管它确实有效,但在体内似乎并不是最好的方法。
由于核心数据实体是 ObservableObjects 我认为我应该能够 直接访问和更新绑定变量,但我找不到任何引用方式 在 ForEach 循环中绑定到 Core Data。
有没有比我下面的代码更合适的方法?
简化示例:
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:
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
【问题讨论】:
【参考方案1】:你已经提到了。 CoreData 与 SwiftUI 配合得很好。
把你的东西变成 ObservableObject
@ObservedObject var thing: Thing
然后您可以将值作为绑定传递。这也适用于 ForEach
TextField("name", text: $thing.localName)
【讨论】:
谢谢。我发誓我试过了。我一定在语法上犯了错误。我会再试一次。【参考方案2】:对于其他人 - 请注意,我必须使用上面的 Binding 扩展,因为 NSManagedObjects 是可选的。因此,正如 davidev 所说:
TextField("name", text: Binding($thing.name, "no name"))
和ObservedObject,不是Observable
【讨论】:
你是完全正确的。更正了我的答案。谢谢:)以上是关于SwiftUI Core Data 在 DetailView 中绑定 TextFields的主要内容,如果未能解决你的问题,请参考以下文章
如何让 SwiftUI 与 Core Data 一起工作(在启动项目后)?
使用 SwiftUI 2.0 和 Core Data 预填充数据