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: String

    lazy var personalizedGreeting: String = {
        [unowned self] in
        return "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 digits
        return resultOfCalculation
        }()

}