TEAM LICENSES: Save money and learn new skills through a Hacking with Swift+ team license >>

SOLVED: Day 25 - ForEach not working when creating buttons for an array of items

Forums > 100 Days of SwiftUI

I'm trying to generate a row buttons for rock, paper, and scissors (3 buttons) using a ForEach loop, but it's not working.

let choices = ["rock", "paper", "scissors"]
HStack {
    ForEach(choices, id: \.self) {
        Button {
            MoveButton(name: $0.capitalized, image: $0)
        }
    }
}

At the ForEach line, I'm getting error:

Contextual type for closure argument list expects 1 argument, which cannot be implicitly ignored. Insert '_ in'

accompanied by this error at the Button line:

Contextual closure type '() -> MoveButton' expects 0 arguments, but 1 was used in closure body

This, however, works

HStack(spacing: 15) {
    ForEach(choices, id: \.self) {
        MoveButton(name: $0.capitalized, image: $0)
    }
}

Writing ForEach using indexes also works

HStack(spacing: 15) {
    ForEach(0..<3) { index in
        Button {
            print("Buttons were generated!")
        } label: {
            MoveButton(name: choices[index].capitalized, image: choices[index])
        }
    }
}

Could someone help me understand why reading directly into the array is causing problems with Button? Thanks!

For context, MoveButton is just a separate view generating button appearance. It's not a button itself (hence why I'm trying to wrap it in a Button).

struct MoveButton: View {
    var name: String
    var image: String

    var body: some View {
        VStack {
            Image(image)
                .resizable()
                .frame(width: 50, height: 50)
                .frame(width: 100, height: 100)
                .background(Color("color-background-alt"))
                .cornerRadius(10)
                .padding(.bottom, 10)
                .shadow(color: .black.opacity(0.15), radius: 5, x: 0, y: 5)

            Text(name)
                .font(.custom("Inter-Medium", size: 14))
        }
    }
}

2      

HStack {
    ForEach(choices, id: \.self) {
        Button {
            MoveButton(name: $0.capitalized, image: $0)
        }
    }
}
  1. $0 here refers to the argument to the Button's closure, not the ForEach's. But you aren't passing in anything for $0 to be a reference to. And you use neither an explicit parameter nor a shorthand parameter in your ForEach. Hence the first error message.
  2. Button takes 2 closures, one for the action and one for the label. The action closure takes no arguments, but you are using $0, which indicates there should be an argument. Hence the second error message.

You need to do something like this:

HStack {
    ForEach(choices, id: \.self) { choice in
        Button {
            //whatever the action is supposed to be
        } label: {
            MoveButton(name: choice.capitalized, image: choice)
        }
    }
}

3      

Hacking with Swift is sponsored by String Catalog.

SPONSORED Get accurate app localizations in minutes using AI. Choose your languages & receive translations for 40+ markets!

Localize My App

Sponsor Hacking with Swift and reach the world's largest Swift community!

Reply to this topic…

You need to create an account or log in to reply.

All interactions here are governed by our code of conduct.

 
Unknown user

You are not logged in

Log in or create account
 

Link copied to your pasteboard.