Swift
方式的延遲加載
而在Swift中,你只需一行代碼即可實現此機制:
lazy var players = String[]()
簡單、簡潔,直入主題。
但你得記住,你必須使用var
關鍵字來定義延遲加載的屬性,不能使用let
關鍵字,因為常量必須在實例構建時賦值。
如果你想給延遲加載加上一些邏輯處理,Swift允許你在屬性后面定義一個閉包調用(閉包的返回值會作為屬性的默認值):
lazy var players: String[] = {var temporaryPlayers = String[]()temporaryPlayers.append("Mike Buss")return temporaryPlayers}()
如果你愿意,你也可以使用實例方法來初始化延遲加載屬性:
lazy var players: String[] = self.initialPlayers() func initialPlayers() -> String[] {var players = ["Mike Buss"]return players }
或者用個類方法也可以:
lazy var players = MultipeerManager.initialPlayers() class func initialPlayers() -> String[] {var players = ["Mike Buss"]return players }
但大家現在更傾向于使用新的閉包語法,因為它將邏輯代碼就定義在了屬性聲明的旁邊。
何時使用延遲加載?
一種使用場景是,一個對象的屬性的初始值依賴與其它的屬性,所以必須先創建出這個對象,才能知道這個屬性的值。
舉例來說,你有一個Person
類以及一個personalizedGreeting
屬性。這個personalizedGreeting
屬性需要在對象創建完成后才延遲加載,因為只有在對象創建完成后它才能知道問候的人是誰(person的name
)。請看代碼:
class Person {var name: Stringlazy var personalizedGreeting: String = {[unowned self] inreturn "Hello, \(self.name)!"}()init(name: String) {self.name = name} }
注意,你必須使用?[unowned self]
來避免循環引用。[unowned self]定義了一個在閉包中需要使用的、存在于閉包外的屬性/變量列表,又叫捕獲列表(capture list
)。
當你實例化一個person
時,他的問候語greeting
此時并沒有創建:
let person = Person(name: "Robert Redford”) // person.personalizedGreeting is nil
但是當你嘗試打印出問候語時,這句問候語會自動生成出來:
NSLog(person.personalizedGreeting) // personalizedGreeting is calculated when used // and now contains the value "Hello, Robert Redford!"
另一種適合延遲加載的場景,是在屬性的初始值需要進行大量計算之時。
舉例來說,當你有個對象需要執行一個高負荷的算法來確定一張圖片中的人臉個數,你可以將numberOfFaces
屬性設置為延遲加載。
或者當你有個類需要計算多個大數的值,你希望它們能在需要的時候才被計算出來:
class MathHelper {lazy var pi: Double = {// Calculate pi to an insane number of digitsreturn resultOfCalculation}()}