与其他编程语言所不同的是,Swift 并不要求你为自定义类和结构去创建独立的接口和实现文件。你所要做的是在一个单一文件中定义一个类或者结构体,系统将会自动生成面向其它代码的外部接口。
注意:通常一个类的实例被称为对象。然而在Swift 中,类和结构体的关系要比在其他语言中更加的密切,本章中所讨论的大部分功能都可以用在类和结构体上。因此,我们会主要使用实例而不是对象。
比较类和结构体
类和结构体都具有以下特性:
- 定义用于存储值的属性
- 定义提供特定能力或功能的方法
- 定义提供使用下标语法访问值的下标
- 定义设置初始状态的初始化方法
- 通过扩展以增加默认实现的功能
- 符合协议提供某种标准功能
类还具有结构体没有的功能,如下:
- 继承使一个类具有另一个类的特性
- 类型转换允许在运行时检查和解释一个类实例的类型
- 反初始化允许一个类实例释放任何其所被分配的资源
- 引用计数允许对一个类的多次引用
注意:结构体总是通过被复制的方式在代码中传递,因此请不要使用引用计数。
定义语法
使用class关键字来申明一个类,使用struct关键字来申明一个结构体。
class SomeClass { } struct SomeStructure { }
注意:类和结构体名称以大写字母开头,属性和方法名称以小写字母开头。
示例如下
struct Resolution { var width = 0 var heigth = 0 } class VideoMode { var resolution = Resolution() var interlaced = false var frameRate = 0.0 var name: String? }
在上面的示例中我们定义了一个名为Resolution的结构体,用来描述一个显示器的像素分辨率。这个结构体包含了两个名为width和height的储存属性。储存属性是捆绑和储存在类或结构体中的常量或变量。当这两个属性被初始化为整数0的时候,它们会被推断为Int类型。个名为VideoMode的类,用来描述一个视频显示器的特定模式。这个类包含了四个储存属性变量。第一个是分辨率,它被初始化为一个新的Resolution结构体的实例,具有Resolution的属性类型。新VideoMode实例同时还会初始化其它三个属性,它们分别是,初始值为false(意为“non-interlaced video”)的inteflaced,回放帧率初始值为0.0的frameRate和值为可选String的name。name属性会被自动赋予一个默认值nil,意为“没有name值”,因它是一个可选类型。
类和结构体实例
Resolution结构体和VideoMode类的定义仅描述了什么是Resolution和VideoMode。它们并没有描述一个特定的分辨率(resolution)或者视频模式(video mode)。为了描述一个特定的分辨率或者视频模式,我们需要创建一个它们的实例。如下
let someResolution = Resolution() let someVideoMode = VideoMode()
过这种方式所创建的类或者结构体实例,其属均会被初始化为默认值。
属性访问
使用点语法访问实例中所含有的属性。其语法规则是,实例名后面紧跟属性名,两者通过点号(.)连接:
println("The width of someResolution is \(someResolution.width)")
你也可以访问子属性,如何VideoMode中Resolution属性的width属性:
println("The width of someVideoMode is \(someVideoMode.resolution.width)")
你也可以使用点语法为属性变量赋值
someVideoMode.resolution.width = 12880 println("The width of someVideoMode is now \(someVideoMode.resolution.width)")
注意:与 Objective-C 语言不同的是,Swift 允许直接设置结构体属性的子属性。上面的最后一个例子,就是直接设置了someVideoMode中resolution属性的width这个子属性,以上操作并不需要从新设置resolution属性。
逐个成员初始化器的结构类型
所有结构体都有一个自动生成的成员逐一初始化方法,用于初始化新结构体实例中成员的属性。新实例中各个属性的初始值可以通过属性的名称传递到成员逐一初始化器之中:
let vga = resolution(width:640, heigth: 480)
与结构体不同,类实例没有默认的成员逐一初始化器。
结构体和枚举是值类型
个值类型是一个值,当它被分配给一个变量或常量时,或当它被传递给函数时,它的值是被复制的,这意味着它们的实例,以及实例中所包含的任何值类型属性,在代码中传递的时候都会被复制。
let hd = Resolution(width: 1920, height: 1080) var cinema = hd
在以上示例中,声明了一个名为hd的常量,其值为一个初始化为全高清视频分辨率(1920 像素宽,1080 像素高)的Resolution实例。
然后示例中又声明了一个名为cinema的变量,其值为之前声明的hd。因为Resolution是一个结构体,所以cinema的值其实是hd的一个拷贝副本,而不是hd本身。尽管hd和cinema有着相同的宽(width)和高(height)属性,但是在后台中,它们是两个完全不同的实例。
类是引用类型
与值类型不同,引用类型在被赋予到一个变量,常量或者被传递到一个函数时,操作的并不是其拷贝。因此,引用的是已存在的实例本身而不是其拷贝
恒等运算符
因为类是引用类型,有可能有多个常量和变量在后台同时引用某一个类实例。如果能够判定两个常量或者变量是否引用同一个类实例将会很有帮助。为了达到这个目的,Swift 内建了两个恒等运算符:
等价于 ( === )
不等价于 ( !== )
if tenEighty === alsoTenTighty { println("tenTighty and alsoTenEighty refer to the same Resolution instance.") }
指针
如果你有 C,C++ 或者 Objective-C 语言的经验,那么你也许会知道这些语言使用指针来引用内存中的地址。一个 Swift 常量或者变量引用一个引用类型的实例与C语言中的指针类似,不同的是并不直接指向内存中的某个地址,而且也不要求你使用星号(*)来表明你在创建一个引用。Swift 中这些引用与其它的常量或变量的定义方式相同。