4

I have just begun learning Swift (and even newer at Swift UI!) so apologies if this is a newbie error.

I am trying to write a very simple programme where a user chooses someone's name from a picker and then sees text below that displays a greeting for that person.

But, the bound var chosenPerson does not update when a new value is picked using the picker. This means that instead of showing a greeting like "Hello Harry", "Hello no-one" is shown even when I've picked a person.


struct ContentView: View {

var people = ["Harry", "Hermione", "Ron"]
@State var chosenPerson: String? = nil

    var body: some View {
        NavigationView {
            Form {
        Section {
    Picker("Choose your favourite", selection: $chosenPerson) {
        ForEach ((0..<people.count), id: \.self) { person in
            Text(self.people[person])
            }
        }
        }

        Section{
            Text("Hello \(chosenPerson ?? "no-one")")
        }
        }
    }
   }
}

(I have included one or two pieces of the original formatting in case this is making a difference)

I've had a look at this question, it seemed like it might be a similar problem but adding .tag(person) to Text(self.people[person])did not solve my issue.

How can I get the greeting to show the picked person's name?

2 Answers 2

16

Bind to the index, not to the string. Using the picker, you are not doing anything that would ever change the string! What changes when a picker changes is the selected index.

struct ContentView: View {
    var people = ["Harry", "Hermione", "Ron"]
    @State var chosenPerson = 0
    var body: some View {
        NavigationView {
            Form {
                Section {
                    Picker("Choose your favourite", selection: $chosenPerson) {
                        ForEach(0..<people.count) { person in
                            Text(self.people[person])
                        }
                    }
                }
                Section {
                    Text("Hello \(people[chosenPerson])")
                }
            }
        }
    }
}

enter image description here

Sign up to request clarification or add additional context in comments.

1 Comment

Thank you. I thought that it was for the value and thus got the type wrong and it always return 0.0 . Now I just changed type from Double to Int and then it just worked.
1

The accepted answer is right if you are using simple arrays, but It was not working for me because I was using an array of custom model structs with and id defined as string, and in this situation the selection must be of the same type as this id. Example:

struct CustomModel: Codable, Identifiable, Hashable{

var id: String // <- ID of type string
var name: String
var imageUrl: String

And then, when you are going to use the picker:

struct UsingView: View {

@State private var chosenCustomModel: String = "" //<- String as ID
@State private var models: [CustomModel] = []


var body: some View {
 
        VStack{
            
                Picker("Picker", selection: $chosenCustomModel){
                        ForEach(models){ model in
                            Text(model.name)
                                .foregroundColor(.blue)
                        }
                    }
                }

Hope it helps somebody.

1 Comment

Your situation is a bit different from the original question (custom Identifiable struct vs String). There's an easier way if you have a struct that is Hashable and Identifiable -- no need to use indexes or ids. Just tag the content inside your ForEach with .tag(model), this will allow Picker to associate the content with your model. So: ``` Picker("Picker", selection: $model) { ForEach(models) { m in Text(m.name).tag(m) } } ```

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.