Home > Software engineering >  How to use .contains with array of Struct in SwiftUI?
How to use .contains with array of Struct in SwiftUI?

Time:08-26

I'm trying to check if my appearedNames array already contains my currentPerson string but unfortunately i got this error: Cannot convert value of type 'String?' to expected argument type '(ColoredName) throws -> Bool'... how should i use .contains with a struct?

struct ColoredName: Identifiable {
    let id = UUID()
    var name: String
    var color: Color
}

struct ContentView: View {
    @State private var names = ["Steve", "Bill", "Jeff", "Elon"]
    @State private var appearedNames = [ColoredName]()
    @State private var currentPerson: String?
    
    var body: some View {
        NavigationView {
            VStack {
                NavigationLink("Change view") {
                    SecondView(appearedNames: $appearedNames)
                }
                
                HStack {
                    Button {
                        if currentPerson != nil && !appearedNames.contains(currentPerson) // <-- I got the error here {
                            appearedNames.append(ColoredName(name: currentPerson ?? "", color: .red))
                        }
                        changePerson()
                    } label: {
                        Text(currentPerson ?? "Start")
                            .foregroundColor(currentPerson != nil ? .red : .black)
                            .font(.largeTitle)
                    }
                    
                    Button {
                        if currentPerson != nil {
                            appearedNames.append(ColoredName(name: currentPerson ?? "", color: .green))
                        }
                        changePerson()
                    } label: {
                        Text(currentPerson ?? "Start")
                            .foregroundColor(currentPerson != nil ? .green : .black)
                            .font(.largeTitle)
                    }
                }
            }
        }
    }
    func changePerson() {
        if names.count > 0 {
            let index = Int.random(in: 0..<names.count)
            currentPerson = names[index]
            names.remove(at: index)
        }
    }
}

struct SecondView: View {
    @Binding var appearedNames: [ColoredName]
    
    var body: some View {
        VStack {
            ForEach(appearedNames) { person in
                Text(person.name)
                    .foregroundColor(person.color)
                    .font(.largeTitle)
                    .bold()
            }
        }
    }
}

CodePudding user response:

try something like this, where you compare the name of the ColoredName in the array, with the String currentPerson (unwrapped):

if currentPerson != nil && !appearedNames.contains(where: { $0.name == currentPerson!} )  {
      appearedNames.append(ColoredName(name: currentPerson ?? "", color: .red))
  }

or, alternatively:

if let theName = currentPerson, !appearedNames.contains(where: { $0.name == theName} )  {
    appearedNames.append(ColoredName(name: theName, color: .red))
}
  • Related