UPGRADE YOUR SKILLS: Learn advanced Swift and SwiftUI on Hacking with Swift+! >>

SOLVED: Day 21: Why doesn't ForEach work with $0 notations in this case?

Forums > 100 Days of SwiftUI

Here's the original snippet from the tutorial:

ForEach(0..<3) { number in
    Button {
       // flag was tapped
    } label: {
        Image(countries[number])
            .renderingMode(.original)
    }
}

I thought I could get away without using the 'number' variable by using the shorthand syntax, like:

ForEach(0..<3) {
 Button {
     //code
 } label: {
     Image(countries[$0])
 }
}

It raised errors about contextual type of closure and suggested using '_ in' (Contextual type for closure argument list expects 1 argument, which cannot be implicitly ignored)

But it works with simple text views:

ForEach(0..<3) {
//
               Text("\($0)")
            }

Furthermore, even using the suggested "_ in" fix raised errors:

ForEach(0..<3) {_ in
                Button {
                    //code
                } label: {
                  Image(countries[_])
                        .renderingMode(.original)
                }

            }

('_' can only appear in a pattern or on the left side of an assignment)

My questions are two fold: (a) Why is the $0 notation not working in this ForEach in this case? (It seem to work in a simple Text("\($0)") view) (b) Why is the ''_ in" format not valid here (i.e., it requires some variable (in this case, 'number'))

(I tried google search but all the questions around this are a bit too complex for the time being)

Thanks

3      

ForEach(0..<3) {
    Button {
        //code
    } label: {
        Image(countries[$0])
    }
}

This doesn't work because the initializer you are using for Button is this one:

init(
    action: @escaping () -> Void,
    label: () -> Label
)

Note that the action and label parameters are closures, which means that $0 you are trying to use in label actually refers to the first parameter passed into that closure, not the parameter of the ForEach. Except, hang on, the action and label closures do not take any parameters. And so, you get an error.

You can see that $0 doesn't belong to the ForEach if you add a line like so:

ForEach(0..<3) {
    let _ = print($0)
    Button {
        //code
    } label: {
        Image(countries[$0])
    }
}

When you do that, this error will disappear: Contextual type for closure argument list expects 1 argument, which cannot be implicitly ignored because you are no longer ignoring the parameter to the ForEach.

It works here:

ForEach(0..<3) {
    Text("\($0)")
}

because Text is taking in either a LocalizedStringKey or a String rather than a closure, so $0 in this case refers to the parameter of the ForEach as you would expect.

This code:

ForEach(0..<3) {_ in
    Button {
        //code
    } label: {
      Image(countries[_])
        .renderingMode(.original)
    }
}

doesn't work for a couple of reasons.

First is because of the same reason the first example above didn't work; you are trying to reference a parameter passed to the label closure but that closure doesn't take any parameters.

Second, and most importantly, you can't access an array this:

countries[_]

Ultimately, you end up having to do this:

ForEach(0..<3) { number in
    Button {
        //code
    } label: {
      Image(countries[number])
        .renderingMode(.original)
    }
}

Hope that helps explain what's going on.

6      

Wow, this seems important. I learned from this thread. Thank you both.

2      

Nice! I've had this question before and I've never looked it up. Thanks!

1      

BUILD THE ULTIMATE PORTFOLIO APP Most Swift tutorials help you solve one specific problem, but in my Ultimate Portfolio App series I show you how to get all the best practices into a single app: architecture, testing, performance, accessibility, localization, project organization, and so much more, all while building a SwiftUI app that works on iOS, macOS and watchOS.

Get it on Hacking with Swift+

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

Archived topic

This topic has been closed due to inactivity, so you can't reply. Please create a new topic if you need to.

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.