Is There Any Particular Use of Closure in Swift? and What's the Benefit

Is there any particular use of closure in swift? and what's the benefit?

The question might be a little broad, but I will try to recap.

Referring to the Documentation:

Closures are self-contained blocks of functionality that can be passed
around and used in your code.

You should use closure(s) when you want to pass a chunk of code as a parameter to a method that you want to execute it asynchronously.

To make it simpler -by giving a real-world example-, imagine that there is a method responsible for scanning the user's photos, so the method should returns an array of photos and another array of videos:

Pesudo-code:

// the method should scan the the user's photos and return them after fetching is finished

// the 'completion' (success) closure should returns two arrays
// what if there is something wrong happened? another closure should returns an error

// for the example purposes they are arrays of strings, the error is also a string
func scanPhotos( completion: @escaping (_ photos: [String], _ videos: [String]) -> (), failure: @escaping (String) -> ()) {
// imagine that the scanning has been successfully done and you filled the two arrays:

//if scanningSuccess {
let fetchedPhotos = [String]()
let fetchedVideos = [String]()

completion(fetchedPhotos, fetchedVideos)
//} else {
// if something goes wrong
failure("the error!!")
//}
}

Calling the method:

scanPhotos(completion: { (photos, videos) in
// now you can use the fetched photos and videos
}, failure: { error in
// display an alert -for example- based on the error is saying...
})

Note the the scanning proccess should be executed asynchronously, when it finished, one of the two blocks (success or failure) should be executed.


Some of the popular methods that work with clousres:

  • animateWithDuration:animations:completion:
  • urlSession(_:dataTask:didReceive:completionHandler:)
  • sort(by:)

AGAIN: it is just a simple usage of the closures; You need to check the documentation for more details.

I hope it helped.

When to use closures in swift?

The two most used cases are completion blocks and higher order functions in Swift.

Completion blocks: for example, when you have some time consuming task, you want to be notified when that task is finished. You can use closures for that, instead of a delegate (or many other things)

func longAction(completion: () -> ()) {
for index in veryLargeArray {
// do something with veryLargeArray, which is extremely time-consuming
}
completion() // notify the caller that the longAction is finished
}

//Or asynch version
func longAction(completion: () -> ()) {

dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0)) {

for elem in veryLargeArray {
// do something with veryLargeArray, which is extremely time-consuming
}
dispatch_async(dispatch_get_main_queue(), {
completion() // notify the caller that the longAction is finished
})
}
}

longAction { print("work done") }

In the example above, when you have a time consuming task, you want to know when the for loop finishes iterating through the very large array. You put the closure { println("work done") } as an input parameter for the function which will be executed after the for loop finishes its work, and print "work done". And what happened is that you gave a function (closure) to longAction and name it to completion, and that function will be executed when you call completion in longAction.

Higher order functions: you can use closures as input parameters for higher order functions, for example:

let array = [1, 2, 3]
let smallerThanTwo = array.filter { $0 < 2 }

With this, you can filter out the numbers that are smaller than 2.

UPDATED About how sorted (probably) works:

So the idea is, that sorted will go through the array, and compare two consecutive elements (i, i + 1) with each other, and swap them, if needed. What does it mean "if needed"? You provided the closure { (s1: String, s2: String) -> Bool in return s1 > s2 }, which will return true if s1 is lexiographically greater than s2. And if that closure returned true, the sorted algorithm will swap those two elements, and countinues this with the next two elements (i + 1, i + 2, if the end of the array is not reached). So basically you have to provide a closure for sorted which will tell "when" to swap to elements.

Closures in Swift: what are they? how do they work?

In really simple terms a closure is a function that can be passed around.

With regard to using sort, you may choose to sort on different properties of the object so you may wish to create your own custom sort function/closure.

Note there is a difference between sort and sorted in Swift. sort mutates the original array, sorted creates a copy of the array. So in your example numbersSorted won't have a value and you should use sorted if you want it to have a value.

let numbers = [2, 5, 3, 2, 1, 0, -8, 12]

let numbersSorted = numbers.sorted { first, second -> Bool in
return first < second
}

print(numbers) // [2, 5, 3, 2, 1, 0, -8, 12]
print(numbersSorted) // [-8, 0, 1, 2, 2, 3, 5, 12]

However I don't need to write the above code like that. I could swap the closure for a function.

let numbers = [2, 5, 3, 2, 1, 0, -8, 12]

func ascending(first: Int, second: Int) -> Bool {
first < second
}

let numbersSorted = numbers.sorted(by: ascending)

print(numbers) // [2, 5, 3, 2, 1, 0, -8, 12]
print(numbersSorted) // [-8, 0, 1, 2, 2, 3, 5, 12]

Note that the function ascending has the same signiture as the closure that we were using before.

Alternatively I can write a closure as a variable that can then be passed around

let numbers = [2, 5, 3, 2, 1, 0, -8, 12]

let ascending = { (first: Int, second: Int) in
return first < second
}

let numbersSorted = numbers.sorted(by: ascending)

print(numbers) // [2, 5, 3, 2, 1, 0, -8, 12]
print(numbersSorted) // [-8, 0, 1, 2, 2, 3, 5, 12]

The most important thing is that the function's and the closure's signature match. That way they can be swapped.

Personally I prefer going for the second option as it makes the code more readable and it can look cleaner.

There is another term that you have to contend with when it comes to closures, and that is @escaping. What does that mean?

An @escaping closure outlives the function that it was passed to. Basically it is saying that this code should be executed in the future after the function has been called.

This is quite often seen when networking calls as they can take a period of time to complete. The function will have executed but you haven't received the response, once the response has been returned then it executes the completion block (our closure) and we can see the updates.

Here are some good articles that you can follow up with

https://learnappmaking.com/closures-swift-how-to/

https://www.hackingwithswift.com/example-code/language/what-is-a-closure

https://www.swiftbysundell.com/basics/closures/

https://www.hackingwithswift.com/example-code/language/what-is-an-escaping-closure

I am little bit confused about escaping closure

I want to know that completion handler and escaping closure are same
or what?

Completion and Error Handlers are related to a process that should be done after executing -and returning- a chunk of code (function):

Completion handlers are callbacks that allow a client to perform some
action when a framework method or function completes its task.
https://developer.apple.com/library/content/featuredarticles/Short_Practical_Guide_Blocks/

which are -logically- representation of escaping closures.

So, referring to the escaping closures definition, a completion handler is by default is an escaping closures.

For reviewing example(s), you might want to check this answer. Also, if you think that you need more description about what is the escaping closure, you might wan to check this Q&A.

Shall we always use [unowned self] inside closure in Swift

No, there are definitely times where you would not want to use [unowned self]. Sometimes you want the closure to capture self in order to make sure that it is still around by the time the closure is called.

Example: Making an asynchronous network request

If you are making an asynchronous network request you do want the closure to retain self for when the request finishes. That object may have otherwise been deallocated but you still want to be able to handle the request finishing.

When to use unowned self or weak self

The only time where you really want to use [unowned self] or [weak self] is when you would create a strong reference cycle. A strong reference cycle is when there is a loop of ownership where objects end up owning each other (maybe through a third party) and therefore they will never be deallocated because they are both ensuring that each other stick around.

In the specific case of a closure, you just need to realize that any variable that is referenced inside of it, gets "owned" by the closure. As long as the closure is around, those objects are guaranteed to be around. The only way to stop that ownership, is to do the [unowned self] or [weak self]. So if a class owns a closure, and that closure captures a strong reference to that class, then you have a strong reference cycle between the closure and the class. This also includes if the class owns something that owns the closure.

Specifically in the example from the video

In the example on the slide, TempNotifier owns the closure through the onChange member variable. If they did not declare self as unowned, the closure would also own self creating a strong reference cycle.

Difference between unowned and weak

The difference between unowned and weak is that weak is declared as an Optional while unowned is not. By declaring it weak you get to handle the case that it might be nil inside the closure at some point. If you try to access an unowned variable that happens to be nil, it will crash the whole program. So only use unowned when you are positive that variable will always be around while the closure is around

How are escaping closures implemented in Swift 3 (under the hood)? Are they implicitly block_copied/retained like in objective-c?

It is true that closures are implicitly retained (strongly) when you save them as properties or otherwise. From The Swift Programming Language, Automatic Reference Counting:

… closures, like classes, are reference types. When you assign a closure to a property, you are assigning a reference to that closure.

(That's why capture lists exist: to help avoid accidental retain cycles.)

However, I think you may be misunderstanding the purpose of @escaping (or the absence of @noescape in older version of Swift). This does not automatically save the closure for you. Rather, it just indicates to the caller that you might save the closure (that the closure might escape the execution of the function). This allows the compiler to perform extra optimizations, such as skipping the retain. It also allows callers to omit self. inside the closure:

class Foo {
var x = 3

func test() {
[1, 2, 3].map { $0 + x }
// `self.x` is not necessary, because the map function's
// closure is non-escaping
}
}

(If you're interested in learning what's really going on under the hood with @escaping, I don't know of a definitive source for this kind of information, but you might find some useful things in this talk about SIL, the SIL.rst docs in the open-source project, and perhaps Understanding Swift Performance from WWDC16.)

Swift, why don't class methods need closure lists

"If functions are essentially closures." This isn't true. Functions (and methods) are not the same thing as closures. Functions have all their free variables unbound. Closures have bound some or all of their free variables (closed over them, which is where the name "closure" comes from).

A "free variable" is any variable defined outside the scope of the function (including its formal parameters). The top-level function func f(x: Int) has one free variable; when you call it, you must pass a parameter. A closure like { f(1) } has no free variables. When you call it, you do not pass any parameters.

A method, like a function, does not capture anything. It is passed all of its free variables when it is executed. For example, when you make the call object.doThis(), this is the same as calling Type.doThis(object)().

class X {
func doThis() {}
}

let x = X()
x.doThis()

X.doThis(x)() // Same thing

X.doThis(x) is a function that returns a function. There's no magic here. All the free variables are provided during the call. Nothing is captured. (The "free variable" in the case you describe is self, but that doesn't change anything. self is not special, except that it gets a little syntactic sugar around it.)

This is different than a closure:

let c = { x.doThis() }
c()

When I call c(), how does it know the value of x? I may have returned c and x may be out of scope now. The system has to keep track of x (including making a strong reference so it doesn't deallocate), and it does that by capturing it, or "closing over x" which raises the possibility of retain loops. So in c, x is bound. It is not free. You can't pass it when you call c().

self is not special here. It's just another variable. [weak self] in closures isn't special either. You can write [weak x] just as well. The [...] syntax is just the capture list.



Related Topics



Leave a reply



Submit