延时加载存储属性是指当第一次被调用的时候才会计算其初始值的属性。在属性声明前使用lazy
来标示一个延时加载存储属性。
注意
必须将延时加载属性声明成变量(使用 var 关键字),因为属性的初始值可能在实例构造完成之后才会得到。而常量属性在构造过程完成之前必须要有初始值,因此无法声明成延时加载。
当属性的值依赖于一些外部因素且这些外部因素只有在构造过程结束之后才会知道的时候,延时加载属性就会很有用。或者当获得属性的值因为需要复杂或者大量的计算,而需要采用需要的时候再计算的方式,延时加载属性也会很有用。
下面的例子使用了延时加载存储属性来避免复杂类中不必要的初始化工作。例子中定义了DataImporter
和DataManager
两个类,下面是部分代码:
class DataImporter { /* DataImporter 是一个负责将外部文件中的数据导入的类。 这个类的初始化会消耗不少时间。 */ var fileName = "data.txt" // 这里会提供数据导入功能 } class DataManager { lazy var importer = DataImporter() var data = [String]() // 这里会提供数据管理功能 } let manager = DataManager() manager.data.append("Some data") manager.data.append("Some more data") // DataImporter 实例的 importer 属性还没有被创建
DataManager
类包含一个名为data
的存储属性,初始值是一个空的字符串数组。这里没有给出全部代码,只需知道DataManager
类的目的是管理和提供对这个字符串数组的访问即可。
DataManager
的一个功能是从文件中导入数据。这个功能由 DataImporter
类提供,DataImporter
完成初始化需要消耗不少时间:因为它的实例在初始化时可能需要打开文件并读取文件中的内容到内存中。
DataManager
管理数据时也可能不从文件中导入数据。所以当 DataManager
的实例被创建时,没必要创建一个DataImporter
的实例,更明智的做法是第一次用到DataImporter
的时候才去创建它。
由于使用了lazy
,DataImporter
的实例importer
属性只有在第一次被访问的时候才被创建。比如访问它的属性fileName
时:
print(manager.importer.fileName) // DataImporter 实例的 importer 属性现在被创建了 // 输出“data.txt”
注意
如果一个被标记为 lazy 的属性在没有初始化时就同时被多个线程访问,则无法保证该属性只会被初始化一次。
注:
1.初始化一个属性,又不经常使用,浪费资源。
2.计算型属性,每次调用都要重新计算,造成资源浪费。
3.延迟属性:只在使用时调用一次,且调用后结果被保存。
4.lazy属性必须显示的声明返回值类型,必须声明成var类型;闭包捕获外部属性必须用self调用。