SwiftUI TextField с вложенным необязательным типом

Всем привет !

Я использую SwiftData с представлением, предназначенным для обновления @Model.

Вот мои данные:

@Model
final class Pet {
    var name: String
    var gender: Gender
    var type: String
    var race: String
    var birthdate: Date
    var color: String
    var eyeColor: String
    var photo: Data?
    var identification: Identification?

    init(
        name: String,
        gender: Gender,
        type: String,
        race: String,
        birthdate: Date,
        color: String,
        eyeColor: String,
        photo: Data?
    ) {
        self.name = name
        self.gender = gender
        self.type = type
        self.race = race
        self.birthdate = birthdate
        self.color = color
        self.eyeColor = eyeColor
        self.photo = photo
    }
}
@Model
final class Identification {
    var chip: Int?
    var chipLocation: String?
    var tatoo: String?
    var tatooLocation: String?

    init(chip: Int?, chipLocation: String?, tatoo: String?, tatooLocation: String?) {
        self.chip = chip
        self.chipLocation = chipLocation
        self.tatoo = tatoo
        self.tatooLocation = tatooLocation
    }
}

Как видите, у меня есть тип под названием «Идентификация», вложенный в модель «Питомец», и он не является обязательным.
Более того, все его свойства также являются необязательными.

Я пытаюсь отредактировать свойство чипа следующим образом:

struct EditInformationView: View {
    @Environment(Pet.self) var pet

    var body: some View {
        @Bindable var pet = pet

        Form {
            Section("Identification") {
                TextField("Chip", value: $pet.identification?.chip)
            }
        }
    }
}

Мой вопрос очень прост: как мне отредактировать параметр чипа с помощью TextField?

Я немного потерялся и был бы признателен за небольшую помощь, большое спасибо :)

Я попытался использовать необязательную цепочку, как предложил мне Xcode, но это не сработало.


52
2

Ответы:

Вы можете попробовать этот простой подход, используя промежуточная переменная и .onSubmit, как показано в примере кода:

struct EditInformationView: View {
    @Environment(Pet.self) var pet

    @State private var chipVal = 0  // <--- here

    var body: some View {
        @Bindable var pet = pet

        Form {
            Section("Identification") {
                TextField("Chip", value: $chipVal, format: .number)  // <--- here
                    .onSubmit {
                        pet.identification?.chip = chipVal  // <--- here
                    }
            }
        }
        .onAppear {
            if let chipv = pet.identification?.chip {  // <--- here
                chipVal = chipv
            }
        }
    }
}

Обратите внимание, вы также можете использовать .onChange(of: chipVal)


Решено

Вы можете использовать любое из «Дополнительных решений привязки».

Вариант 1

struct EditInformationView: View {
    @Environment(Pet.self) var pet

    var body: some View {
        @Bindable var pet = pet

        Form {
            Section("Identification") {
                if let identification = Binding($pet.identification) {
                    TextField("Chip", value: identification.chip, format: .number)
                } else {
                    ProgressView()
                        .task {
                            pet.identification = Identification(chip: nil, chipLocation: nil, tatoo: nil, tatooLocation: nil)
                        }
                }
            }
        }
    }
}

Вариант 2

struct EditInformationView: View {
    @Environment(Pet.self) var pet
    
    var body: some View {
        @Bindable var pet = pet
        
        Form {
            Section("Identification") {
                TextField("Chip", value: ($pet.identification ?? Identification(chip: nil, chipLocation: nil, tatoo: nil, tatooLocation: nil)).chip, format: .number)
                
            }
        }
    }
}

@MainActor func ?? <Element> (lhs: Binding<Element?>, rhs: Element) -> Binding<Element> {
    Binding {
        lhs.wrappedValue ?? rhs
    } set: { newValue in
        lhs.wrappedValue = newValue
    }
    
}

Если вы ищете ТАК, есть еще несколько.

Суть в том, чтобы разобраться с идентификацией до того, как заняться ее свойствами. Есть бесконечное количество способов справиться с этим.