发布于 2015-06-14 01:52:37 | 125 次阅读 | 评论: 0 | 来源: 网络整理
简单来说,一个存储属性就是存储在特定类或结构体的实例里的一个常量或变量,存储属性可以是变量存储属性(用关键字var
定义),也可以是常量存储属性(用关键字let
定义)。
可以在定义存储属性的时候指定默认值,请参考构造过程一章的默认属性值一节。也可以在构造过程中设置或修改存储属性的值,甚至修改常量存储属性的值,请参考构造过程一章的在初始化阶段修改常量存储属性一节。
下面的例子定义了一个名为FixedLengthRange
的结构体,它描述了一个在创建后无法修改值域宽度的区间:
struct FixedLengthRange {
var firstValue: Int
let length: Int
}
var rangeOfThreeItems = FixedLengthRange(firstValue: 0, length: 3)
// 该区间表示整数0,1,2
rangeOfThreeItems.firstValue = 6
// 该区间现在表示整数6,7,8
FixedLengthRange
的实例包含一个名为firstValue
的变量存储属性和一个名为length
的常量存储属性。在上面的例子中,length
在创建实例的时候被赋值,因为它是一个常量存储属性,所以之后无法修改它的值。
如果创建了一个结构体的实例并赋值给一个常量,则无法修改实例的任何属性,即使定义了变量存储属性:
let rangeOfFourItems = FixedLengthRange(firstValue: 0, length: 4)
// 该区间表示整数0,1,2,3
rangeOfFourItems.firstValue = 6
// 尽管 firstValue 是个变量属性,这里还是会报错
因为rangeOfFourItems
声明成了常量(用let
关键字),即使firstValue
是一个变量属性,也无法再修改它了。
这种行为是由于结构体(struct)属于值类型。当值类型的实例被声明为常量的时候,它的所有属性也就成了常量。
属于引用类型的类(class)则不一样,把一个引用类型的实例赋给一个常量后,仍然可以修改实例的变量属性。
延迟存储属性是指当第一次被调用的时候才会计算其初始值的属性。在属性声明前使用@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 += "Some data"
manager.data += "Some more data"
// DataImporter 实例的 importer 属性还没有被创建
DataManager
类包含一个名为data
的存储属性,初始值是一个空的字符串(String
)数组。虽然没有写出全部代码,DataManager
类的目的是管理和提供对这个字符串数组的访问。
DataManager
的一个功能是从文件导入数据,该功能由DataImporter
类提供,DataImporter
需要消耗不少时间完成初始化:因为它的实例在初始化时可能要打开文件,还要读取文件内容到内存。
DataManager
也可能不从文件中导入数据。所以当DataManager
的实例被创建时,没必要创建一个DataImporter
的实例,更明智的是当用到DataImporter
的时候才去创建它。
由于使用了@lazy
,importer
属性只有在第一次被访问的时候才被创建。比如访问它的属性fileName
时:
println(manager.importer.fileName)
// DataImporter 实例的 importer 属性现在被创建了
// 输出 "data.txt”
如果您有过 Objective-C 经验,应该知道有两种方式在类实例存储值和引用。对于属性来说,也可以使用实例变量作为属性值的后端存储。
Swift 编程语言中把这些理论统一用属性来实现。Swift 中的属性没有对应的实例变量,属性的后端存储也无法直接访问。这就避免了不同场景下访问方式的困扰,同时也将属性的定义简化成一个语句。 一个类型中属性的全部信息——包括命名、类型和内存管理特征——都在唯一一个地方(类型定义中)定义。