Swift Basics: Closures
Closures are when you add functions, etc, blocks of code to a variable declaration. It can take in parameters and can have return values.
Here is a simple closure:
let c1 = { (name: String) -> Void in
print(name)
}
To execute it:
c1("ABC")
They are self contained blocks of code. They can be used throughout the application code.
We can indicate that a closure is a parameter in a function.
func test(handler: (String) -> Void)
{
//(String) -> Void means that it is a closure that takes in a String and does not have a return value
handler("efg")
}
Then when we call the function:
test(handler: c1)
With a return value:
let c2 =
{
(name: String) -> String in
return "Well \(name)"
}
to call it:
var message = c2("Mary")
Let's say we have a function that accepts a closure as a parameter:
func test(handler:() -> Void)
{
handler()
}
create a closure:
let c3 = {
()-> Void in
print("ABC")
}
Have the function call the closure:
test(handler: c3)
You can pass other closures into the handler as well.
An example of a shorthand closure
test(handler: {print("GHI")})
Another example:
func printMany(num: Int, handler(_: String)->Void)
{
for _ in 0..<num
{ handler("DEF")}
}
If you were to call the function this way, it will print Well DEF 5 times.
test(num: 5){ print("Well \($0)")}
$0 just means the first parameter, without giving it a name.
$1 means the second parameter, without giving it a name.
let c4: (String, String) -> Void =
{
print("\($0) \($1)")
}
To call it:
c4("ABC", "DEF")
If it does not return a value, instead of void, we can do this:
let c5: ()->() = {}
An example of closures being used is that of Map in arrays. It applies the closure to every element of the array:
myArray.map { str in print(str)}
This will print every element in the array.
OR
myArray.map{print($0)}
We could have 2 separate closures and place them in the map.
let add1 = {
(number: Int) -> Int in
return number += 1
}
let minus1 = {
(number: Int) -> Int in
return number -= 1
}
var newArray = numbersList.map(add1)
var newArray2 = numbersList.map(minus1)
Here is a simple closure:
let c1 = { (name: String) -> Void in
print(name)
}
To execute it:
c1("ABC")
They are self contained blocks of code. They can be used throughout the application code.
We can indicate that a closure is a parameter in a function.
func test(handler: (String) -> Void)
{
//(String) -> Void means that it is a closure that takes in a String and does not have a return value
handler("efg")
}
Then when we call the function:
test(handler: c1)
With a return value:
let c2 =
{
(name: String) -> String in
return "Well \(name)"
}
to call it:
var message = c2("Mary")
Let's say we have a function that accepts a closure as a parameter:
func test(handler:() -> Void)
{
handler()
}
create a closure:
let c3 = {
()-> Void in
print("ABC")
}
Have the function call the closure:
test(handler: c3)
You can pass other closures into the handler as well.
An example of a shorthand closure
test(handler: {print("GHI")})
Another example:
func printMany(num: Int, handler(_: String)->Void)
{
for _ in 0..<num
{ handler("DEF")}
}
If you were to call the function this way, it will print Well DEF 5 times.
test(num: 5){ print("Well \($0)")}
$0 just means the first parameter, without giving it a name.
$1 means the second parameter, without giving it a name.
let c4: (String, String) -> Void =
{
print("\($0) \($1)")
}
To call it:
c4("ABC", "DEF")
If it does not return a value, instead of void, we can do this:
let c5: ()->() = {}
An example of closures being used is that of Map in arrays. It applies the closure to every element of the array:
myArray.map { str in print(str)}
This will print every element in the array.
OR
myArray.map{print($0)}
We could have 2 separate closures and place them in the map.
let add1 = {
(number: Int) -> Int in
return number += 1
}
let minus1 = {
(number: Int) -> Int in
return number -= 1
}
var newArray = numbersList.map(add1)
var newArray2 = numbersList.map(minus1)
Let's say you have a closure called add1. It can be a parameter inside a function:
func toAdd(workingDone: (Int)->Int)
{
newArray = myArray.map(workingDone)
}
To call:
toAdd(workingDone: add1)
Closures help you to run code asynchronously (which prevents UI from freezing if you are getting data from a webservice).
In order to reuse a closure's parameters and return types, instead of retyping, you can use a typealias:
typealias UseMeInstead = (String) -> Void
Defining the function with a handler:
func test(handler: UseMeInstead) { handler("ABC")}
Selecting a closure based on results:
typealias c1 = ((String)->Void)
func test( handlerA: c1, handlerB: c1)
{
if a>b
{
handlerA("ABC")
}
else
{
handlerB("DEF")
}
}
//The results of what you enter into the closure c1 will depend on conditions.
The closure for both situations:
var sitA : ClassA.c1 = {print("HAHA: \($0)")}
var sitB : ClassA.c1 = {print("LALA: \($0)")}
When we call:
classA.test(handlerA: sitA, handlerB: sitB)
if a > b
We will get: HAHA: ABC
If you have a class, let's say ClassA. We assign a closure, c1 to a property of ClassA.
Let's say, within the closure, we make use of an instance of the class - this will cause memory issues.
To solve this problem, when declaring the closure:
lazy var c1: (()->String)
{ [unowned self] in return self.nameOfProperty}
Comments
Post a Comment