Reputation: 49
I was reading a blog and there was a function like below. I want to know what could be the purpose of writing it in this way?
public func moveNinjaToBottomRight() {
ninja.center = {
let x = (frame.maxX - ninja.frame.width / 2)
let y = (frame.maxY - ninja.frame.height / 2)
return CGPoint(x: x, y: y)
}()
}
Upvotes: 0
Views: 95
Reputation: 17969
The parens after the braced expression are called an Immediately Invoked Closure and have the effect of executing the closure inside the braces.
The style is commonly used for initialisation where it serves a valuable purpose of allowing you to create a property with complex initialisation:
public let ninja: UIImageView = {
let image = UIImage(named: "ninja")
let view = UIImageView(image: image)
view.frame = CGRect(x: 0, y: 0, width: 45, height: 39)
return view
}()
Using it inside a function as you have shown has no technical purpose. It is likely to be less efficient unless the compiler is capable of optimising it to simpler logic.
It maintains a consistency with the way they are initialising variables elsewhere in the sample (assuming you are looking at the same code I found).
In C programming, it's common to just use a pair of braces to provide local scoping of variables. That is a robust programming practice to ensure they are not re-used further down a method.
The Swift idiom is to use do { ...}
if you want to achieve such scoping.
So, to be clear, the function you are looking at could have been written plainly
public func moveNinjaToBottomRight() {
let x = (frame.maxX - ninja.frame.width / 2)
let y = (frame.maxY - ninja.frame.height / 2)
ninja.center = CGPoint(x: x, y: y)
}
Or even
public func moveNinjaToBottomRight() {
ninja.center = CGPoint(
x: (frame.maxX - ninja.frame.width / 2),
y: (frame.maxY - ninja.frame.height / 2))
}
Or, if there was more logic and they wanted local scoping.
public func moveNinjaToBottomRight() {
do {
let x = (frame.maxX - ninja.frame.width / 2)
let y = (frame.maxY - ninja.frame.height / 2)
ninja.center = CGPoint(x: x, y: y)
}
// more code here which wants to use x and y names
// but is not reusing the variables above
}
Upvotes: 1
Reputation: 154583
This is just a matter of style.
Writing the function this way:
public func moveNinjaToBottomRight() {
ninja.center = {
let x = (frame.maxX - ninja.frame.width / 2)
let y = (frame.maxY - ninja.frame.height / 2)
return CGPoint(x: x, y: y)
}()
}
adds clarity to the purpose of the function. At a glance you can see that it just updates ninja.center
and you know that the code inside the closure is computing that new center. This would especially be true if computing the new center took many more lines.
The other way to write it would be:
public func moveNinjaToBottomRight() {
let x = (frame.maxX - ninja.frame.width / 2)
let y = (frame.maxY - ninja.frame.height / 2)
ninja.center = CGPoint(x: x, y: y)
}
In this case, you have to read through all of the lines before you get to what the function really does. Again, for such a short function it makes little difference, but it it were longer it would take the reader longer to access what was going on.
I would recommend only using this functional style if the code inside the closure has a specific purpose. In this case it is creating a CGPoint
. If the code in the closure was causing side effects like playing sounds or updating the user interface, then that I believe the imperative style used by the second example makes more sense.
Upvotes: 1