定義
lazy屬性就是初始值直到第一次使用的時候才執行計算的屬性,這對小記憶體的手機所産生的性能上的優化是相當可觀的。
注意:lazy屬性必須是變量(var修飾符),因為常量屬性(let修飾符)必須在初始化之前就有值,是以常量屬性不能定義為lazy。
Objective-C中的延遲加載
Objective-C并沒有在文法上支援延遲加載,通常是由程式員自己手動實作的。
示例如下:
@property (nonatomic, strong) NSArray *names;
- (NSArray *)names {
if (!_names) {
_names = [[NSArray alloc] init];
NSLog(@"隻在首次通路輸出");
}
return _names;
}
說明:在初始化對象後,_names 是 nil。隻有當首次通路 names 屬性時 getter 方法會被調用,并檢查如果還沒有初始化的話,就進行指派。可以想見,控制台列印的“隻在首次通路輸出”的确隻會輸出一次。我們之後再多次通路這個屬性的話,因為 _names已經有值,是以将直接傳回。
分析:getter方法和下劃線文法對初學者并不是那麼的友好,同時屬性以及對應的getter方法空間上隔得比較遠,代碼邏輯不直覺。
Swift的延遲加載
Swift中則可以通過lazy關鍵字簡單地實作相同功能,比如上述示例代碼在Swift中實作的話:
lazy var names: NSArray = {
let names = NSArray()
print("隻在首次通路輸出")
return names
}()
分析:相比起Objective-C中的實作,現在的lazy是在是簡單的多了,而且更加的直覺。除了上述直接在屬性後面定義閉包調用的方法以外,還可以使用執行個體方法(func)和類方法(class func)來為lazy屬性初始化添加必要的邏輯。
使用場景
延遲加載主要有以下兩個使用的場景:
1. 屬性的初始值依賴于其他的屬性值,隻有其他的屬性值有值之後才能得出該屬性的值。
2. 屬性的初始值需要大量的計算。
進階用法
在Swift标準庫中還有一組lazy方法,可以配合map、filter這類接受閉包并進行運作的方法一起,讓整個行為變成延時進行的。以下是map函數的用法(示例取自喵神的Swifter):
let data = .
let result = data.lazy.map {
(i: Int) -> Int in
print("正在處理 \(i)")
return i *
}
print("準備通路結果")
for i in result {
print("操作後結果為 \(i)")
}
print("操作完畢")
// 準備通路結果
// 正在處理 1
// 操作後結果為 2
// 正在處理 2
// 操作後結果為 4
// 正在處理 3
// 操作後結果為 6
// 操作完畢
對于那些不需要完全運作,可能提前退出的情況,使用 lazy 來進行性能優化效果會非常有效。
參考連結:
1. 喵神:LAZY 修飾符和 LAZY 方法
2. Swiftist:Swift中的延遲加載
3. Apple developer