1,默认构造器
<span style="color:#3366ff;">class ShoppingListItem {
var name: String?
var quantity = 1
var purchased = false
}
var item = ShoppingListItem()</span>
<span style="color: rgb(102, 102, 102); font-family: Verdana, 'Lantinghei SC', 'Hiragino Sans GB', 'Microsoft Yahei', Helvetica, arial, 宋体, sans-serif; font-size: 14px; line-height: 26px;">由于</span><code style="box-sizing: border-box; font-family: Menlo, Monaco, Consolas, 'Courier New', monospace; font-size: 13px; border-top-left-radius: 4px; border-top-right-radius: 4px; border-bottom-right-radius: 4px; border-bottom-left-radius: 4px; padding: 2px 4px; color: rgb(45, 133, 202); background-color: rgb(249, 242, 244); line-height: 26px;">ShoppingListItem</code><span style="color: rgb(102, 102, 102); font-family: Verdana, 'Lantinghei SC', 'Hiragino Sans GB', 'Microsoft Yahei', Helvetica, arial, 宋体, sans-serif; font-size: 14px; line-height: 26px;">类中的所有属性都有默认值,且它是没有父类的基类,它将自动获得一个可以为所有属性设置默认值的默认构造器(尽管代码中没有显式为</span><code style="box-sizing: border-box; font-family: Menlo, Monaco, Consolas, 'Courier New', monospace; font-size: 13px; border-top-left-radius: 4px; border-top-right-radius: 4px; border-bottom-right-radius: 4px; border-bottom-left-radius: 4px; padding: 2px 4px; color: rgb(45, 133, 202); background-color: rgb(249, 242, 244); line-height: 26px;">name</code><span style="color: rgb(102, 102, 102); font-family: Verdana, 'Lantinghei SC', 'Hiragino Sans GB', 'Microsoft Yahei', Helvetica, arial, 宋体, sans-serif; font-size: 14px; line-height: 26px;">属性设置默认值,但由于</span><code style="box-sizing: border-box; font-family: Menlo, Monaco, Consolas, 'Courier New', monospace; font-size: 13px; border-top-left-radius: 4px; border-top-right-radius: 4px; border-bottom-right-radius: 4px; border-bottom-left-radius: 4px; padding: 2px 4px; color: rgb(45, 133, 202); background-color: rgb(249, 242, 244); line-height: 26px;">name</code><span style="color: rgb(102, 102, 102); font-family: Verdana, 'Lantinghei SC', 'Hiragino Sans GB', 'Microsoft Yahei', Helvetica, arial, 宋体, sans-serif; font-size: 14px; line-height: 26px;">是可选字符串类型,它将默认设置为</span><code style="box-sizing: border-box; font-family: Menlo, Monaco, Consolas, 'Courier New', monospace; font-size: 13px; border-top-left-radius: 4px; border-top-right-radius: 4px; border-bottom-right-radius: 4px; border-bottom-left-radius: 4px; padding: 2px 4px; color: rgb(45, 133, 202); background-color: rgb(249, 242, 244); line-height: 26px;">nil</code><span style="color: rgb(102, 102, 102); font-family: Verdana, 'Lantinghei SC', 'Hiragino Sans GB', 'Microsoft Yahei', Helvetica, arial, 宋体, sans-serif; font-size: 14px; line-height: 26px;">)</span>
<span style="color: rgb(51, 51, 51); font-family: Verdana, 'Lantinghei SC', 'Hiragino Sans GB', 'Microsoft Yahei', Helvetica, arial, 宋体, sans-serif; font-size: 18px; line-height: 1.1; white-space: pre-wrap; background-color: rgb(248, 248, 248);">
</span>
<span style="color: rgb(51, 51, 51); font-family: Verdana, 'Lantinghei SC', 'Hiragino Sans GB', 'Microsoft Yahei', Helvetica, arial, 宋体, sans-serif; font-size: 18px; line-height: 1.1; white-space: pre-wrap; background-color: rgb(248, 248, 248);">2,结构体的逐一成员构造器</span>
如果结构体对所有存储型属性提供了默认值且自身没有提供定制的构造器,它们能自动获得一个逐一成员构造器。
<span style="color:#3366ff;">struct Size {
var width = 0.0, height = 0.0
}
let twoByTwo = Size(width: 2.0, height: 2.0)</span>
<span style="color:#3366ff;">
</span>
<span style="color:#3366ff;"></span><h2 id="6991a0fd56a4a3d49a37bc291614a5fe" style="box-sizing: border-box; font-family: Verdana, 'Lantinghei SC', 'Hiragino Sans GB', 'Microsoft Yahei', Helvetica, arial, 宋体, sans-serif; font-weight: 500; line-height: 1.225; color: rgb(51, 51, 51); margin: 5px 0px; font-size: 18px; padding-bottom: 0.3em;">3,值类型的构造器代理</h2><span style="color: rgb(102, 102, 102); font-family: Verdana, 'Lantinghei SC', 'Hiragino Sans GB', 'Microsoft Yahei', Helvetica, arial, 宋体, sans-serif; font-size: 14px; line-height: 26px;">构造器可以通过调用其它构造器来完成实例的部分构造过程。这一过程称为构造器代理,它能减少多个构造器间的代码重复。</span>
<span style="color:#3366ff;"><span style="color: rgb(102, 102, 102); font-family: Verdana, 'Lantinghei SC', 'Hiragino Sans GB', 'Microsoft Yahei', Helvetica, arial, 宋体, sans-serif; font-size: 14px; line-height: 26px;"><span style="color: rgb(102, 102, 102); font-family: Verdana, 'Lantinghei SC', 'Hiragino Sans GB', 'Microsoft Yahei', Helvetica, arial, 宋体, sans-serif; font-size: 14px; line-height: 26px; white-space: pre-wrap; background-color: rgb(248, 248, 248);">如果你为某个值类型定义了一个定制的构造器,你将无法访问到默认构造器(如果是结构体,则无法访问逐一对象构造器)。</span>
</span></span>
<span style="font-family: Verdana, 'Lantinghei SC', 'Hiragino Sans GB', 'Microsoft Yahei', Helvetica, arial, 宋体, sans-serif; font-size: 14px; line-height: 26px;"></span><pre name="code" class="plain" style="background-color: rgb(248, 248, 248); color: rgb(51, 102, 255);">struct Size {
var width = 0.0, height = 0.0
}
struct Point {
var x = 0.0, y = 0.0
}
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)
}
}
<span style="font-family: Verdana, 'Lantinghei SC', 'Hiragino Sans GB', 'Microsoft Yahei', Helvetica, arial, 宋体, sans-serif; font-size: 14px; line-height: 26px;"><span style="color:#ff6600;">类里面的所有存储型属性--包括所有继承自父类的属性--都必须在构造过程中设置初始值。</span></span><span style="color:#3366ff;">
</span>
<span style="font-family: Verdana, 'Lantinghei SC', 'Hiragino Sans GB', 'Microsoft Yahei', Helvetica, arial, 宋体, sans-serif; font-size: 14px; line-height: 26px;"><span style="color:#666666;color: rgb(51, 102, 255);">
</span></span>
4,指定构造器和便利构造器
规则 1
指定构造器必须调用其直接父类的的指定构造器。
规则 2
便利构造器必须调用同一类中定义的其它构造器。
规则 3
便利构造器必须最终以调用一个指定构造器结束。
一个更方便记忆的方法是:
- 指定构造器必须总是向上代理
- 便利构造器必须总是横向代理
安全检查 1
指定构造器必须保证它所在类引入的所有属性都必须先初始化完成,之后才能将其它构造任务向上代理给父类中的构造器。
如上所述,一个对象的内存只有在其所有存储型属性确定之后才能完全初始化。为了满足这一规则,指定构造器必须保证它所在类引入的属性在它往上代理之前先完成初始化。
安全检查 2
指定构造器必须先向上代理调用父类构造器,然后再为继承的属性设置新值。如果没这么做,指定构造器赋予的新值将被父类中的构造器所覆盖。
安全检查 3
便利构造器必须先代理调用同一类中的其它构造器,然后再为任意属性赋新值。如果没这么做,便利构造器赋予的新值将被同一类中其它指定构造器所覆盖。
安全检查 4
构造器在第一阶段构造完成之前,不能调用任何实例方法、不能读取任何实例属性的值,self
的值不能被引用。
类实例在第一阶段结束以前并不是完全有效,仅能访问属性和调用方法,一旦完成第一阶段,该实例才会声明为有效实例。
构造器的继承和重写
跟 Objective-C 中的子类不同,Swift 中的子类不会默认继承父类的构造器。Swift 的这种机制可以防止一个父类的简单构造器被一个更专业的子类继承,并被错误的用来创建子类的实例。
假设要为子类中引入的任意新属性提供默认值,请遵守以下2个规则:
规则 1
如果子类没有定义任何指定构造器,它将自动继承所有父类的指定构造器。
规则 2
如果子类提供了所有父类指定构造器的实现--不管是通过规则1继承过来的,还是通过自定义实现的--它将自动继承所有父类的便利构造器。
即使你在子类中添加了更多的便利构造器,这两条规则仍然适用。
<span style="color:#3366ff;">class Food {
var name: String
init(name: String) {
self.name = name
}
convenience init() {
self.init(name: "[Unnamed]")
}
}</span>
<span style="color:#3366ff;">class RecipeIngredient: Food {
var quantity: Int
init(name: String, quantity: Int) {
self.quantity = quantity
super.init(name: name)
}
override convenience init(name: String) {
self.init(name: name, quantity: 1)
}
}</span>
<span style="color:#3366ff;">
</span>
<span style="color:#3366ff;">
</span>
<span style="color:#3366ff;"></span><p style="box-sizing: border-box; font-family: Verdana, 'Lantinghei SC', 'Hiragino Sans GB', 'Microsoft Yahei', Helvetica, arial, 宋体, sans-serif; margin-top: 0px; margin-bottom: 10px; color: rgb(102, 102, 102); line-height: 26px; font-size: 14px;"><code style="box-sizing: border-box; font-family: Menlo, Monaco, Consolas, 'Courier New', monospace; font-size: 13px; border-top-left-radius: 4px; border-top-right-radius: 4px; border-bottom-right-radius: 4px; border-bottom-left-radius: 4px; padding: 2px 4px; color: rgb(45, 133, 202); background-color: rgb(249, 242, 244);">RecipeIngredient</code>类拥有一个指定构造器<code style="box-sizing: border-box; font-family: Menlo, Monaco, Consolas, 'Courier New', monospace; font-size: 13px; border-top-left-radius: 4px; border-top-right-radius: 4px; border-bottom-right-radius: 4px; border-bottom-left-radius: 4px; padding: 2px 4px; color: rgb(45, 133, 202); background-color: rgb(249, 242, 244);">init(name: String, quantity: Int)</code>,它可以用来产生新<code style="box-sizing: border-box; font-family: Menlo, Monaco, Consolas, 'Courier New', monospace; font-size: 13px; border-top-left-radius: 4px; border-top-right-radius: 4px; border-bottom-right-radius: 4px; border-bottom-left-radius: 4px; padding: 2px 4px; color: rgb(45, 133, 202); background-color: rgb(249, 242, 244);">RecipeIngredient</code>实例的所有属性值。这个构造器一开始先将传入的<code style="box-sizing: border-box; font-family: Menlo, Monaco, Consolas, 'Courier New', monospace; font-size: 13px; border-top-left-radius: 4px; border-top-right-radius: 4px; border-bottom-right-radius: 4px; border-bottom-left-radius: 4px; padding: 2px 4px; color: rgb(45, 133, 202); background-color: rgb(249, 242, 244);">quantity</code>参数赋值给<code style="box-sizing: border-box; font-family: Menlo, Monaco, Consolas, 'Courier New', monospace; font-size: 13px; border-top-left-radius: 4px; border-top-right-radius: 4px; border-bottom-right-radius: 4px; border-bottom-left-radius: 4px; padding: 2px 4px; color: rgb(45, 133, 202); background-color: rgb(249, 242, 244);">quantity</code>属性,这个属性也是唯一在<code style="box-sizing: border-box; font-family: Menlo, Monaco, Consolas, 'Courier New', monospace; font-size: 13px; border-top-left-radius: 4px; border-top-right-radius: 4px; border-bottom-right-radius: 4px; border-bottom-left-radius: 4px; padding: 2px 4px; color: rgb(45, 133, 202); background-color: rgb(249, 242, 244);">RecipeIngredient</code>中新引入的属性。随后,构造器将任务向上代理给父类<code style="box-sizing: border-box; font-family: Menlo, Monaco, Consolas, 'Courier New', monospace; font-size: 13px; border-top-left-radius: 4px; border-top-right-radius: 4px; border-bottom-right-radius: 4px; border-bottom-left-radius: 4px; padding: 2px 4px; color: rgb(45, 133, 202); background-color: rgb(249, 242, 244);">Food</code>的<code style="box-sizing: border-box; font-family: Menlo, Monaco, Consolas, 'Courier New', monospace; font-size: 13px; border-top-left-radius: 4px; border-top-right-radius: 4px; border-bottom-right-radius: 4px; border-bottom-left-radius: 4px; padding: 2px 4px; color: rgb(45, 133, 202); background-color: rgb(249, 242, 244);">init(name: String)</code>。这个过程满足<a target=_blank href="http://wiki.jikexueyuan.com/project/swift/chapter2/14_Initialization.html#two_phase_initialization" style="box-sizing: border-box; background-color: transparent; color: rgb(45, 133, 202); text-decoration: none;">两段式构造过程</a>中的安全检查1。</p><p style="box-sizing: border-box; font-family: Verdana, 'Lantinghei SC', 'Hiragino Sans GB', 'Microsoft Yahei', Helvetica, arial, 宋体, sans-serif; margin-top: 0px; margin-bottom: 10px; color: rgb(102, 102, 102); line-height: 26px; font-size: 14px;"><code style="box-sizing: border-box; font-family: Menlo, Monaco, Consolas, 'Courier New', monospace; font-size: 13px; border-top-left-radius: 4px; border-top-right-radius: 4px; border-bottom-right-radius: 4px; border-bottom-left-radius: 4px; padding: 2px 4px; color: rgb(45, 133, 202); background-color: rgb(249, 242, 244);">RecipeIngredient</code>也定义了一个便利构造器<code style="box-sizing: border-box; font-family: Menlo, Monaco, Consolas, 'Courier New', monospace; font-size: 13px; border-top-left-radius: 4px; border-top-right-radius: 4px; border-bottom-right-radius: 4px; border-bottom-left-radius: 4px; padding: 2px 4px; color: rgb(45, 133, 202); background-color: rgb(249, 242, 244);">init(name: String)</code>,它只通过<code style="box-sizing: border-box; font-family: Menlo, Monaco, Consolas, 'Courier New', monospace; font-size: 13px; border-top-left-radius: 4px; border-top-right-radius: 4px; border-bottom-right-radius: 4px; border-bottom-left-radius: 4px; padding: 2px 4px; color: rgb(45, 133, 202); background-color: rgb(249, 242, 244);">name</code>来创建<code style="box-sizing: border-box; font-family: Menlo, Monaco, Consolas, 'Courier New', monospace; font-size: 13px; border-top-left-radius: 4px; border-top-right-radius: 4px; border-bottom-right-radius: 4px; border-bottom-left-radius: 4px; padding: 2px 4px; color: rgb(45, 133, 202); background-color: rgb(249, 242, 244);">RecipeIngredient</code>的实例。这个便利构造器假设任意<code style="box-sizing: border-box; font-family: Menlo, Monaco, Consolas, 'Courier New', monospace; font-size: 13px; border-top-left-radius: 4px; border-top-right-radius: 4px; border-bottom-right-radius: 4px; border-bottom-left-radius: 4px; padding: 2px 4px; color: rgb(45, 133, 202); background-color: rgb(249, 242, 244);">RecipeIngredient</code>实例的<code style="box-sizing: border-box; font-family: Menlo, Monaco, Consolas, 'Courier New', monospace; font-size: 13px; border-top-left-radius: 4px; border-top-right-radius: 4px; border-bottom-right-radius: 4px; border-bottom-left-radius: 4px; padding: 2px 4px; color: rgb(45, 133, 202); background-color: rgb(249, 242, 244);">quantity</code>为1,所以不需要显示指明数量即可创建出实例。这个便利构造器的定义可以让创建实例更加方便和快捷,并且避免了使用重复的代码来创建多个<code style="box-sizing: border-box; font-family: Menlo, Monaco, Consolas, 'Courier New', monospace; font-size: 13px; border-top-left-radius: 4px; border-top-right-radius: 4px; border-bottom-right-radius: 4px; border-bottom-left-radius: 4px; padding: 2px 4px; color: rgb(45, 133, 202); background-color: rgb(249, 242, 244);">quantity</code>为 1 的<code style="box-sizing: border-box; font-family: Menlo, Monaco, Consolas, 'Courier New', monospace; font-size: 13px; border-top-left-radius: 4px; border-top-right-radius: 4px; border-bottom-right-radius: 4px; border-bottom-left-radius: 4px; padding: 2px 4px; color: rgb(45, 133, 202); background-color: rgb(249, 242, 244);">RecipeIngredient</code>实例。这个便利构造器只是简单的将任务代理给了同一类里提供的指定构造器。</p><p style="box-sizing: border-box; font-family: Verdana, 'Lantinghei SC', 'Hiragino Sans GB', 'Microsoft Yahei', Helvetica, arial, 宋体, sans-serif; margin-top: 0px; margin-bottom: 10px; color: rgb(102, 102, 102); line-height: 26px; font-size: 14px;">注意,<code style="box-sizing: border-box; font-family: Menlo, Monaco, Consolas, 'Courier New', monospace; font-size: 13px; border-top-left-radius: 4px; border-top-right-radius: 4px; border-bottom-right-radius: 4px; border-bottom-left-radius: 4px; padding: 2px 4px; color: rgb(45, 133, 202); background-color: rgb(249, 242, 244);">RecipeIngredient</code>的便利构造器<code style="box-sizing: border-box; font-family: Menlo, Monaco, Consolas, 'Courier New', monospace; font-size: 13px; border-top-left-radius: 4px; border-top-right-radius: 4px; border-bottom-right-radius: 4px; border-bottom-left-radius: 4px; padding: 2px 4px; color: rgb(45, 133, 202); background-color: rgb(249, 242, 244);">init(name: String)</code>使用了跟<code style="box-sizing: border-box; font-family: Menlo, Monaco, Consolas, 'Courier New', monospace; font-size: 13px; border-top-left-radius: 4px; border-top-right-radius: 4px; border-bottom-right-radius: 4px; border-bottom-left-radius: 4px; padding: 2px 4px; color: rgb(45, 133, 202); background-color: rgb(249, 242, 244);">Food</code>中指定构造器<code style="box-sizing: border-box; font-family: Menlo, Monaco, Consolas, 'Courier New', monospace; font-size: 13px; border-top-left-radius: 4px; border-top-right-radius: 4px; border-bottom-right-radius: 4px; border-bottom-left-radius: 4px; padding: 2px 4px; color: rgb(45, 133, 202); background-color: rgb(249, 242, 244);">init(name: String)</code>相同的参数。因为这个便利构造器重写要父类的指定构造器<code style="box-sizing: border-box; font-family: Menlo, Monaco, Consolas, 'Courier New', monospace; font-size: 13px; border-top-left-radius: 4px; border-top-right-radius: 4px; border-bottom-right-radius: 4px; border-bottom-left-radius: 4px; padding: 2px 4px; color: rgb(45, 133, 202); background-color: rgb(249, 242, 244);">init(name: String)</code>,必须在前面使用使用<code style="box-sizing: border-box; font-family: Menlo, Monaco, Consolas, 'Courier New', monospace; font-size: 13px; border-top-left-radius: 4px; border-top-right-radius: 4px; border-bottom-right-radius: 4px; border-bottom-left-radius: 4px; padding: 2px 4px; color: rgb(45, 133, 202); background-color: rgb(249, 242, 244);">override</code>标识(参见<a target=_blank href="http://wiki.jikexueyuan.com/project/swift/chapter2/14_Initialization.html#initializer_inheritance_and_overriding" style="box-sizing: border-box; background-color: transparent; color: rgb(45, 133, 202); text-decoration: none;">构造器的继承和重写</a>)。</p><p style="box-sizing: border-box; font-family: Verdana, 'Lantinghei SC', 'Hiragino Sans GB', 'Microsoft Yahei', Helvetica, arial, 宋体, sans-serif; margin-top: 0px; margin-bottom: 10px; color: rgb(102, 102, 102); line-height: 26px; font-size: 14px;">在这个例子中,<code style="box-sizing: border-box; font-family: Menlo, Monaco, Consolas, 'Courier New', monospace; font-size: 13px; border-top-left-radius: 4px; border-top-right-radius: 4px; border-bottom-right-radius: 4px; border-bottom-left-radius: 4px; padding: 2px 4px; color: rgb(45, 133, 202); background-color: rgb(249, 242, 244);">RecipeIngredient</code>的父类是<code style="box-sizing: border-box; font-family: Menlo, Monaco, Consolas, 'Courier New', monospace; font-size: 13px; border-top-left-radius: 4px; border-top-right-radius: 4px; border-bottom-right-radius: 4px; border-bottom-left-radius: 4px; padding: 2px 4px; color: rgb(45, 133, 202); background-color: rgb(249, 242, 244);">Food</code>,它有一个便利构造器<code style="box-sizing: border-box; font-family: Menlo, Monaco, Consolas, 'Courier New', monospace; font-size: 13px; border-top-left-radius: 4px; border-top-right-radius: 4px; border-bottom-right-radius: 4px; border-bottom-left-radius: 4px; padding: 2px 4px; color: rgb(45, 133, 202); background-color: rgb(249, 242, 244);">init()</code>。这个构造器因此也被<code style="box-sizing: border-box; font-family: Menlo, Monaco, Consolas, 'Courier New', monospace; font-size: 13px; border-top-left-radius: 4px; border-top-right-radius: 4px; border-bottom-right-radius: 4px; border-bottom-left-radius: 4px; padding: 2px 4px; color: rgb(45, 133, 202); background-color: rgb(249, 242, 244);">RecipeIngredient</code>继承。这个继承的<code style="box-sizing: border-box; font-family: Menlo, Monaco, Consolas, 'Courier New', monospace; font-size: 13px; border-top-left-radius: 4px; border-top-right-radius: 4px; border-bottom-right-radius: 4px; border-bottom-left-radius: 4px; padding: 2px 4px; color: rgb(45, 133, 202); background-color: rgb(249, 242, 244);">init()</code>函数版本跟<code style="box-sizing: border-box; font-family: Menlo, Monaco, Consolas, 'Courier New', monospace; font-size: 13px; border-top-left-radius: 4px; border-top-right-radius: 4px; border-bottom-right-radius: 4px; border-bottom-left-radius: 4px; padding: 2px 4px; color: rgb(45, 133, 202); background-color: rgb(249, 242, 244);">Food</code>提供的版本是一样的,除了它是将任务代理给<code style="box-sizing: border-box; font-family: Menlo, Monaco, Consolas, 'Courier New', monospace; font-size: 13px; border-top-left-radius: 4px; border-top-right-radius: 4px; border-bottom-right-radius: 4px; border-bottom-left-radius: 4px; padding: 2px 4px; color: rgb(45, 133, 202); background-color: rgb(249, 242, 244);">RecipeIngredient</code>版本的<code style="box-sizing: border-box; font-family: Menlo, Monaco, Consolas, 'Courier New', monospace; font-size: 13px; border-top-left-radius: 4px; border-top-right-radius: 4px; border-bottom-right-radius: 4px; border-bottom-left-radius: 4px; padding: 2px 4px; color: rgb(45, 133, 202); background-color: rgb(249, 242, 244);">init(name: String)</code>而不是<code style="box-sizing: border-box; font-family: Menlo, Monaco, Consolas, 'Courier New', monospace; font-size: 13px; border-top-left-radius: 4px; border-top-right-radius: 4px; border-bottom-right-radius: 4px; border-bottom-left-radius: 4px; padding: 2px 4px; color: rgb(45, 133, 202); background-color: rgb(249, 242, 244);">Food</code>提供的版本。</p>
<span style="color:#3366ff;">let oneMysteryItem = RecipeIngredient()
let oneBacon = RecipeIngredient(name: "Bacon")
let sixEggs = RecipeIngredient(name: "Eggs", quantity: 6)</span>
5,可失败构造器
如果一个类,结构体或枚举类型的对象,在构造自身的过程中有可能失败,则为其定义一个可失败构造器,是非常有必要的。这里所指的“失败”是指,如给构造器传入无效的参数值,或缺少某种所需的外部资源,又或是不满足某种必要的条件等。
为了妥善处理这种构造过程中可能会失败的情况。你可以在一个类,结构体或是枚举类型的定义中,添加一个或多个可失败构造器。其语法为在init
关键字后面加添问号(init?)
。
<span style="color:#3366ff;">struct Animal {
let species: String
init?(species: String) {
if species.isEmpty { return nil }
self.species = species
}
}</span>
<span style="color:#3366ff;">let someCreature = Animal(species: "Giraffe")
// someCreature 的类型是 Animal? 而不是 Animal
if let giraffe = someCreature {
print("An animal was initialized with a species of \(giraffe.species)")
}
// 打印 "An animal was initialized with a species of Giraffe"</span>
枚举类型的可失败构造器
你可以通过构造一个带一个或多个参数的可失败构造器来获取枚举类型中特定的枚举成员。还能在参数不满足你所期望的条件时,导致构造失败。
<span style="color:#3366ff;">enum TemperatureUnit {
case Kelvin, Celsius, Fahrenheit
init?(symbol: Character) {
switch symbol {
case "K":
self = .Kelvin
case "C":
self = .Celsius
case "F":
self = .Fahrenheit
default:
return nil
}
}
}</span>
<h3 style="box-sizing: border-box; font-family: Verdana, 'Lantinghei SC', 'Hiragino Sans GB', 'Microsoft Yahei', Helvetica, arial, 宋体, sans-serif; font-weight: 500; line-height: 1.1; color: rgb(51, 51, 51); margin-top: 30px; margin-bottom: 10px; font-size: 18px;">构造失败的传递</h3><p style="box-sizing: border-box; font-family: Verdana, 'Lantinghei SC', 'Hiragino Sans GB', 'Microsoft Yahei', Helvetica, arial, 宋体, sans-serif; margin-top: 0px; margin-bottom: 10px; color: rgb(102, 102, 102); line-height: 26px; font-size: 14px;">可失败构造器同样满足在<a target=_blank href="http://wiki.jikexueyuan.com/project/swift/chapter2/14_Initialization.html#initialization_chain" style="box-sizing: border-box; background-color: transparent; color: rgb(45, 133, 202); text-decoration: none;">构造器链</a>中所描述的构造规则。其允许在同一类,结构体和枚举中横向代理其他的可失败构造器。类似的,子类的可失败构造器也能向上代理基类的可失败构造器。</p>
注意: 你可以用一个非可失败构造器重写一个可失败构造器,但反过来却行不通。
可失败构造器 init!
通常来说我们通过在init
关键字后添加问号的方式来定义一个可失败构造器,但你也可以使用通过在init
后面添加惊叹号的方式来定义一个可失败构造器(init!)
,该可失败构造器将会构建一个特定类型的隐式解析可选类型的对象。
你可以在 init?
构造器中代理调用 init!
构造器,反之亦然。 你也可以用 init?
重写 init!
,反之亦然。 你还可以用 init
代理调用init!
,但这会触发一个断言:是否 init!
构造器会触发构造失败?
<span style="font-family: Verdana, 'Lantinghei SC', 'Hiragino Sans GB', 'Microsoft Yahei', Helvetica, arial, 宋体, sans-serif; font-size: 14px; line-height: 26px;"><span style="color:#3366ff;background-color: rgb(248, 248, 248);"><span style="color: rgb(102, 102, 102); font-family: Verdana, 'Lantinghei SC', 'Hiragino Sans GB', 'Microsoft Yahei', Helvetica, arial, 宋体, sans-serif; font-size: 14px; line-height: 26px;"></span></span></span><h2 id="a1531f1b787f93be773413756d84538c" style="box-sizing: border-box; font-family: Verdana, 'Lantinghei SC', 'Hiragino Sans GB', 'Microsoft Yahei', Helvetica, arial, 宋体, sans-serif; font-weight: 500; line-height: 1.225; color: rgb(51, 51, 51); margin: 5px 0px; font-size: 18px; padding-bottom: 0.3em;">必要构造器</h2>
在类的构造器前添加
required
修饰符表明所有该类的子类都必须实现该构造器
<span style="font-family: Verdana, 'Lantinghei SC', 'Hiragino Sans GB', 'Microsoft Yahei', Helvetica, arial, 宋体, sans-serif; font-size: 14px; line-height: 26px;"><span style="color:#3366ff;background-color: rgb(248, 248, 248);"><span style="color: rgb(102, 102, 102); font-family: Verdana, 'Lantinghei SC', 'Hiragino Sans GB', 'Microsoft Yahei', Helvetica, arial, 宋体, sans-serif; font-size: 14px; line-height: 26px;">
</span></span></span>
<span style="font-family: Verdana, 'Lantinghei SC', 'Hiragino Sans GB', 'Microsoft Yahei', Helvetica, arial, 宋体, sans-serif; font-size: 14px; line-height: 26px;"><span style="color:#3366ff;background-color: rgb(248, 248, 248);"><span style="color: rgb(102, 102, 102); font-family: Verdana, 'Lantinghei SC', 'Hiragino Sans GB', 'Microsoft Yahei', Helvetica, arial, 宋体, sans-serif; font-size: 14px; line-height: 26px;">
</span></span></span>