Reputation: 360
I just saw the sample code from Apple:
let timeRemainingFormatter: NSDateComponentsFormatter = {
let formatter = NSDateComponentsFormatter()
formatter.zeroFormattingBehavior = .Pad
formatter.allowedUnits = [.Minute, .Second]
return formatter
}()
var timeRemainingString: String {
let components = NSDateComponents()
components.second = Int(max(0.0, timeRemaining))
return timeRemainingFormatter.stringFromDateComponents(components)!
}
The question is: The constant and the variable are both declared with a closure, but one with an equal sign, the other is not. Why?
Upvotes: 5
Views: 829
Reputation: 1978
()
says "execute now and return the results." Now for a long-winded answer:
let timeRemainingFormatter: NSDateComponentsFormatter = {
// ...
}() // <- The '()' means "execute now and give me the formatter"
timeRemainingFormatter
will be calculated once, at init time, and the value will be stored. The parenthesis indicates that the closure should be executed immediately and the results returned, in this case to be stored as a property.
var timeRemainingString: String {
// ...
}
timeRemainingString
will be calculated each time it is called.
More generally, in Swift, functions are just named closures. Defining a function like:
func myFunc() -> Void {
print("Function")
}
is pretty much the same as defining a closure like:
let myClosure: () -> Void = {
print("Closure")
}
In both cases, you have a name (myFunc
/myClosure
), a call signature(() -> Void
), and a block of code ({ print(...) }
).
Just as you would call your function:
myFunc()
you could call your stored closure like:
myClosure()
and both would print.
Functions are pretty much just a convenience for defining named closures.
Let's say you had a global function and a global stored closure, defined respectively as:
func myIntFunc() -> Int { return 1 }
let myIntClosure: () -> Int = { return 2 }
The similarities should be pretty obvious.
Now you want to use them in a class as properties. You'd do
class MyClass {
let funcInt: Int = myIntFunc() // would resolve to 1
let closureInt: Int = myIntClosure() // would resolve to 2
}
Notice how you have ()
at the end of both of those. That says "execute my function/closure to get the Int
now."
Now imagine you don't want to define a global closure; you'd rather put that code in your class, to keep things organized. So you do:
class MyClass {
let funcInt: Int = myIntFunc() // would resolve to 1
let closureInt: Int = { return 2 }() // would resolve to 2
}
You still need to execute your closure to get the Int
out of it, just like the function. So you place ()
after it, just like the function.
Lastly, we will touch on the "calculated property".
var timeRemainingString: String {
// ...
}
You can think of this as a way of writing a function that takes no arguments, and thus you get a short-cut call signature (you can treat it like a property). It's really like the closure is being stored by the property, but because it is a special notation, Swift knows to execute the closure and returns its result every time you call for the property. Thus this is a "calculated property".
When you call:
let timeRemaining = instance.timeRemainingString
Swift is really translating that to:
let timeRemaining = instance.timeRemainingString()
It's just adding the ()
for you to make the stored closure execute.
Things are actually a little more complicated than that, because you can define setter closures along with the getters we've just discussed, and even observer closures as well. Swift will just dispatch to the correct closure depending on what kind of operation you're trying to perform.
Upvotes: 8