视图更改不会更新 object/model
Change in View does not update object/model
我遇到一个问题,即视图中的更改不会更新模型中的基础对象。这里的想法是生成所有不同类型(字符串、日期、布尔值)的动态属性列表,在 GUI 中一切看起来都很好,但是当点击“保存”按钮时,我可以看到数据没有更新。我在这里错过了什么?
完整的工作演示项目如下:
//
// ContentView.swift
// AttributeDemo
//
// Created by Max on 28.05.22.
//
import SwiftUI
public enum AttributeType: Codable, CaseIterable{
case int
case string
case datetime
case decimal
case double
case boolean
var stringValue: String {
switch self {
case .int: return "Full numbers"
case .string: return "Text"
case .datetime: return "Date"
case .decimal: return "Decimal"
case .double: return "Double"
case .boolean: return "Yes/No"
}
}
}
public class Attribute: Identifiable, Codable, ObservableObject {
public var id: UUID = UUID()
public var bkey: String = ""
public var tmp_create: Date = Date()
public var itemBkey: String = ""
public var attrType: AttributeType = .string
public var name: String = ""
public var description: String = ""
public var value_int: Int = 0
public var value_string: String = ""
public var value_datetime: Date = Date()
public var value_decimal: Decimal = 0.0
public var value_double: Double = 0.0
public var value_boolean: Bool = false
var userBkey: String = ""
var userToken: String = ""
}
struct ContentView: View {
@State private var attributes: [Attribute] = []
@State private var showingAttributeTypes = false
var body: some View {
VStack{
Button("Add attribute"){
self.showingAttributeTypes.toggle()
}
.confirmationDialog("Select a color", isPresented: $showingAttributeTypes, titleVisibility: .visible) {
Button("Text") {
addAttribute(attributeType: .string)
}
Button("Number") {
addAttribute(attributeType: .decimal)
}
Button("Date") {
addAttribute(attributeType: .datetime)
}
Button("Yes/No") {
addAttribute(attributeType: .boolean)
}
}
ForEach(self.attributes){value in
AttributeView(attribute: value)
}
Button("Save"){
self.attributes.forEach{value in
print(value.attrType.stringValue)
print(value.value_string)
print(value.value_datetime)
print(value.value_boolean)
print("--------------------------------")
}
}
}
}
func addAttribute(attributeType: AttributeType){
var attribute = Attribute()
attribute.attrType = attributeType
self.attributes.append(attribute)
}
}
struct AttributeView: View {
@ObservedObject var attribute: Attribute = Attribute()
@State private var description: String = ""
@State private var value_boolean: Bool = false
@State private var value_string: String = ""
@State private var value_decimal: Decimal = 0.0
@State private var value_double: Double = 0.0
@State private var value_datetime: Date = Date()
var body: some View {
HStack{
FormField(fieldName: "Description", fieldValue: $description)
.keyboardType(.default)
Spacer()
switch(attribute.attrType){
case .boolean:
Toggle(isOn: $value_boolean) {
Label("", image: "")
}
case .string:
TextField("", text: $value_string)
.keyboardType(.default)
case .datetime:
DatePicker(selection: $value_datetime, displayedComponents: .date, label: { Text("") })
case .decimal:
TextField("", value: $value_decimal, format: .number)
.keyboardType(.decimalPad)
case .double:
TextField("", value: $value_double, format: .number)
.keyboardType(.decimalPad)
default:
EmptyView()
}
}
}
}
struct FormField: View {
var fieldName = ""
@Binding var fieldValue: String
var body: some View{
TextField(fieldName, text: $fieldValue)
}
}
struct ContentView_Previews: PreviewProvider {
static var previews: some View {
ContentView()
}
}
要在视图中进行更改以更新模型中的基础对象,您可以尝试一小段 re-structure 代码,其中您将 Attribute
设为 struct
,使用ObservableObject
模型以保留您的 Attributes
数组,并像本示例代码中那样使用它们:
public struct Attribute: Identifiable, Codable { // <-- here
public var id: UUID = UUID()
public var bkey: String = ""
public var tmp_create: Date = Date()
public var itemBkey: String = ""
public var attrType: AttributeType = .string
public var name: String = ""
public var description: String = ""
public var value_int: Int = 0
public var value_string: String = ""
public var value_datetime: Date = Date()
public var value_decimal: Decimal = 0.0
public var value_double: Double = 0.0
public var value_boolean: Bool = false
var userBkey: String = ""
var userToken: String = ""
}
public class AttributeModel: ObservableObject { // <-- here
@Published var attributes: [Attribute] = [] // <-- here
}
struct ContentView: View {
@StateObject var model = AttributeModel() // <-- here
@State private var showingAttributeTypes = false
var body: some View {
VStack{
Button("Add attribute"){
self.showingAttributeTypes.toggle()
}
.confirmationDialog("Select a color", isPresented: $showingAttributeTypes, titleVisibility: .visible) {
Button("Text") {
addAttribute(attributeType: .string)
}
Button("Number") {
addAttribute(attributeType: .decimal)
}
Button("Date") {
addAttribute(attributeType: .datetime)
}
Button("Yes/No") {
addAttribute(attributeType: .boolean)
}
}
ForEach($model.attributes){ $value in // <-- here
AttributeView(attribute: $value)
}
Button("Save"){
model.attributes.forEach { value in
print("---> \(value)") // <-- here
print("--------------------------------")
}
}
}
}
func addAttribute(attributeType: AttributeType){
var attribute = Attribute()
attribute.attrType = attributeType
model.attributes.append(attribute)
}
}
struct AttributeView: View {
@Binding var attribute: Attribute // <-- here
var body: some View {
HStack{
FormField(fieldName: "Description", fieldValue: $attribute.description)
.keyboardType(.default)
Spacer()
switch(attribute.attrType){
case .boolean:
Toggle(isOn: $attribute.value_boolean) { // <-- here etc...
Label("", image: "")
}
case .string:
TextField("", text: $attribute.value_string)
.keyboardType(.default)
case .datetime:
DatePicker(selection: $attribute.value_datetime, displayedComponents: .date, label: { Text("") })
case .decimal:
TextField("", value: $attribute.value_decimal, format: .number)
.keyboardType(.decimalPad)
case .double:
TextField("", value: $attribute.value_double, format: .number)
.keyboardType(.decimalPad)
default:
EmptyView()
}
}
}
}
我遇到一个问题,即视图中的更改不会更新模型中的基础对象。这里的想法是生成所有不同类型(字符串、日期、布尔值)的动态属性列表,在 GUI 中一切看起来都很好,但是当点击“保存”按钮时,我可以看到数据没有更新。我在这里错过了什么?
完整的工作演示项目如下:
//
// ContentView.swift
// AttributeDemo
//
// Created by Max on 28.05.22.
//
import SwiftUI
public enum AttributeType: Codable, CaseIterable{
case int
case string
case datetime
case decimal
case double
case boolean
var stringValue: String {
switch self {
case .int: return "Full numbers"
case .string: return "Text"
case .datetime: return "Date"
case .decimal: return "Decimal"
case .double: return "Double"
case .boolean: return "Yes/No"
}
}
}
public class Attribute: Identifiable, Codable, ObservableObject {
public var id: UUID = UUID()
public var bkey: String = ""
public var tmp_create: Date = Date()
public var itemBkey: String = ""
public var attrType: AttributeType = .string
public var name: String = ""
public var description: String = ""
public var value_int: Int = 0
public var value_string: String = ""
public var value_datetime: Date = Date()
public var value_decimal: Decimal = 0.0
public var value_double: Double = 0.0
public var value_boolean: Bool = false
var userBkey: String = ""
var userToken: String = ""
}
struct ContentView: View {
@State private var attributes: [Attribute] = []
@State private var showingAttributeTypes = false
var body: some View {
VStack{
Button("Add attribute"){
self.showingAttributeTypes.toggle()
}
.confirmationDialog("Select a color", isPresented: $showingAttributeTypes, titleVisibility: .visible) {
Button("Text") {
addAttribute(attributeType: .string)
}
Button("Number") {
addAttribute(attributeType: .decimal)
}
Button("Date") {
addAttribute(attributeType: .datetime)
}
Button("Yes/No") {
addAttribute(attributeType: .boolean)
}
}
ForEach(self.attributes){value in
AttributeView(attribute: value)
}
Button("Save"){
self.attributes.forEach{value in
print(value.attrType.stringValue)
print(value.value_string)
print(value.value_datetime)
print(value.value_boolean)
print("--------------------------------")
}
}
}
}
func addAttribute(attributeType: AttributeType){
var attribute = Attribute()
attribute.attrType = attributeType
self.attributes.append(attribute)
}
}
struct AttributeView: View {
@ObservedObject var attribute: Attribute = Attribute()
@State private var description: String = ""
@State private var value_boolean: Bool = false
@State private var value_string: String = ""
@State private var value_decimal: Decimal = 0.0
@State private var value_double: Double = 0.0
@State private var value_datetime: Date = Date()
var body: some View {
HStack{
FormField(fieldName: "Description", fieldValue: $description)
.keyboardType(.default)
Spacer()
switch(attribute.attrType){
case .boolean:
Toggle(isOn: $value_boolean) {
Label("", image: "")
}
case .string:
TextField("", text: $value_string)
.keyboardType(.default)
case .datetime:
DatePicker(selection: $value_datetime, displayedComponents: .date, label: { Text("") })
case .decimal:
TextField("", value: $value_decimal, format: .number)
.keyboardType(.decimalPad)
case .double:
TextField("", value: $value_double, format: .number)
.keyboardType(.decimalPad)
default:
EmptyView()
}
}
}
}
struct FormField: View {
var fieldName = ""
@Binding var fieldValue: String
var body: some View{
TextField(fieldName, text: $fieldValue)
}
}
struct ContentView_Previews: PreviewProvider {
static var previews: some View {
ContentView()
}
}
要在视图中进行更改以更新模型中的基础对象,您可以尝试一小段 re-structure 代码,其中您将 Attribute
设为 struct
,使用ObservableObject
模型以保留您的 Attributes
数组,并像本示例代码中那样使用它们:
public struct Attribute: Identifiable, Codable { // <-- here
public var id: UUID = UUID()
public var bkey: String = ""
public var tmp_create: Date = Date()
public var itemBkey: String = ""
public var attrType: AttributeType = .string
public var name: String = ""
public var description: String = ""
public var value_int: Int = 0
public var value_string: String = ""
public var value_datetime: Date = Date()
public var value_decimal: Decimal = 0.0
public var value_double: Double = 0.0
public var value_boolean: Bool = false
var userBkey: String = ""
var userToken: String = ""
}
public class AttributeModel: ObservableObject { // <-- here
@Published var attributes: [Attribute] = [] // <-- here
}
struct ContentView: View {
@StateObject var model = AttributeModel() // <-- here
@State private var showingAttributeTypes = false
var body: some View {
VStack{
Button("Add attribute"){
self.showingAttributeTypes.toggle()
}
.confirmationDialog("Select a color", isPresented: $showingAttributeTypes, titleVisibility: .visible) {
Button("Text") {
addAttribute(attributeType: .string)
}
Button("Number") {
addAttribute(attributeType: .decimal)
}
Button("Date") {
addAttribute(attributeType: .datetime)
}
Button("Yes/No") {
addAttribute(attributeType: .boolean)
}
}
ForEach($model.attributes){ $value in // <-- here
AttributeView(attribute: $value)
}
Button("Save"){
model.attributes.forEach { value in
print("---> \(value)") // <-- here
print("--------------------------------")
}
}
}
}
func addAttribute(attributeType: AttributeType){
var attribute = Attribute()
attribute.attrType = attributeType
model.attributes.append(attribute)
}
}
struct AttributeView: View {
@Binding var attribute: Attribute // <-- here
var body: some View {
HStack{
FormField(fieldName: "Description", fieldValue: $attribute.description)
.keyboardType(.default)
Spacer()
switch(attribute.attrType){
case .boolean:
Toggle(isOn: $attribute.value_boolean) { // <-- here etc...
Label("", image: "")
}
case .string:
TextField("", text: $attribute.value_string)
.keyboardType(.default)
case .datetime:
DatePicker(selection: $attribute.value_datetime, displayedComponents: .date, label: { Text("") })
case .decimal:
TextField("", value: $attribute.value_decimal, format: .number)
.keyboardType(.decimalPad)
case .double:
TextField("", value: $attribute.value_double, format: .number)
.keyboardType(.decimalPad)
default:
EmptyView()
}
}
}
}