Home > front end >  Swift Equatable Struct doesn't allow updating?
Swift Equatable Struct doesn't allow updating?

Time:01-11

I'm trying to understand Equatable. When I using Equatable on my CreateCustomer struct why can I not add more phone types if I set one, or when I have added more why can I only set one? Without Equatable on my struct it works fine.

Here is my SwiftUI view to set the phone type

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 = ""
    }
}

Thanks for any help!!!!

CodePudding user response:

This is how I would implement Customer and CustomerPhone and how to check if a Customer object is empty

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
    }
}

CodePudding user response:

With a bit of tidying up and renaming, and making Customer an ObservableObject, I think this does what you want…

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())
    }    
}

  • Related