发布于 2015-06-14 01:59:50 | 201 次阅读 | 评论: 0 | 来源: 网络整理
构造器可以通过调用其它构造器来完成实例的部分构造过程。这一过程称为构造器代理,它能减少多个构造器间的代码重复。
构造器代理的实现规则和形式在值类型和类类型中有所不同。值类型(结构体和枚举类型)不支持继承,所以构造器代理的过程相对简单,因为它们只能代理任务给本身提供的其它构造器。类则不同,它可以继承自其它类(请参考继承),这意味着类有责任保证其所有继承的存储型属性在构造时也能正确的初始化。这些责任将在后续章节类的继承和构造过程中介绍。
对于值类型,你可以使用self.init
在自定义的构造器中引用其它的属于相同值类型的构造器。并且你只能在构造器内部调用self.init
。
注意,如果你为某个值类型定义了一个定制的构造器,你将无法访问到默认构造器(如果是结构体,则无法访问逐一对象构造器)。这个限制可以防止你在为值类型定义了一个更复杂的,完成了重要准备构造器之后,别人还是错误的使用了那个自动生成的构造器。
注意:
假如你想通过默认构造器、逐一对象构造器以及你自己定制的构造器为值类型创建实例,我们建议你将自己定制的构造器写到扩展(extension
)中,而不是跟值类型定义混在一起。想查看更多内容,请查看扩展章节。
下面例子将定义一个结构体Rect
,用来展现几何矩形。这个例子需要两个辅助的结构体Size
和Point
,它们各自为其所有的属性提供了初始值0.0
。
struct Size {
var width = 0.0, height = 0.0
}
struct Point {
var x = 0.0, y = 0.0
}
你可以通过以下三种方式为Rect
创建实例--使用默认的0值来初始化origin
和size
属性;使用特定的origin
和size
实例来初始化;使用特定的center
和size
来初始化。在下面Rect
结构体定义中,我们为着三种方式提供了三个自定义的构造器:
struct Rect {
var origin = Point()
var size = Size()
init() {}
init(origin: Point, size: Size) {
self.origin = origin
self.size = size
}
init(center: Point, size: Size) {
let originX = center.x - (size.width / 2)
let originY = center.y - (size.height / 2)
self.init(origin: Point(x: originX, y: originY), size: size)
}
}
第一个Rect
构造器init()
,在功能上跟没有自定义构造器时自动获得的默认构造器是一样的。这个构造器是一个空函数,使用一对大括号{}
来描述,它没有执行任何定制的构造过程。调用这个构造器将返回一个Rect
实例,它的origin
和size
属性都使用定义时的默认值Point(x: 0.0, y: 0.0)
和Size(width: 0.0, height: 0.0)
:
let basicRect = Rect()
// basicRect 的原点是 (0.0, 0.0),尺寸是 (0.0, 0.0)
第二个Rect
构造器init(origin:size:)
,在功能上跟结构体在没有自定义构造器时获得的逐一成员构造器是一样的。这个构造器只是简单的将origin
和size
的参数值赋给对应的存储型属性:
let originRect = Rect(origin: Point(x: 2.0, y: 2.0),
size: Size(width: 5.0, height: 5.0))
// originRect 的原点是 (2.0, 2.0),尺寸是 (5.0, 5.0)
第三个Rect
构造器init(center:size:)
稍微复杂一点。它先通过center
和size
的值计算出origin
的坐标。然后再调用(或代理给)init(origin:size:)
构造器来将新的origin
和size
值赋值到对应的属性中:
let centerRect = Rect(center: Point(x: 4.0, y: 4.0),
size: Size(width: 3.0, height: 3.0))
// centerRect 的原点是 (2.5, 2.5),尺寸是 (3.0, 3.0)
构造器init(center:size:)
可以自己将origin
和size
的新值赋值到对应的属性中。然而尽量利用现有的构造器和它所提供的功能来实现init(center:size:)
的功能,是更方便、更清晰和更直观的方法。
注意:
如果你想用另外一种不需要自己定义init()
和init(origin:size:)
的方式来实现这个例子,请参考扩展。