This is second part of closures, if you
haven't gone thorough first part then please go through it before reading this.
In this part you will learn about completion
handlers,
when to use@escaping and trailing closure,so lets begin with it.
Trailing Closures
A
trailing closure can be used only if a function requires a
closure as the final argument/parameter. You may
trail (to follow behind) the closure argument parameter section. In other
words, the final parameter is separated from the normal function parameter
block.
Okay,
now it’s time to create a function that sums a range of values. Of course, we
are going to add timesTenFunc or timesTenClosure as the
final parameter.
func sum(from: Int, to: Int, closure:
(Int) -> (Int)) -> Int {
var sum = 0
for i in from...to {
sum += closure(i)
}
return sum
}
// Normal Closure calling
sum(from: 0, to: 10, closure: { number
in return number * 10 })
// Trailing Closure Longer Version
sum(from: 0, to: 10) { (number)
in
return number * 10
}
// Trailing Closure Shorter Version
sum(from: 0, to: 10) { return $0 * 10}
// Trailing Closure Extremely Short
Version
sum(from: 0, to: 10) { $0 * 10 }
So,
what’s the advantage of using trailing closures? Well, it is particularly
useful when your closure expression is longer than just simply multiplying
values or when you are using completion handlers, which I will talk about them
soon in this article. Trailing closures make code readable and eye friendly.
You can use normal closure, a trailing closure is optional, but most
developers love/use it.
Completion Handler
There
are times you put a closure as one of the parameters, but you only want to
execute the closure after the function returns. For example when you want to
notify user after downloading a file from the URL, we use completion handler in
this case.
// Create Function
func downloadFileFromURL(url: NSURL,
completionHandler: (Bool) -> Void) {
// NSURL logic code & download.
(return false/true)
completionHandler(true)
// Download has been completed
}
Surprisingly,
even before we call the function downloadFileFromURL, we’ve
provided a default parameter to the completionHandler block
by defining it as true only if the networking logic
has successfully gone through. So, when you run the function, the only
parameter you need to fill up is url and you can
notify the user based on whether the completionBlock is true or false
// Run function
downloadFileFromURL(url: NSURL(string:
"abc")!, completionHandler: {
isSuccessful -> Void in
if isSuccessful {
print("You've downloaded")
} else {
print("Unexpected error
encountered")
}
})
I
have arbitrarily called the predefined the name of the parameter (true/false)
as isSuccessful. The cool thing is, again, isSuccessfulalready has
its own value because we predefined while creating the function. However,
please remember that isSuccessful is only defined after going
through the network logic.
In
real life situation when you try to fetch data from Firebase/Facebook, you
will always ask to put something like
fetchProfileImage() { (imageFile, name, error) in
if error == nil {
}
// put into UIImage with imageFile/name
}
Escaping/Non Escaping Closures
There
are 2 types of closures, Escaping closure and non Escaping closures.
I
will explain you one by one
- Non Escaping Closure
The lifecycle of a non-escaping closure
is simple:
1.
Pass a closure into a function
2.
The function runs the closure (or not)
3.
The function returns
Notice the closure has not escaped the
body of the function. When the function ends, the passed-in closure goes out of
scope and there were no additional references made to the closure.
If you remember your memory management,
you might say the retains and releases are balanced; the closure object’s
retain count after the function returns is the same as it was before the
function was called.
- Escaping Closures
You can probably guess what “escaping
closure” means now. Inside the function, you can still run the closure (or
not); the extra bit is the closure is stored some place that will outlive the
function. There are several ways to have a closure escape its containing
function.
Asynchronous execution: If
you execute the closure asynchronously on a dispatch queue, the queue will hold
onto the closure for you. You have no idea when the closure will be executed
and there’s no guarantee it will complete before the function returns.
Storage: Storing
the closure to a global variable, property, or any other bit of storage that
lives on past the function call means the closure has also escaped.
0 comments:
Post a Comment