Swift中的延迟加载是一种将对象的创建或其它高负荷操作延迟到真正需要时才执行的机制。当为iOS进行编程时,仅在需要时才分配内存,对小内存的手机而言(相对于电脑)非常实用。

Objective-C中的延迟加载

在Objecitve-C中,如果你要延迟加载一个可变数组,你需要这么做:

@property (nonatomic, strong) NSMutableArray *players;

- (NSMutableArray *)players {
    if (!_players) {
        _players = [[NSMutableArray alloc] init];
    }
    return _players;
}

players会返回nil_players实例变量是在属性同步时默认创建的,需要在属性名前加上下划线,才能访问到这个实例变量。

这些对初学者来说都不那么直观。

Swift方式的延迟加载

而在Swift中,你只需一行代码即可实现此机制:

lazy var players = String[]()

简单、简洁,直入主题。

var关键字来定义延迟加载的属性,不能使用let关键字,因为常量必须在实例构建时赋值。

如果你想给延迟加载加上一些逻辑处理,Swift允许你在属性后面定义一个闭包调用(闭包的返回值会作为属性的默认值):

(1)

lazy var text:UITextField = {
        var text = UITextField()
        text = UITextField(frame: CGRectMake(100, 100, 100, 100))
        text.backgroundColor = UIColor.redColor()
        text.placeholder = "姓名"
        text.delegate = self
        return text
        }()

如果你愿意,你也可以使用实例方法来初始化延迟加载属性:

(2)

lazy var players: String[] = self.initialPlayers()
func initialPlayers() -> String[] {
    var players = ["Mike Buss"]
    return players
}

或者用个类方法也可以:

(3)

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
        }()

}