Welcome to the Treehouse Community
Want to collaborate on code errors? Have bugs you need feedback on? Looking for an extra set of eyes on your latest project? Get support with fellow developers, designers, and programmers of all backgrounds and skill levels here with the Treehouse Community! While you're at it, check out some resources Treehouse students have shared here.
Looking to learn something new?
Treehouse offers a seven day free trial for new students. Get access to thousands of hours of content and join thousands of Treehouse students and alumni in the community today.
Start your free trialNicoara Talpes
7,354 Pointshow does he use the let keyowrd in the short downloadTaskWithRequest form?
Hello everyone, how come this works and what does it do? (let url, let response, let error)
4 Answers
Jhoan Arango
14,575 PointsHello:
So you want to understand why Pasan did the closure the way he did ?
Closures are a tricky thing to understand sometimes, but once you get the hang of it, they are kind of amazing.
On the same example that you gave:
(url: NSURL?, response: NSURLResponse?, error: NSError?) -> Void
If you look at it, it kind of looks like a function..well basically IT is a function.
Let's take a look:
func nameOfFunction (url: NSURL?, response: NSURLResponse?, error: NSError?) -> Void {
// Do your work here.
}
See very similar..
Now when you are dealing with a closure, and its the last parameter in a function, then you can use a "trailing closure". Basically making it shorter and more readable. But you still have to give them its parameters.
Swift shows you the "skeleton" of closure as you type, giving you an idea of what the parameters should be named and their type.
// Here we see that this closure has 3 parameters
(url: NSURL?, response: NSURLResponse?, error: NSError?) -> Void
// So when writing the trailing closure you can do it like this
(let url, let response, let error ) in
// Think of it as if we had done it like this
(let url: NSURL?, let response: NSURLResponse?, let error: NSError? ) -> Void
/*
But what Pasan was showing you is that swift is so SMART that it already knows
what the parameter's types are therefore we can skip writing them explicitly.
*/
// But that's not the end of it... we can even make it shorter and simpler
(url, response, error ) in
// do your work here
we do not specify their type because swift "knows" what type they should be since they are "required". You can named those parameters whatever you want, but it will make more sense to go with what they show you.
(let url: let response, let error ) in
/*
Swift infers that "let url" is of type NSURL
and that "let response" is of type NSURLResponse, and so on.
That is why we do not specify their type.
*/
I hope this answer helps you understand a bit more, if you need more help please let me know..
Good luck.
jcorum
71,830 PointsSorry, one never knows for sure what level someone's at!
Yes, there are other uses for let in Swift. Your example of an enum shows one of them. Optional binding is another.
Here's an excerpt from the Swift documentation about enums with associated values that might help explain what is going on in your enum example:
"In Swift, an enumeration to define product barcodes of either type [UPCA or QR] might look like this:
enum Barcode { case UPCA(Int, Int, Int, Int) case QRCode(String) } This can be read as:
“Define an enumeration type called Barcode, which can take either a value of UPCA with an associated value of type (Int, Int, Int, Int), or a value of QRCode with an associated value of type String.”
This definition does not provide any actual Int or String values—it just defines the type of associated values that Barcode constants and variables can store when they are equal to Barcode.UPCA or Barcode.QRCode.
New barcodes can then be created using either type:
var productBarcode = Barcode.UPCA(8, 85909, 51226, 3)
This example creates a new variable called productBarcode and assigns it a value of Barcode.UPCA with an associated tuple value of (8, 85909, 51226, 3).
The same product can be assigned a different type of barcode:
productBarcode = .QRCode("ABCDEFGHIJKLMNOP")
At this point, the original Barcode.UPCA and its integer values are replaced by the new Barcode.QRCode and its string value. Constants and variables of type Barcode can store either a .UPCA or a .QRCode (together with their associated values), but they can only store one of them at any given time.
The different barcode types can be checked using a switch statement, as before. This time, however, the associated values can be extracted as part of the switch statement. You extract each associated value as a constant (with the let prefix) or a variable (with the var prefix) for use within the switch case’s body:
switch productBarcode { case .UPCA(let numberSystem, let manufacturer, let product, let check): print("UPC-A: (numberSystem), (manufacturer), (product), (check).") case .QRCode(let productCode): print("QR code: (productCode).") } // Prints "QR code: ABCDEFGHIJKLMNOP." If all of the associated values for an enumeration case are extracted as constants, or if all are extracted as variables, you can place a single var or let annotation before the case name, for brevity:
switch productBarcode { case let .UPCA(numberSystem, manufacturer, product, check): print("UPC-A: (numberSystem), (manufacturer), (product), (check).") case let .QRCode(productCode): print("QR code: (productCode).") } // Prints "QR code: ABCDEFGHIJKLMNOP."
But that's not what Pasan is doing in this video.
Re the 3 accent marks. If you don't leave a blank line before and after them your code won't display properly.
Nicoara Talpes
7,354 PointsI understand. So back to my original question, what does he do in this video?
jcorum
71,830 PointsMy apologies. I originally thought you were asking about the constant declarations Pasan was writing around 1:05 in the video. Now I see I was wrong. I didn't watch enough. You were asking about the two ways Pasan wrote the trailing closure around 5:20 of the video.
As I guess you already know, one way to write a trailing closure is:
{(parameters) -> (return type) in ... }
One of the examples in the Swift documentation, for example, is:
let digitNames = [
0: "Zero", 1: "One", 2: "Two", 3: "Three", 4: "Four",
5: "Five", 6: "Six", 7: "Seven", 8: "Eight", 9: "Nine"
]
let numbers = [16, 58, 510]
let strings = numbers.map {
(number) -> String in //number is a parameter
var number = number
var output = ""
while number > 0 {
output = digitNames[number % 10]! + output
number /= 10
}
return output
}
The documentation explains the line var number = number by saying "In this example, the variable number is initialized with the value of the closure’s number parameter, so that the value can be modified within the closure body. (The parameters to functions and closures are always constants.)"
Adding let before number in the above example changes nothing when run in Xcode.
Pasan could have written { (url, response, error) in ... } but he chose to make their constant status explicit.
Bottom line, url, response, error are constant parameters for the closure.
jcorum
71,830 PointsSwift documentation: "You declare constants with the let keyword and variables with the var keyword."
Pasan may seem to be muddying the water a bit by saying:
"First, I'm going to create a session variable. 0:31 Next, I'll create a URL. 0:50 Then a request variable. 0:56 And we'll initialize it using the URL."
The three "variables" he creates are actually constants.
But he's in good company, as the Apple documentation also says: "Swift uses variables to store and refer to values by an identifying name. Swift also makes extensive use of variables whose values cannot be changed. These are known as constants, and are much more powerful than constants in C. Constants are used throughout Swift to make code safer and clearer in intent when you work with values that do not need to change."
So perhaps we should think of it this way: var creates variables that can be changed while let creates variables that cannot be changed (i.e., are not variable!).
Nicoara Talpes
7,354 PointsHello, Thanks for answering, I know the difference between var and let. My question is unclear, so I will ask again.
In the optionals course, he uses a similar notation :
enum Button {
case Done(String)
case Edit(String)
func toUIBarButtonItem() -> UIBarButtonItem {
switch self {
case .Done(let title): return UIBarButtonItem(title: title, style: UIBarButtonStyle.Done, target: nil, action: nil)
case .Edit(let title): return UIBarButtonItem(title: title, style: UIBarButtonStyle.Plain, target: nil, action: nil)
}
}
}
where he uses "let title" as an argument to pass the associated value of the Done member.
I do not understand how he goes from:
(url: NSURL?, response: NSURLResponse?, error: NSError?) -> Void
to
(let url, let response, let error)
, apart from using the shorthand syntax of inferring the type and not mentioning the return type. Thanks