This is a companion discussion topic for the original entry at https://www.raywenderlich.com/5994-programming-in-swift/lessons/34
This is a companion discussion topic for the original entry at https://www.raywenderlich.com/5994-programming-in-swift/lessons/34
I have some questions about closures and scope.
This code is a bit confusing to me. When I try to break it down…
(line50) if true (if we get a positive match)- actually, what are we checking exactly? The contents of the if statement?
(line51) define new constant ‘myName’ to have the value “Ray” (a string)
(line52) ‘printClosure’ ??? is this a var that was previously declared outside of the scope? If so, then this variable runs the print function on the constant created in the if statement?
Or, it’s a closure, but missing the parameters because it was possible to shorten it, so it went from something like ‘printClosure: type = { return }’
I would really appreciate a clarification on that.
Also, I’m struggling to understand the scope in the ‘increment count’ closure.
You make two statements: “The ‘count’ variable is declared outside of the closure” and “the closure is able to access the variable because the closure is defined in the same scope as the variable” -
-I understand the first part. The closure starts after the opening curly brace. Or is it part of the constant ‘incrementCount’?
-For the second part, do you just mean the global scope?
Finally, in the last example:
(line72) = the function returns () → Int
from my understanding, that means, it doesn’t take any parameters, and then returns an Int.
does this need to go in there to match the type of the closure?
(line74) = the ‘incrementCount’ constant is of the same type () → Int
(line76) = the closure returns the ‘count’ which has been transformed by the closure
(line78) = the function, which contains the closure, returns the ‘incrementCount’ value.
Is ‘incrementCount’ considered a constant? or just a closure?
if true (if we get a positive match)- actually, what are we checking exactly? The contents of the if statement?
What gets evaluated is the expression between the if
keyword and the {
. That’s true
, so the code within will run. We don’t get into do
statements in this course, but the end result is exactly the same as using do
instead of if true
.
‘printClosure’ ??? is this a var that was previously declared outside of the scope?
Yes.
If so, then this variable runs the print function on the constant created in the if statement?
When called, yes.
-I understand the first part. The closure starts after the opening curly brace. Or is it part of the constant ‘incrementCount’?
incrementCount
references the closure.
-For the second part, do you just mean the global scope?
It could be, but the exact scope is not important, just that the scope is the same.
the function returns
() -> Int
from my understanding, that means, it doesn’t take any parameters, and then returns an Int.
Your understanding may be correct, depending on what you mean by “it”. If “it” is the type of what will be returned from the function, then yes, your understanding is spot-on.
does this need to go in there to match the type of the closure?
What does “the closure” refer to? Perhaps this simpler way of writing it will help you:
func makeCountingClosure() -> () -> Int {
var count = 0
return {
count += 1
return count
}
}
Is ‘incrementCount’ considered a constant? or just a closure?
It’s a constant that references a closure. As shown above, it’s not necessary, but it followed from the previous example where incrementCount
was not defined within a function.
Thank you for your reply.
Is there a way to rewrite the first bit of code and have it work in xcode?
As it is, it gives the following error: “use of unresolved identifier 'printClosure.”
The only way I got it to work was by removing the if statement and declaring a variable for the closure to refer to:
I realize that the if statement may have just been there to illustrate the scope/capturing concept… Sorry if I’m over-thinking this.
.
Question 2: If you always need to declare the type of the closure, are void closures the exception to this rule? If it’s of type () → Void, can you skip over declaring the type and go straight to the assigning step?
‘printClosure’ is of the type as () → (), so that’s why I’m wondering.
.
I think I’ve got it now: The return type of the function must match the closure type for the function to be able to return the closure.
In this example, that’s why we set the return type of the function to () → Int. It’s literally because we’re returning the closure as a last step, which is of type () → Int itself, and both need to match.
Also, the closure is of that type because we’re not passing any arguments when calling it (it has no parameters), we’re only returning an Int that incrementally increases by one.
I realize that the if statement may have just been there to illustrate the scope/capturing concept…
It was! That’s why we only had it on the slide and not in the playground. But now that we see that it might confuse someone, we’ll try to be more clear in the next update.
Is there a way to rewrite the first bit of code and have it work in xcode?
Here’s the simplest, using a do
block like I mentioned to create a new scope:
let printClosure: () -> Void
do {
let myName = "Ray"
printClosure = {
print(myName)
}
}
printClosure()
If you always need to declare the type of the closure, are void closures the exception to this rule? If it’s of type () -> Void, can you skip over declaring the type and go straight to the assigning step?
It may be obvious from the beginning of this post, but no.
The rest of what you said sounds exactly right!
Very difficult to understand this topic, need more explanation I’ve been getting everything until now
@brunomj1997 Please let us know what you don’t understand exactly when you get a chance. Thank you!