Я пытаюсь понять Equatable. Когда я использую Equatable в своей структуре CreateCustomer, почему я не могу добавить больше типов телефонов, если я установил один, или когда я добавил больше, почему я могу установить только один? Без Equatable в моей структуре все работает нормально.
Вот мое представление SwiftUI для установки типа телефона
struct T01: View{
@State var phoneTypes: [String] = ["Other", "Home", "Service", "Work", "Cell"]
@State var customerCreate: CreateCustomer = CreateCustomer()
var body: some View {
VStack{
if (customerCreate != CreateCustomer()){
Button(action: {
customerCreate = CreateCustomer()
}, label: {
Text("Clear").padding()
})
}
ForEach($customerCreate.phone.indices, id: \.self) { i in
Menu {
ForEach(phoneTypes, id: \.self){ client in
Button() {
let x = client
customerCreate.phone[i].phoneType = x
print(customerCreate.phone[i].phoneType)
} label:{
Text(client)
if customerCreate.phone[i].phoneType == client
{
Image(systemName: "checkmark")
}
}
}
} label: {
VStack{
HStack{
Spacer()
Text(customerCreate.phone[i].phoneType.isEmpty ? "Select the phone type *" : customerCreate.phone[i].phoneType)
.foregroundColor(customerCreate.phone[i].phoneType.isEmpty ? .gray : .black)
Image(systemName: "chevron.down")
.foregroundColor(Color.green)
Spacer()
}
}
}
}
Button(action: {
customerCreate.addPhone()
}, label: {
HStack {
Image(systemName: "plus.circle")
.font(.system(size: 15))
Text("Add Phone")
.fontWeight(.thin)
.font(.system(size: 15))
}
})
}
}
}
struct CreateCustomer: Codable, Equatable {
static func == (lhs: CreateCustomer, rhs: CreateCustomer) -> Bool {
// It can be fixed by changing == to > but I want the == so I can know if I should display the clear button or not.
return String(lhs.phone.first?.phoneType ?? "") == String(rhs.phone.first?.phoneType ?? "")
}
var phone: [CustomerPhone]
init() {
phone = [CustomerPhone()]
}
public mutating func addPhone(){
phone.append(CustomerPhone())
}
}
struct CustomerPhone: Codable {
var phone: String
var phoneType: String
init(){
phone = ""
phoneType = ""
}
}
Спасибо за любую помощь!!!!
@AshleyMills Спасибо, я пытался сделать его более минимальным. Кажется, что это ошибка только тогда, когда есть структура внутри другой структуры, что делает код немного запутанным для чтения.
Очень сложно понять ваш код, например customerCreate != CreateCustomer() и phone.append(CustomerPhone()). Почему вы создаете новые объекты во многих местах?
@JoakimDanielson customerCreate != CreateCustomer() Это сравнивает локальный объект с пустым, чтобы определить, должна ли быть видна кнопка очистки, для которой требуется Equatable . В то время как phone.append(CustomerPhone()) должен добавить новый телефон клиента в массив и работает только без Equatable. Я постараюсь добавить некоторые комментарии.
Это IMO не лучший способ сделать это, лучше, чем иметь вычисляемое свойство или функцию, которая возвращает логическое значение, является ли объект пустым или нет.
@JoakimDanielson Спасибо! Звучит хорошо, я сделаю это и удалю Equatable. Тем не менее интересно, что добавление Equatable нарушает его функциональность.
indices
и ярости небезопасны в SwiftUI, вы должны использовать сами объекты и соответствовать Identifiable
Разве ForEach($customerCreate.phone.indices) не сломан полностью? Я не могу протестировать его прямо сейчас, но я ожидаю, что он будет обновлять содержимое своего представления только при изменении количества элементов (что приводит к изменению индексов), но не при изменении любой из записей на месте.
@Alexander Александр, да, Equatable static func == (lhs: CreateCustomer, rhs: CreateCustomer), кажется, ломает обновление, поэтому я изменил его, чтобы использовать var isEmpty: Bool как решение, и теперь оно работает нормально :)
@micah, ты понимаешь, что здесь делает соответствие Equatable? Я думаю, что есть недостающая часть, которая вызывает у вас некоторое замешательство.
С небольшой очисткой и переименованием, а также созданием Customer ObservableObject, я думаю, это делает то, что вы хотите…
struct ContentView: View {
@State var phoneTypes: [String] = ["Other", "Home", "Service", "Work", "Cell"]
@StateObject var customer = Customer()
var body: some View {
VStack{
if !customer.isEmpty {
Button(action: {
customer.phones = []
}, label: {
Text("Clear").padding()
})
}
ForEach($customer.phones.indices, id: \.self) { i in
Menu {
ForEach(phoneTypes, id: \.self) { phoneType in
Button() {
customer.phones[i].phoneType = phoneType
print(customer.phones)
} label:{
Text(phoneType)
if customer.phones[i].phoneType == phoneType {
Image(systemName: "checkmark")
}
}
}
} label: {
VStack{
HStack{
Spacer()
Text(customer.phones[i].phoneType.isEmpty ? "Select the phone type *" : customer.phones[i].phoneType)
.foregroundColor(customer.phones[i].phoneType.isEmpty ? .gray : .black)
Image(systemName: "chevron.down")
.foregroundColor(Color.green)
Spacer()
}
}
}
}
Button(action: {
customer.addPhone()
print(customer.phones)
}, label: {
HStack {
Image(systemName: "plus.circle")
Text("Add Phone")
.fontWeight(.thin)
}
})
.font(.system(size: 15))
}
}
}
final class Customer: ObservableObject {
@Published var phones: [CustomerPhone]
var isEmpty: Bool {
phones == [CustomerPhone()]
}
init() {
phones = [CustomerPhone()]
}
public func addPhone(){
phones.append(CustomerPhone())
}
}
Вот как я бы реализовал Customer и CustomerPhone и как проверить, пуст ли объект Customer
struct Customer: Codable, Equatable {
var phones: [CustomerPhone]
init() {
phones = [CustomerPhone()]
}
public mutating func add(phone: CustomerPhone = CustomerPhone()){
phones.append(phone)
}
var isEmpty: Bool {
phones.isEmpty || phones.allSatisfy(\.isEmpty)
}
}
struct CustomerPhone: Codable, Equatable {
var phone: String
var phoneType: String
init(){
phone = ""
phoneType = ""
}
var isEmpty: Bool {
phone.isEmpty && phoneType.isEmpty
}
}
Спасибо!!!! Не знал, что можно сделать Equatable без static func == (lhs: CreateCustomer, rhs: CreateCustomer), супер круто!!!!!
@micah в некоторых случаях компилятор может автоматически синтезировать оператор равенства для структур и перечислений.
Несколько вещей, прежде чем попытаться ответить на вопрос. Использование соглашений о кодировании Swift облегчает чтение вашего кода, поэтому используйте UpperCamelCase для имен типов и протоколов и LowerCamelCase для всего остального (и змеиный регистр нигде). Так что customerCreate вместо Customer_Create, var phone: String вместо var Phone: String и т. д. Кроме того, пожалуйста, просто используйте минимальный код, демонстрирующий проблему, и убедитесь, что он компилируется (приведенный выше код не компилируется). Для справки см. минимальный воспроизводимый пример