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.
1. import UIKit
3. let box: UIView = {
4. let view = UIView()
5. return view
6. }()
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.
1. let buttonSize = CGRect(x: 0, y: 0, width: 100, height: 100)
3. // ViewControllerOne
4. let bobButton = UIButton(frame: buttonSize)
5. bobButton.backgroundColor = .black
6. bobButton.titleLabel?.text = "Bob"
7. bobButton.titleLabel?.textColor = .white
9. // ViewControllerTwo
10. let bobbyButton = UIButton(frame: buttonSize)
11. bobbyButton.backgroundColor = .black
12. bobbyButton.titleLabel?.text = "Bobby"
13. bobbyButton.titleLabel?.textColor = .white
It is tedious.
Create Button with Function
You may create a function instead.
1. func createButton(enterTitle: String) -> UIButton {
2. let button = UIButton(frame: buttonSize)
3. button.backgroundColor = .black
4. button.titleLabel?.text = enterTitle
5. return button
6. }
7. 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
1. struct Human {
2. init() {
3. print("Born 1996")
4. }
5. }
Create an instance called, bobInstance.
1. let createBob = { () -> Human in
2. let human = Human()
3. return human
4. }
6. let bobInstance = createBob()
You’ve created two constants: createBob and bobInstance. Unnecessary.
Initialize in Single Line
1. let bobby = { () -> Human in
2. let human = Human()
3. return human
4. }()
Now, bobby contains the human object.
Create UIView Unconventionally
Let us apply the same principle to creating a UIView object.
1. let bobView = { () -> UIView in
2. let view = UIView()
3. view.backgroundColor = .black
4. return view
5. }()
7. let bobbyView = { () -> UIView in
8. let view = UIView()
9. view.backgroundColor = .black
10. return view
11. }()
The closure block has no parameter. Therefore, you no longer have to define the type explicitly - 3001_intro_closures_part1
1. let newBobbyView: UIView = {
2. let view = UIView()
3. view.backgroundColor = .black
4. return view
5. }()
You only have to define the type of newBobbyView as UIView.
Introducing Lazy Var
The lazy keyword is used in front of a variable.
1. class IntenseMathProblem {
2. lazy var complexNumber: Int = {
3. 1 * 1
4. }()
5. }
lazy properties are not initialized until you access them.
1. let problem = IntenseMathProblem() // no value for complexNumber
2. problem.complexNumber // now, complexnumber is 1
Application
You may use lazy to sort your database.
1. class SortFromDataBase {
2. // Data
3. lazy var sortNumberFromDatabase: [Int] = {
4. // Caluation and sorting
5. [1, 2, 3, 4, 5, 6, 7, 8, 9]
6. }()
7. }
8. // 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.
1. class CompressionManager {
2. lazy var compressedImage: UIImage = {
3. let image = UIImage()
4. // Compress the image
5. // Logic
6. return image
7. }()
8. }
Rules
- You can’t use
lazywithletsince 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.
lazyis 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.
