Sunday, June 25, 2017

Closures Part - 2 (Swift)

4:10 AM Posted by CHANDAN MAKHIJA No comments
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