Lazy Init with Closures
Introduction
Welcome to Chapter 3 of Intro to Functional Swift. There are two objectives. The first is to learn how to initialize an object using a closure block. The second is to understand when, where, how, and why we use the lazy
keyword in the Swift Programming Language.
Problem
How to initialize an object with a closure?
Unconventional Way
If you’ve followed tutorials online or looked through open source projects, it’s not uncommon to initialize UI components with the following way.
import UIKit
let box: UIView = {
let view = UIView()
return view
}()
However, a lot of students fail to explain because they simply copy.
Create UI Components
To appreciate the unconventional method, let us begin the “normal” way to create UI components programmatically.
let buttonSize = CGRect(x: 0, y: 0, width: 100, height: 100)
// ViewControllerOne
let bobButton = UIButton(frame: buttonSize)
bobButton.backgroundColor = .black
bobButton.titleLabel?.text = "Bob"
bobButton.titleLabel?.textColor = .white
// ViewControllerTwo
let bobbyButton = UIButton(frame: buttonSize)
bobbyButton.backgroundColor = .black
bobbyButton.titleLabel?.text = "Bobby"
bobbyButton.titleLabel?.textColor = .white
It is tedious.
Create Button with Function
You may create a function instead.
func createButton(enterTitle: String) -> UIButton {
let button = UIButton(frame: buttonSize)
button.backgroundColor = .black
button.titleLabel?.text = enterTitle
return button
}
createButton(enterTitle: "Yoyo")
However, when you build apps, it is unlikely that buttons look identical. Therefore, the function may require multiple parameters for customization. It becomes more tedious and readability decreases.
Introducing Unconventional Way
The unconventional way uses a closure block to initialize an object.
Create Object with Closure
First, let us figure out how to create an object using a closure block.
Design a Human
struct
struct Human {
init() {
print("Born 1996")
}
}
Create an instance called, bobInstance
.
let createBob = { () -> Human in
let human = Human()
return human
}
let bobInstance = createBob()
You’ve created two constants: createBob
and bobInstance
. Unnecessary.
Initialize in Single Line
let bobby = { () -> Human in
let human = Human()
return human
}()
Now, bobby
contains the human
object.
Create UIView Unconventionally
Let us apply the same principle to creating a UIView
object.
let bobView = { () -> UIView in
let view = UIView()
view.backgroundColor = .black
return view
}()
let bobbyView = { () -> UIView in
let view = UIView()
view.backgroundColor = .black
return view
}()
The closure block has no parameter. Therefore, you no longer have to define the type explicitly - 3001_intro_closures_part1
let newBobbyView: UIView = {
let view = UIView()
view.backgroundColor = .black
return view
}()
You only have to define the type of newBobbyView
as UIView
.
Introducing Lazy Var
The lazy
keyword is used in front of a variable.
class IntenseMathProblem {
lazy var complexNumber: Int = {
1 * 1
}()
}
lazy
properties are not initialized until you access them.
let problem = IntenseMathProblem() // no value for complexNumber
problem.complexNumber // now, complexnumber is 1
Application
You may use lazy
to sort your database.
class SortFromDataBase {
// Data
lazy var sortNumberFromDatabase: [Int] = {
// Caluation and sorting
[1, 2, 3, 4, 5, 6, 7, 8, 9]
}()
}
// SortFromDataBase().sortNumberFromDatabase
You do not want to sort your entire database. It would burn a lot of computing power.
The same principle applies to image compression.
class CompressionManager {
lazy var compressedImage: UIImage = {
let image = UIImage()
// Compress the image
// Logic
return image
}()
}
Rules
- You can’t use
lazy
withlet
since there is no initial value, and it is attained later when it is accessed. - You can’t use it with a Computed property since computed property is always recalculated (requires CPU) when you modify any of the variables that has a relationship with the lazy property.
lazy
is only valid for members of a struct or class
Resources
Swift Lazy Initialization with Closures
Source Code
3003_lazy_init_closures.playground
Conclusion
You’ve learned how to initialize an object using closures instead of the tedious method above. I do not use Storyboard
. In fact, I have a “library” of UI Components so that I don’t waste time typing all day. I just copy the closure block from the library and modify a little. Second, you’ve learned to use the lazy
keyword in front of a property that requires heavy computing.
In the following lesson, you will discover a unique behavior of closures.
Note: Learn Swift with Bob is available on Udemy. If you wish to receive a discount link, you may sign up here.