在 SwiftUI 中更新/编辑数组元素的最佳方法
Posted
技术标签:
【中文标题】在 SwiftUI 中更新/编辑数组元素的最佳方法【英文标题】:Best Way to Update/Edit an Array Element in SwiftUI 【发布时间】:2020-05-30 17:28:50 【问题描述】:我有一组可识别的培训元素。每个 Training 元素只有两个属性,name 和 isRequired。
将数组元素的现有值更新为新的编辑值的最直接(最快捷)的方法是什么...编辑后的值随后将提交到数据库。
是否可以将EditTraining
视图(子)中的状态设置为传入的(父)值,然后在子视图中编辑状态?
我被困在这个问题上的时间比我承认的要长。
非常感谢您的帮助!
代码如下:
import SwiftUI
struct Training: Identifiable
let id: String
let trainingName: String
let isRequired: Bool
class GetTrainings: ObservableObject
@Published var items = [Training]()
init()
self.items = [
Training(id: "ttt1", trainingName: "Safety", isRequired: true),
Training(id: "ttt2", trainingName: "Administrative", isRequired: false),
Training(id: "ttt3", trainingName: "Computer", isRequired: true),
Training(id: "ttt4", trainingName: "People", isRequired: true),
Training(id: "ttt5", trainingName: "Managerial", isRequired: true),
]
struct TrainingList: View
@ObservedObject var trainings = GetTrainings()
var body: some View
NavigationView
VStack
List
ForEach(trainings.items) training in
HStack
NavigationLink(destination: TrainingView(training: training))
Text("\(training.trainingName)")
.navigationBarTitle("Training List")
struct TrainingView: View
var training: Training
var body: some View
VStack
Text("\(training.trainingName)").font(.body)
Text("\(training.isRequired == true ? "Required Training" : "Training Not Required")")
HStack
NavigationLink(destination: EditTraining(training: training))
Text("Edit Training Details")
.navigationBarTitle("\(training.trainingName) Page", displayMode: .inline)
struct EditTraining: View
var training: Training
// Can I set the state values to the passed in values ???
@State private var newName: String = ""
@State private var isRequiredTraining: Bool = false
//@Binding var name: String = training.trainingName ????
private func submitData()
let newName = self.newName
let newBoolVal = self.isRequiredTraining
print("Firebase Sync Id is :\(training.id) Text: \(newName) and Bool: \(newBoolVal)")
var body: some View
VStack
Form
Section (header: Text("Edit"))
Text("\(training.trainingName)")
/* TextField should Populate With passed In Training Name Here*/
TextField("New Name", text: self.$newName)
Toggle(isOn: self.$isRequiredTraining)
Text("Is Required")
Section
Button(action:
self.submitData()
)
Text("Submit")
.navigationBarTitle("Edit Training Page", displayMode: .inline)
struct ContentView: View
var body: some View
VStack
TrainingList()
struct ContentView_Previews: PreviewProvider
static var previews: some View
ContentView()
【问题讨论】:
【参考方案1】:在我看来,对模型使用 ObservableObject 更为可取,因为它允许通过引用模型对象深入层次结构并在工作流程中保持最新状态。
这里有一个解决方案。使用 Xcode 11.4 / ios 13.4 测试
class Training: ObservableObject, Identifiable
let id: String
@Published var trainingName: String
@Published var isRequired: Bool
init(id: String, trainingName: String, isRequired: Bool)
self.id = id
self.trainingName = trainingName
self.isRequired = isRequired
class GetTrainings: ObservableObject
@Published var items = [Training]()
init()
self.items = [
Training(id: "ttt1", trainingName: "Safety", isRequired: true),
Training(id: "ttt2", trainingName: "Administrative", isRequired: false),
Training(id: "ttt3", trainingName: "Computer", isRequired: true),
Training(id: "ttt4", trainingName: "People", isRequired: true),
Training(id: "ttt5", trainingName: "Managerial", isRequired: true),
]
struct TrainingList: View
@ObservedObject var trainings = GetTrainings()
var body: some View
NavigationView
VStack
List
ForEach(trainings.items) training in
HStack
NavigationLink(destination: TrainingView(training: training))
Text("\(training.trainingName)")
.navigationBarTitle("Training List")
.onAppear
self.trainings.objectWillChange.send() // refresh
struct TrainingView: View
@ObservedObject var training: Training
var body: some View
VStack
Text("\(training.trainingName)").font(.body)
Text("\(training.isRequired == true ? "Required Training" : "Training Not Required")")
HStack
NavigationLink(destination: EditTraining(training: training))
Text("Edit Training Details")
.navigationBarTitle("\(training.trainingName) Page", displayMode: .inline)
struct EditTraining: View
@ObservedObject var training: Training
@State private var newName: String
@State private var isRequiredTraining: Bool
init(training: Training)
self.training = training
self._newName = State(initialValue: training.trainingName)
self._isRequiredTraining = State(initialValue: training.isRequired)
private func submitData()
let newName = self.newName
let newBoolVal = self.isRequiredTraining
print("Firebase Sync Id is :\(training.id) Text: \(newName) and Bool: \(newBoolVal)")
self.training.trainingName = newName
self.training.isRequired = newBoolVal
var body: some View
VStack
Form
Section (header: Text("Edit"))
Text("\(training.trainingName)")
/* TextField should Populate With passed In Training Name Here*/
TextField("New Name", text: self.$newName)
Toggle(isOn: self.$isRequiredTraining)
Text("Is Required")
Section
Button(action:
UIApplication.shared.sendAction(#selector(UIResponder.resignFirstResponder),
to:nil, from:nil, for:nil)
self.submitData()
)
Text("Submit")
.navigationBarTitle("Edit Training Page", displayMode: .inline)
【讨论】:
你是救生员!我不确定我是否会提出您的解决方案。它工作完美!非常感谢! 这是一个很好的例子,非常有帮助,谢谢。为什么需要按钮中的UIApplication.shared.sendAction
?似乎可以正常工作,self.trainings.objectWillChange.send()
以上是关于在 SwiftUI 中更新/编辑数组元素的最佳方法的主要内容,如果未能解决你的问题,请参考以下文章
在 Apple Watch 上的 SwiftUI 中,更新描述自具有 Always On 状态的日期以来的间隔的字符串的最佳方法是啥?