Functional swift: All about Closures

According to apple docs: Closures are self-contained blocks of functionality that can be passed around and used in your code. I tried to include all about closures here in this article. It’s a bit lengthy one. But worth reading it. I guarantee !!!

I don’t know who that is, But the photo looks refreshing. isn’t??

Function:

function that takes two parameters and returns two parameters using tuples

Function types

func doSometingWithInt(someInt:Int) -> Int {return someInt * 2}
(int) -> (int)
(int, int) -> (int)
func personInTheHouse() -> ((String) -> String) {func doProcess(process: String) -> (String) { // nested functionreturn “The person is \(process).”}return doProcess // or return doProcess(process:)}let person = personInTheHouse()print(person(“playing cricket”)) // prints “The person is playing cricket.

Defining a closure :

{ (params) -> returnType instatements}
func addTwoNumbers(number1:Int, number2:Int) -> Int {return number1 + number2}addTwoNumbers(number1: 8, number2: 2) // result is 10
let closure: (Int, Int) -> Int = { (number1, number2) inreturn number1 + number2}closure(8,2) // the result is 10

Shorthand Argument Names

var shortHandClosure:(Int,Int)->Int = {return $0 + $1}shortHandClosure(8,2) // result is 10
var superShortClosure:(Int,Int)->Int = {$0 + $1}

Inferred type closure

let inferredClosure = {(x:Int,y:Int)->Int in x + y }inferredClosure(1,99) // result is 100

Return types can also be inferred:

let inferredReturnTypeClosure = {(number:Int) in number*number }

Closure that takes nothing and returns a string:

let callStringWtihClosure: () -> String = { () in return “hello”
}
//____________
print(callStringWtihClosure()) // prints “hello”
let callStringWtihClosure: () -> String = {return “hello”}
let callStringWithClosureWithoutType = { “hi, I’m a closure too” }

Closures and functions are first class types in swift:

Methods with completion callback using closures:

Returning a closure from a function

// return a closure from a functionvar addClosure:(Int,Int)->Int = { $0 + $1 }func returnClosure() -> (Int,Int)->Int {return addClosure}//____________________________________returnClosure()(10,20) // returns 30var returnedClosure = returnClosure() // returns a closure of type (Int,Int)->IntreturnedClosure(20,10) // returns 30

Initialize or customize objects using closures

func setupView() -> UIView {let view = UIView()view.backgroundColor = .redreturn view}let someView = setupView() // returns a red view
let setupViewUsingClosure = { () -> UIView inlet view = UIView()view.backgroundColor = .greenreturn view}let someOtherView = setupViewUsingClosure() // returns a green view
let setupViewUsingClosure: UIView = {let view = UIView()view.backgroundColor = .greenreturn view}() //IMPORTANT!!! I have added () at the end.
let aClosure= { “hello, I’m a closure too.” }let aString= { “hello, I’m a closure too.” }() // added () at the end.

lazy init:

Trailing Closures

func doSomething(number:Int,onSuccess closure:(Int)->Void) {closure(number * number * number)}doSomething(number: 100) { (numberCube) inprint(numberCube) // prints  1000000}

Capturing values

// capturing valuesvar i = 0var closureArray = [()->()]()for _ in 1…5 {closureArray.append {print(i)}i += 1}// here i will be 5closureArray[0]() // prints 5closureArray[1]() // prints 5closureArray[2]() // prints 5closureArray[3]() // prints 5closureArray[4]() // prints 5

Creating a capture list:

var closureArray2 = [()->()]()var j = 0for _ in 1…5 {closureArray2.append { [j] inprint(j)}j += 1}// here i will be 5closureArray2[0]() // prints 0closureArray2[1]() // prints 1closureArray2[2]() // prints 2closureArray2[3]() // prints 3closureArray2[4]() // prints 4
closure.append { [j,k,l] inprint("\(j) \(k) \(l)")}
closure.append { [a = j, b = k, c = l] inprint("\(j) \(k) \(l)")}

Escaping closure vs non-escaping closure

func someFunctionWithNonescapingClosure(closure: () -> Void) {closure()}func someFunctionWithEscapingClosure(completionHandler: @escaping () -> Void) {completionHandler()}class SomeClass {var x = 10func doSomething() {someFunctionWithEscapingClosure { self.x = 100 }someFunctionWithNonescapingClosure { x = 200 }}}

Memory management

class InterviewTest {var name: String = “Abhilash”lazy var greeting : String = {return “Hello \(self.name)”}()}
//-------------------------
let testObj = InterviewTest()testObj.greeting // result is Hello Abhilash

weak

lazy var greeting : String = { [weak self] inguard let strongSelf = self else { return “” }return “Hello \(strongSelf.name)”}()

Unowned

lazy var greeting : String = { [unowned self] inreturn “Hello \(self.name)”}()
lazy var greeting : String = { [unowned unownedSelf = self] inreturn “Hello \(unownedSelf.name)”}()

How to capture self with closures with arguments?

capturing self along with closure parameters

Autoclosures

var customersInLine = [“Chris”, “Alex”, “Ewa”, “Barry”, “Daniella”]print(customersInLine.count)// Prints “5”let customerProvider = { customersInLine.remove(at: 0) } // this is of type ()->Stringprint(customerProvider()) // prints Chris.. the remove(at:) returns a String.
// customersInLine is ["Alex", "Ewa", "Barry", "Daniella"]func serve(customer customerProvider: () -> String) {print("Now serving \(customerProvider())!")}serve(customer: { customersInLine.remove(at: 0) } ) // we cannot omit {}// Prints "Now serving Alex!"
// customersInLine is ["Ewa", "Barry", "Daniella"]func serve(customer customerProvider: @autoclosure () -> String) {print("Now serving \(customerProvider())!")}serve(customer: customersInLine.remove(at: 0))// Prints "Now serving Ewa!"
serve(customer: { customersInLine.remove(at: 0) }) // need {}
serve(customer: customersInLine.remove(at: 0)) // omit {}

One more example for explaining autoclosure:

extension UIView {

class func animate(withDuration duration: TimeInterval, _ animations: @escaping @autoclosure () -> Void) {
UIView.animate(withDuration: duration, animations: animations)
}

}
UIView.animate(withDuration: 2.5) { 
self.view.backgroundColor = .orange
}
UIView.animate(withDuration: 2.5, self.view.backgroundColor = .orange)

Last , but not the least!!!

var addClosure:(Int,Int)->Int = { $0 + $1 }let addClosure2 = addClosure

If you enjoyed reading this post, please share and recommend it so others can find it 💚💚💚💚💚💚 !!!!

iOS and tvOS developer, dreamer, photographer 🤨

Get the Medium app

A button that says 'Download on the App Store', and if clicked it will lead you to the iOS App store
A button that says 'Get it on, Google Play', and if clicked it will lead you to the Google Play store