Lazy 概念
- 在Swift中,屬性可以聲明為延遲加載。延時加載屬性就屬于懶加載編程的一種,在對象構造時屬性并不會被賦值,只有當使用到時才對屬性進行賦值。
- 懶加載是編程中常用的一種優化技巧。很多時候類示例中的屬性是否真正創建與用戶的操作邏輯有關,例如復雜對象的某個屬性可能需要從本地文件進行讀取,這是一個耗時的過程,并且并非用戶每次都會用到這個屬性,這時就可以采用懶加載的方式,只有當使用到這個屬性時才進行文件的讀取。
- 懶加載可以有效地加快對象的構造速度并且可以在一定程度上節省內存的使用。
使用
OC 中可能是這樣的:
@property (copy, nonatomic) NSString *name;
- (NSString *)name {
if (!_name) {
_name = @"sampson";
}
return _name;
}
swift 中我們在使用 lazy 修飾屬性時,必須聲明屬性是變量(var),不能使用let關鍵字。而且我們需要顯示的指定屬性的類型。對該屬性進行一個賦值語句用來首次訪問時使用。
lazy var name: String = "sampson"
lazy var textLabel: UILabel = {
let label = UILabel()
label.text = "yo yo yo 柚子茶!"
return label
}()
何時使用延遲加載?
- 一種使用場景是,一個對象的屬性的初始值依賴與其它的屬性,所以必須先創建出這個對象,才能知道這個屬性的值。
舉例來說,你有一個Person
類以及一個personalizedGreeting
屬性。這個personalizedGreeting
屬性需要在對象創建完成后才延遲加載,因為只有在對象創建完成后它才能知道問候的人是誰(person的name
)。請看代碼:
class Person {
var name: String
lazy var personalizedGreeting: String = {
[weak self] in
return "Hello, \(self?.name ?? "XXX")!"
}()
init(name: String) {
self.name = name
}
}
注意,你必須使用
[weak self]
來避免[循環引用]。[weak self]定義了一個在閉包中需要使用的、存在于閉包外的屬性/變量列表,又叫捕獲列表(capture list
)。
當你實例化一個person
時,他的問候語greeting
此時并沒有創建:
let person = Person(name: "sampson”)
// person.personalizedGreeting is nil
但是當你嘗試打印出問候語時,這句問候語會自動生成出來:
NSLog(person.personalizedGreeting)
// personalizedGreeting is calculated when used
// and now contains the value "Hello, sampson!"
- 另一種適合延遲加載的場景,是在屬性的初始值需要進行大量計算之時。
舉例來說,當你有個對象需要執行一個高負荷的算法來確定一張圖片中的人臉個數,你可以將numberOfFaces屬性設置為延遲加載。
或者當你有個類需要計算多個大數的值,你希望它們能在需要的時候才被計算出來:
class MathHelper {
lazy var pi: Double = {
// Calculate pi to an insane number of digits
return resultOfCalculation
}()
}
拓展
lazy
還可以配合 map
filter
這類接受閉包運行的方法一起,使整個行為變成延遲進行的。
let numbers = 1...5
let doubleNumbers = numbers.map { (i: Int) -> Int in
print("numbers\(i)")
return i * 2
}
for i in doubleNumbers {
print("doubleNumbers\(i)")
}
打印結果:
numbers1
numbers2
numbers3
numbers4
numbers5
doubleNumbers2
doubleNumbers4
doubleNumbers6
doubleNumbers8
doubleNumbers10
使用 lazy 后得到延遲運行版本的容器
let numbers = 1...5
let doubleNumbers = numbers.lazy.map { (i: Int) -> Int in
print("numbers\(i)")
return i * 2
}
for i in doubleNumbers {
print("doubleNumbers\(i)")
}
打印結果:
numbers1
doubleNumbers2
numbers2
doubleNumbers4
numbers3
doubleNumbers6
numbers4
doubleNumbers8
numbers5
doubleNumbers10
對于一些不需要完全運行或者提前退出的情況,使用 lazy
進行性能優化更加有效。