Swift : How $0 works in Array.forEach?
Solution 1
Short answer
Look at this code
let nums = [1,2,3,4]
nums.forEach { print($0) }
Here the closure following forEach
I mean this part
{ print($0) }
is executed 4 times (once for every element inside the array). Each time it is executed $0
contains a copy of the n-th
element of your thenums
array.
So the first time contains
1
, then2
and so on...
Here's the output
1
2
3
4
Comparing forEach
with the for-in
construct
So can we say tha $0
is like the n
value in the following code?
for n in nums {
print(n)
}
Yes, it has pretty much the same meaning.
How does it work?
The forEach
method accept a closure. The closure has this signature.
(Self.Generator.Element) throws -> Void
When you use the forEach
it makes a "contract" with you.
- You provide to the
forEach
a closure that accept a single param in input where the param has the same type of the Array - The
forEach
will apply that closure to each element of the array.
Example
nums.forEach { (n) in
print(n)
}
However in Swift you can omit explicit names for the parameters of a closure. In this inside the closure you can refer that params using $0
for the first param, $1
for the second one and so on.
So the previous snippet of code can be also be written like below
nums.forEach {
print($0)
}
Solution 2
Shorthand Argument Names
Swift automatically provides shorthand argument names to inline closures, which can be used to refer to the values of the closure’s arguments by the names $0, $1, $2, and so on.
If you use these shorthand argument names within your closure expression, you can omit the closure’s argument list from its definition, and the number and type of the shorthand argument names will be inferred from the expected function type. The in keyword can also be omitted, because the closure expression is made up entirely of its body:
reversed = names.sort( { $0 > $1 } ) Here, $0 and $1 refer to the closure’s first and second String arguments.
Solution 3
Functions like "forEach", "sort" take closure as an argument. These closures also have arguments, for example to a closure of "forEach" function you can provide your own name of an argument, or use the default one "$0". If the closure has multiple arguments (like function "sort" does) the default ones are gonna be "$0", "$1" if you provide none. Keep in mind closures can expect you to return some value, like "sort" does. You got the logic, here is example:
let array: [String] = []
array.forEach { element in
element.doStuff()
}
array.forEach {
$0.doStuff()
}
let sortedArray = array.sort { first, second in
return first < second
}
let sortedArray = array.sort {
return $0 < $1
}
SaRaVaNaN DM
Passionate about mobile technologies and would love to explore new things always. Mobile App Developer with 10 years of experience. Platform : iOS, React Native, Android Programming Languages : Swift, Objective-C, Java, C, Javascript, CSS, Html IDE : Xcode, VS Code, Android Studio, Intellij Voip : PJSip Version Control : Git, SVN
Updated on July 22, 2022Comments
-
SaRaVaNaN DM almost 2 years
I have seen most of the swift developer are starting using .forEach, understood its another way to iterate array. But what is the meaning of '$0' and how it works? If it's an index then it should increment 0,1,2...
@IBOutlet var headingLabels: [UILabel]! .... headingLabels.forEach { $0.attributedText = NSAttributedString(string: $0.text!, attributes: [NSKernAttributeName: 1]) }
-
SaRaVaNaN DM almost 8 yearsIn my case, it's alway $0. But still i can able to iterate all the elements.
-
Asdrubal almost 8 years$0 is the first argument in each iteration. Think of a for loop like this: for
(index, element) in list.enumerate() { print("Item \(index): \(element)") }
$0 would represent element. The only reason you would use this is to write code faster with less lines -
java_doctor_101 over 7 years@appzYourFile, how does the contract work under the hood? Do you know where I can find the source of this? Basically I am trying to figure out that when you call a method called foreach on an instance of type array how does that function know about the value present inside the array since all we are passing in that function is an empty closure variable. Right? How doe for each function actually gets the data of the array to iterate over? Thanks!
-
Luca Angeletti over 7 years@nitinsh99: Take a look here. Specifically the Inferring Type From Context and Shorthand Argument Names paragraphs
-
Motti Shneor over 7 yearsin $0, the 0 (zero) denotes the index of the function/closure argument - not the index of item in the array. This notion is familiar to unix shell-script and C developers where there are arg0 arg1 etc. denoting the arguments of a script or function.
-
Edison about 7 years@appzYourLife Great explanation. I've seen this on an online iOS interview test.