I have learnt Swift for a while and I have read the Swift language guide.
https://developer.apple.com/library/content/documentation/Swift/Conceptual/Swift_Programming_
Closures are a concept you use mainly on asynchronous function calls. (at least I do so)
A good example where Apple uses closures is URLSession
:
func downloadTask(with url: URL, completionHandler: @escaping (URL?, URLResponse?, Error?) -> Void) -> URLSessionDownloadTask
This method creates an URLSessionDownloadTask
that runs in a background thread. When you call this method, you are passing a closure as completionHandler
. This closure is executed, when the task has finished.
There are some other cases, but I haven't used them this much yet, because I love the delegate pattern. I found an article that compares Closures and Delegates in Swift.
Delegates in Swift have a big problem: Unless you are using @objc
, you have to implement every method of a protocol
, which could lead to lots of unnecessary code and would look confusing. That's why I guess it would be much better to use closures in many cases.
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:
AGAIN: it is just a simple usage of the closures; You need to check the documentation for more details.
I hope it helped.