Swift 構(gòu)造過(guò)程

構(gòu)造過(guò)程是為了使用某個(gè)類(lèi)、結(jié)構(gòu)體或枚舉類(lèi)型的實(shí)例而進(jìn)行的準(zhǔn)備過(guò)程。這個(gè)過(guò)程包含了為實(shí)例中的每個(gè)屬性設(shè)置初始值和為其執(zhí)行必要的準(zhǔn)備和初始化任務(wù)。

Swift 構(gòu)造函數(shù)使用 init() 方法。

與 Objective-C 中的構(gòu)造器不同,Swift 的構(gòu)造器無(wú)需返回值,它們的主要任務(wù)是保證新實(shí)例在第一次使用前完成正確的初始化。

類(lèi)實(shí)例也可以通過(guò)定義析構(gòu)器(deinitializer)在類(lèi)實(shí)例釋放之前執(zhí)行清理內(nèi)存的工作。

存儲(chǔ)型屬性的初始賦值

類(lèi)和結(jié)構(gòu)體在實(shí)例創(chuàng)建時(shí),必須為所有存儲(chǔ)型屬性設(shè)置合適的初始值。

存儲(chǔ)屬性在構(gòu)造器中賦值時(shí),它們的值是被直接設(shè)置的,不會(huì)觸發(fā)任何屬性觀測(cè)器。

存儲(chǔ)屬性在構(gòu)造器中賦值流程:

創(chuàng)建初始值。

在屬性定義中指定默認(rèn)屬性值。

初始化實(shí)例,并調(diào)用 init() 方法。

構(gòu)造器

構(gòu)造器在創(chuàng)建某特定類(lèi)型的新實(shí)例時(shí)調(diào)用。它的最簡(jiǎn)形式類(lèi)似于一個(gè)不帶任何參數(shù)的實(shí)例方法,以關(guān)鍵字init命名。

語(yǔ)法

init()

{

// 實(shí)例化后執(zhí)行的代碼

}

實(shí)例

以下結(jié)構(gòu)體定義了一個(gè)不帶參數(shù)的構(gòu)造器 init,并在里面將存儲(chǔ)型屬性 length 和 breadth 的值初始化為 6 和 12:

struct rectangle {

var length: Double

var breadth: Double

init() {

length = 6

breadth = 12

}

}

var area = rectangle()

print("矩形面積為 \(area.length*area.breadth)")

以上程序執(zhí)行輸出結(jié)果為:

矩形面積為 72.0

默認(rèn)屬性值

我們可以在構(gòu)造器中為存儲(chǔ)型屬性設(shè)置初始值;同樣,也可以在屬性聲明時(shí)為其設(shè)置默認(rèn)值。

使用默認(rèn)值能讓你的構(gòu)造器更簡(jiǎn)潔、更清晰,且能通過(guò)默認(rèn)值自動(dòng)推導(dǎo)出屬性的類(lèi)型。

以下實(shí)例我們?cè)趯傩月暶鲿r(shí)為其設(shè)置默認(rèn)值:

struct rectangle {

// 設(shè)置默認(rèn)值

var length = 6

var breadth = 12

}

var area = rectangle()

print("矩形的面積為 \(area.length*area.breadth)")

以上程序執(zhí)行輸出結(jié)果為:

矩形面積為 72

構(gòu)造參數(shù)

你可以在定義構(gòu)造器 init() 時(shí)提供構(gòu)造參數(shù),如下所示:

struct Rectangle {

var length: Double

var breadth: Double

var area: Double

init(fromLength length: Double, fromBreadth breadth: Double) {

self.length = length

self.breadth = breadth

area = length * breadth

}

init(fromLeng leng: Double, fromBread bread: Double) {

self.length = leng

self.breadth = bread

area = leng * bread

}

}

let ar = Rectangle(fromLength: 6, fromBreadth: 12)

print("面積為: \(ar.area)")

let are = Rectangle(fromLeng: 36, fromBread: 12)

print("面積為: \(are.area)")

以上程序執(zhí)行輸出結(jié)果為:

面積為: 72.0

面積為: 432.0

內(nèi)部和外部參數(shù)名

跟函數(shù)和方法參數(shù)相同,構(gòu)造參數(shù)也存在一個(gè)在構(gòu)造器內(nèi)部使用的參數(shù)名字和一個(gè)在調(diào)用構(gòu)造器時(shí)使用的外部參數(shù)名字。

然而,構(gòu)造器并不像函數(shù)和方法那樣在括號(hào)前有一個(gè)可辨別的名字。所以在調(diào)用構(gòu)造器時(shí),主要通過(guò)構(gòu)造器中的參數(shù)名和類(lèi)型來(lái)確定需要調(diào)用的構(gòu)造器。

如果你在定義構(gòu)造器時(shí)沒(méi)有提供參數(shù)的外部名字,Swift 會(huì)為每個(gè)構(gòu)造器的參數(shù)自動(dòng)生成一個(gè)跟內(nèi)部名字相同的外部名。

struct Color {

let red, green, blue: Double

init(red: Double, green: Double, blue: Double) {

self.red? = red

self.green = green

self.blue? = blue

}

init(white: Double) {

red? = white

green = white

blue? = white

}

}

// 創(chuàng)建一個(gè)新的Color實(shí)例,通過(guò)三種顏色的外部參數(shù)名來(lái)傳值,并調(diào)用構(gòu)造器

let magenta = Color(red: 1.0, green: 0.0, blue: 1.0)

print("red 值為: \(magenta.red)")

print("green 值為: \(magenta.green)")

print("blue 值為: \(magenta.blue)")

// 創(chuàng)建一個(gè)新的Color實(shí)例,通過(guò)三種顏色的外部參數(shù)名來(lái)傳值,并調(diào)用構(gòu)造器

let halfGray = Color(white: 0.5)

print("red 值為: \(halfGray.red)")

print("green 值為: \(halfGray.green)")

print("blue 值為: \(halfGray.blue)")

以上程序執(zhí)行輸出結(jié)果為:

red 值為: 1.0

green 值為: 0.0

blue 值為: 1.0

red 值為: 0.5

green 值為: 0.5

blue 值為: 0.5

沒(méi)有外部名稱(chēng)參數(shù)

如果你不希望為構(gòu)造器的某個(gè)參數(shù)提供外部名字,你可以使用下劃線_來(lái)顯示描述它的外部名。

struct Rectangle {

var length: Double

init(frombreadth breadth: Double) {

length = breadth * 10

}

init(frombre bre: Double) {

length = bre * 30

}

//不提供外部名字

init(_ area: Double) {

length = area

}

}

// 調(diào)用不提供外部名字

let rectarea = Rectangle(180.0)

print("面積為: \(rectarea.length)")

// 調(diào)用不提供外部名字

let rearea = Rectangle(370.0)

print("面積為: \(rearea.length)")

// 調(diào)用不提供外部名字

let recarea = Rectangle(110.0)

print("面積為: \(recarea.length)")

以上程序執(zhí)行輸出結(jié)果為:

面積為: 180.0

面積為: 370.0

面積為: 110.0

可選屬性類(lèi)型

如果你定制的類(lèi)型包含一個(gè)邏輯上允許取值為空的存儲(chǔ)型屬性,你都需要將它定義為可選類(lèi)型optional type(可選屬性類(lèi)型)。

當(dāng)存儲(chǔ)屬性聲明為可選時(shí),將自動(dòng)初始化為空 nil。

struct Rectangle {

var length: Double?

init(frombreadth breadth: Double) {

length = breadth * 10

}

init(frombre bre: Double) {

length = bre * 30

}

init(_ area: Double) {

length = area

}

}

let rectarea = Rectangle(180.0)

print("面積為:\(rectarea.length)")

let rearea = Rectangle(370.0)

print("面積為:\(rearea.length)")

let recarea = Rectangle(110.0)

print("面積為:\(recarea.length)")

以上程序執(zhí)行輸出結(jié)果為:

面積為:Optional(180.0)

面積為:Optional(370.0)

面積為:Optional(110.0)

構(gòu)造過(guò)程中修改常量屬性

只要在構(gòu)造過(guò)程結(jié)束前常量的值能確定,你可以在構(gòu)造過(guò)程中的任意時(shí)間點(diǎn)修改常量屬性的值。

對(duì)某個(gè)類(lèi)實(shí)例來(lái)說(shuō),它的常量屬性只能在定義它的類(lèi)的構(gòu)造過(guò)程中修改;不能在子類(lèi)中修改。

盡管 length 屬性現(xiàn)在是常量,我們?nèi)匀豢梢栽谄漕?lèi)的構(gòu)造器中設(shè)置它的值:

struct Rectangle {

let length: Double?

init(frombreadth breadth: Double) {

length = breadth * 10

}

init(frombre bre: Double) {

length = bre * 30

}

init(_ area: Double) {

length = area

}

}

let rectarea = Rectangle(180.0)

print("面積為:\(rectarea.length)")

let rearea = Rectangle(370.0)

print("面積為:\(rearea.length)")

let recarea = Rectangle(110.0)

print("面積為:\(recarea.length)")

以上程序執(zhí)行輸出結(jié)果為:

面積為:Optional(180.0)

面積為:Optional(370.0)

面積為:Optional(110.0)

默認(rèn)構(gòu)造器

默認(rèn)構(gòu)造器將簡(jiǎn)單的創(chuàng)建一個(gè)所有屬性值都設(shè)置為默認(rèn)值的實(shí)例:

以下實(shí)例中,ShoppingListItem類(lèi)中的所有屬性都有默認(rèn)值,且它是沒(méi)有父類(lèi)的基類(lèi),它將自動(dòng)獲得一個(gè)可以為所有屬性設(shè)置默認(rèn)值的默認(rèn)構(gòu)造器

class ShoppingListItem {

var name: String?

var quantity = 1

var purchased = false

}

var item = ShoppingListItem()

print("名字為: \(item.name)")

print("數(shù)理為: \(item.quantity)")

print("是否付款: \(item.purchased)")

以上程序執(zhí)行輸出結(jié)果為:

名字為: nil

數(shù)理為: 1

是否付款: false

結(jié)構(gòu)體的逐一成員構(gòu)造器

如果結(jié)構(gòu)體對(duì)所有存儲(chǔ)型屬性提供了默認(rèn)值且自身沒(méi)有提供定制的構(gòu)造器,它們能自動(dòng)獲得一個(gè)逐一成員構(gòu)造器。

我們?cè)谡{(diào)用逐一成員構(gòu)造器時(shí),通過(guò)與成員屬性名相同的參數(shù)名進(jìn)行傳值來(lái)完成對(duì)成員屬性的初始賦值。

下面例子中定義了一個(gè)結(jié)構(gòu)體 Rectangle,它包含兩個(gè)屬性 length 和 breadth。Swift 可以根據(jù)這兩個(gè)屬性的初始賦值100.0 、200.0自動(dòng)推導(dǎo)出它們的類(lèi)型Double。

struct Rectangle {

var length = 100.0, breadth = 200.0

}

let area = Rectangle(length: 24.0, breadth: 32.0)

print("矩形的面積: \(area.length)")

print("矩形的面積: \(area.breadth)")

由于這兩個(gè)存儲(chǔ)型屬性都有默認(rèn)值,結(jié)構(gòu)體 Rectangle 自動(dòng)獲得了一個(gè)逐一成員構(gòu)造器 init(width:height:)。 你可以用它來(lái)為 Rectangle 創(chuàng)建新的實(shí)例。

以上程序執(zhí)行輸出結(jié)果為:

名字為: nil

矩形的面積: 24.0

矩形的面積: 32.0

值類(lèi)型的構(gòu)造器代理

構(gòu)造器可以通過(guò)調(diào)用其它構(gòu)造器來(lái)完成實(shí)例的部分構(gòu)造過(guò)程。這一過(guò)程稱(chēng)為構(gòu)造器代理,它能減少多個(gè)構(gòu)造器間的代碼重復(fù)。

以下實(shí)例中,Rect 結(jié)構(gòu)體調(diào)用了 Size 和 Point 的構(gòu)造過(guò)程:

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)

}

}

// origin和size屬性都使用定義時(shí)的默認(rèn)值Point(x: 0.0, y: 0.0)和Size(width: 0.0, height: 0.0):

let basicRect = Rect()

print("Size 結(jié)構(gòu)體初始值: \(basicRect.size.width, basicRect.size.height) ")

print("Rect 結(jié)構(gòu)體初始值: \(basicRect.origin.x, basicRect.origin.y) ")

// 將origin和size的參數(shù)值賦給對(duì)應(yīng)的存儲(chǔ)型屬性

let originRect = Rect(origin: Point(x: 2.0, y: 2.0),

size: Size(width: 5.0, height: 5.0))

print("Size 結(jié)構(gòu)體初始值: \(originRect.size.width, originRect.size.height) ")

print("Rect 結(jié)構(gòu)體初始值: \(originRect.origin.x, originRect.origin.y) ")

//先通過(guò)center和size的值計(jì)算出origin的坐標(biāo)。

//然后再調(diào)用(或代理給)init(origin:size:)構(gòu)造器來(lái)將新的origin和size值賦值到對(duì)應(yīng)的屬性中

let centerRect = Rect(center: Point(x: 4.0, y: 4.0),

size: Size(width: 3.0, height: 3.0))

print("Size 結(jié)構(gòu)體初始值: \(centerRect.size.width, centerRect.size.height) ")

print("Rect 結(jié)構(gòu)體初始值: \(centerRect.origin.x, centerRect.origin.y) ")

以上程序執(zhí)行輸出結(jié)果為:

Size 結(jié)構(gòu)體初始值: (0.0, 0.0)

Rect 結(jié)構(gòu)體初始值: (0.0, 0.0)

Size 結(jié)構(gòu)體初始值: (5.0, 5.0)

Rect 結(jié)構(gòu)體初始值: (2.0, 2.0)

Size 結(jié)構(gòu)體初始值: (3.0, 3.0)

Rect 結(jié)構(gòu)體初始值: (2.5, 2.5)

構(gòu)造器代理規(guī)則

值類(lèi)型 類(lèi)類(lèi)型

不支持繼承,所以構(gòu)造器代理的過(guò)程相對(duì)簡(jiǎn)單,因?yàn)樗鼈冎荒艽斫o本身提供的其它構(gòu)造器。 你可以使用self.init在自定義的構(gòu)造器中引用其它的屬于相同值類(lèi)型的構(gòu)造器。 它可以繼承自其它類(lèi),這意味著類(lèi)有責(zé)任保證其所有繼承的存儲(chǔ)型屬性在構(gòu)造時(shí)也能正確的初始化。

類(lèi)的繼承和構(gòu)造過(guò)程

Swift 提供了兩種類(lèi)型的類(lèi)構(gòu)造器來(lái)確保所有類(lèi)實(shí)例中存儲(chǔ)型屬性都能獲得初始值,它們分別是指定構(gòu)造器和便利構(gòu)造器。

指定構(gòu)造器 便利構(gòu)造器

類(lèi)中最主要的構(gòu)造器 類(lèi)中比較次要的、輔助型的構(gòu)造器

初始化類(lèi)中提供的所有屬性,并根據(jù)父類(lèi)鏈往上調(diào)用父類(lèi)的構(gòu)造器來(lái)實(shí)現(xiàn)父類(lèi)的初始化。 可以定義便利構(gòu)造器來(lái)調(diào)用同一個(gè)類(lèi)中的指定構(gòu)造器,并為其參數(shù)提供默認(rèn)值。你也可以定義便利構(gòu)造器來(lái)創(chuàng)建一個(gè)特殊用途或特定輸入的實(shí)例。

每一個(gè)類(lèi)都必須擁有至少一個(gè)指定構(gòu)造器 只在必要的時(shí)候?yàn)轭?lèi)提供便利構(gòu)造器

Init(parameters) {

statements

}

convenience init(parameters) {

statements

}

指定構(gòu)造器實(shí)例

class mainClass {

var no1 : Int // 局部存儲(chǔ)變量

init(no1 : Int) {

self.no1 = no1 // 初始化

}

}

class subClass : mainClass {

var no2 : Int // 新的子類(lèi)存儲(chǔ)變量

init(no1 : Int, no2 : Int) {

self.no2 = no2 // 初始化

super.init(no1:no1) // 初始化超類(lèi)

}

}

let res = mainClass(no1: 10)

let res2 = subClass(no1: 10, no2: 20)

print("res 為: \(res.no1)")

print("res2 為: \(res2.no1)")

print("res2 為: \(res2.no2)")

以上程序執(zhí)行輸出結(jié)果為:

res 為: 10

res 為: 10

res 為: 20

便利構(gòu)造器實(shí)例

class mainClass {

var no1 : Int // 局部存儲(chǔ)變量

init(no1 : Int) {

self.no1 = no1 // 初始化

}

}

class subClass : mainClass {

var no2 : Int

init(no1 : Int, no2 : Int) {

self.no2 = no2

super.init(no1:no1)

}

// 便利方法只需要一個(gè)參數(shù)

override convenience init(no1: Int)? {

self.init(no1:no1, no2:0)

}

}

let res = mainClass(no1: 20)

let res2 = subClass(no1: 30, no2: 50)

print("res 為: \(res.no1)")

print("res2 為: \(res2.no1)")

print("res2 為: \(res2.no2)")

以上程序執(zhí)行輸出結(jié)果為:

res 為: 20

res2 為: 30

res2 為: 50

構(gòu)造器的繼承和重載

Swift 中的子類(lèi)不會(huì)默認(rèn)繼承父類(lèi)的構(gòu)造器。

父類(lèi)的構(gòu)造器僅在確定和安全的情況下被繼承。

當(dāng)你重寫(xiě)一個(gè)父類(lèi)指定構(gòu)造器時(shí),你需要寫(xiě)override修飾符。

class SuperClass {

var corners = 4

var description: String {

return "\(corners) 邊"

}

}

let rectangle = SuperClass()

print("矩形: \(rectangle.description)")

class SubClass: SuperClass {

override init() {? //重載構(gòu)造器

super.init()

corners = 5

}

}

let subClass = SubClass()

print("五角型: \(subClass.description)")

以上程序執(zhí)行輸出結(jié)果為:

矩形: 4 邊

五角型: 5 邊

指定構(gòu)造器和便利構(gòu)造器實(shí)例

接下來(lái)的例子將在操作中展示指定構(gòu)造器、便利構(gòu)造器和自動(dòng)構(gòu)造器的繼承。

它定義了包含兩個(gè)個(gè)類(lèi)MainClass、SubClass的類(lèi)層次結(jié)構(gòu),并將演示它們的構(gòu)造器是如何相互作用的。

class MainClass {

var name: String

init(name: String) {

self.name = name

}

convenience init() {

self.init(name: "[匿名]")

}

}

let main = MainClass(name: "Runoob")

print("MainClass 名字為: \(main.name)")

let main2 = MainClass()

print("沒(méi)有對(duì)應(yīng)名字: \(main2.name)")

class SubClass: MainClass {

var count: Int

init(name: String, count: Int) {

self.count = count

super.init(name: name)

}

override convenience init(name: String) {

self.init(name: name, count: 1)

}

}

let sub = SubClass(name: "Runoob")

print("MainClass 名字為: \(sub.name)")

let sub2 = SubClass(name: "Runoob", count: 3)

print("count 變量: \(sub2.count)")

以上程序執(zhí)行輸出結(jié)果為:

MainClass 名字為: Runoob

沒(méi)有對(duì)應(yīng)名字: [匿名]

MainClass 名字為: Runoob

count 變量: 3

類(lèi)的可失敗構(gòu)造器

如果一個(gè)類(lèi),結(jié)構(gòu)體或枚舉類(lèi)型的對(duì)象,在構(gòu)造自身的過(guò)程中有可能失敗,則為其定義一個(gè)可失敗構(gòu)造器。

變量初始化失敗可能的原因有:

傳入無(wú)效的參數(shù)值。

缺少某種所需的外部資源。

沒(méi)有滿足特定條件。

為了妥善處理這種構(gòu)造過(guò)程中可能會(huì)失敗的情況。

你可以在一個(gè)類(lèi),結(jié)構(gòu)體或是枚舉類(lèi)型的定義中,添加一個(gè)或多個(gè)可失敗構(gòu)造器。其語(yǔ)法為在init關(guān)鍵字后面加添問(wèn)號(hào)(init?)。

實(shí)例

下例中,定義了一個(gè)名為Animal的結(jié)構(gòu)體,其中有一個(gè)名為species的,String類(lèi)型的常量屬性。

同時(shí)該結(jié)構(gòu)體還定義了一個(gè),帶一個(gè)String類(lèi)型參數(shù)species的,可失敗構(gòu)造器。這個(gè)可失敗構(gòu)造器,被用來(lái)檢查傳入的參數(shù)是否為一個(gè)空字符串,如果為空字符串,則該可失敗構(gòu)造器,構(gòu)建對(duì)象失敗,否則成功。

struct Animal {

let species: String

init?(species: String) {

if species.isEmpty { return nil }

self.species = species

}

}

//通過(guò)該可失敗構(gòu)造器來(lái)構(gòu)建一個(gè)Animal的對(duì)象,并檢查其構(gòu)建過(guò)程是否成功

// someCreature 的類(lèi)型是 Animal? 而不是 Animal

let someCreature = Animal(species: "長(zhǎng)頸鹿")

// 打印 "動(dòng)物初始化為長(zhǎng)頸鹿"

if let giraffe = someCreature {

print("動(dòng)物初始化為\(giraffe.species)")

}

以上程序執(zhí)行輸出結(jié)果為:

動(dòng)物初始化為長(zhǎng)頸鹿

枚舉類(lèi)型的可失敗構(gòu)造器

你可以通過(guò)構(gòu)造一個(gè)帶一個(gè)或多個(gè)參數(shù)的可失敗構(gòu)造器來(lái)獲取枚舉類(lèi)型中特定的枚舉成員。

實(shí)例

下例中,定義了一個(gè)名為T(mén)emperatureUnit的枚舉類(lèi)型。其中包含了三個(gè)可能的枚舉成員(Kelvin,Celsius,和 Fahrenheit)和一個(gè)被用來(lái)找到Character值所對(duì)應(yīng)的枚舉成員的可失敗構(gòu)造器:

enum TemperatureUnit {

// 開(kāi)爾文,攝氏,華氏

case Kelvin, Celsius, Fahrenheit

init?(symbol: Character) {

switch symbol {

case "K":

self = .Kelvin

case "C":

self = .Celsius

case "F":

self = .Fahrenheit

default:

return nil

}

}

}

let fahrenheitUnit = TemperatureUnit(symbol: "F")

if fahrenheitUnit != nil {

print("這是一個(gè)已定義的溫度單位,所以初始化成功。")

}

let unknownUnit = TemperatureUnit(symbol: "X")

if unknownUnit == nil {

print("這不是一個(gè)已定義的溫度單位,所以初始化失敗。")

}

以上程序執(zhí)行輸出結(jié)果為:

這是一個(gè)已定義的溫度單位,所以初始化成功。

這不是一個(gè)已定義的溫度單位,所以初始化失敗。

類(lèi)的可失敗構(gòu)造器

值類(lèi)型(如結(jié)構(gòu)體或枚舉類(lèi)型)的可失敗構(gòu)造器,對(duì)何時(shí)何地觸發(fā)構(gòu)造失敗這個(gè)行為沒(méi)有任何的限制。

但是,類(lèi)的可失敗構(gòu)造器只能在所有的類(lèi)屬性被初始化后和所有類(lèi)之間的構(gòu)造器之間的代理調(diào)用發(fā)生完后觸發(fā)失敗行為。

實(shí)例

下例子中,定義了一個(gè)名為 StudRecord 的類(lèi),因?yàn)?studname 屬性是一個(gè)常量,所以一旦 StudRecord 類(lèi)構(gòu)造成功,studname 屬性肯定有一個(gè)非nil的值。

class StudRecord {

let studname: String!

init?(studname: String) {

self.studname = studname

if studname.isEmpty { return nil }

}

}

if let stname = StudRecord(studname: "失敗構(gòu)造器") {

print("模塊為 \(stname.studname)")

}

以上程序執(zhí)行輸出結(jié)果為:

模塊為 失敗構(gòu)造器

覆蓋一個(gè)可失敗構(gòu)造器

就如同其它構(gòu)造器一樣,你也可以用子類(lèi)的可失敗構(gòu)造器覆蓋基類(lèi)的可失敗構(gòu)造器。

者你也可以用子類(lèi)的非可失敗構(gòu)造器覆蓋一個(gè)基類(lèi)的可失敗構(gòu)造器。

你可以用一個(gè)非可失敗構(gòu)造器覆蓋一個(gè)可失敗構(gòu)造器,但反過(guò)來(lái)卻行不通。

一個(gè)非可失敗的構(gòu)造器永遠(yuǎn)也不能代理調(diào)用一個(gè)可失敗構(gòu)造器。

實(shí)例

以下實(shí)例描述了可失敗與非可失敗構(gòu)造器:

class Planet {

var name: String

init(name: String) {

self.name = name

}

convenience init() {

self.init(name: "[No Planets]")

}

}

let plName = Planet(name: "Mercury")

print("行星的名字是: \(plName.name)")

let noplName = Planet()

print("沒(méi)有這個(gè)名字的行星: \(noplName.name)")

class planets: Planet {

var count: Int

init(name: String, count: Int) {

self.count = count

super.init(name: name)

}

override convenience init(name: String) {

self.init(name: name, count: 1)

}

}

以上程序執(zhí)行輸出結(jié)果為:

行星的名字是: Mercury

沒(méi)有這個(gè)名字的行星: [No Planets]

可失敗構(gòu)造器 init!

通常來(lái)說(shuō)我們通過(guò)在init關(guān)鍵字后添加問(wèn)號(hào)的方式(init?)來(lái)定義一個(gè)可失敗構(gòu)造器,但你也可以使用通過(guò)在init后面添加驚嘆號(hào)的方式來(lái)定義一個(gè)可失敗構(gòu)造器(init!)。實(shí)例如下:

struct StudRecord {

let stname: String

init!(stname: String) {

if stname.isEmpty {return nil }

self.stname = stname

}

}

let stmark = StudRecord(stname: "Runoob")

if let name = stmark {

print("指定了學(xué)生名")

}

let blankname = StudRecord(stname: "")

if blankname == nil {

print("學(xué)生名為空")

}

以上程序執(zhí)行輸出結(jié)果為:

指定了學(xué)生名

學(xué)生名為空

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書(shū)系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌,老刑警劉巖,帶你破解...
    沈念sama閱讀 229,963評(píng)論 6 542
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場(chǎng)離奇詭異,居然都是意外死亡,警方通過(guò)查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 99,348評(píng)論 3 429
  • 文/潘曉璐 我一進(jìn)店門(mén),熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái),“玉大人,你說(shuō)我怎么就攤上這事?!?“怎么了?”我有些...
    開(kāi)封第一講書(shū)人閱讀 178,083評(píng)論 0 383
  • 文/不壞的土叔 我叫張陵,是天一觀的道長(zhǎng)。 經(jīng)常有香客問(wèn)我,道長(zhǎng),這世上最難降的妖魔是什么? 我笑而不...
    開(kāi)封第一講書(shū)人閱讀 63,706評(píng)論 1 317
  • 正文 為了忘掉前任,我火速辦了婚禮,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘。我一直安慰自己,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 72,442評(píng)論 6 412
  • 文/花漫 我一把揭開(kāi)白布。 她就那樣靜靜地躺著,像睡著了一般。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上,一...
    開(kāi)封第一講書(shū)人閱讀 55,802評(píng)論 1 328
  • 那天,我揣著相機(jī)與錄音,去河邊找鬼。 笑死,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播,決...
    沈念sama閱讀 43,795評(píng)論 3 446
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼!你這毒婦竟也來(lái)了?” 一聲冷哼從身側(cè)響起,我...
    開(kāi)封第一講書(shū)人閱讀 42,983評(píng)論 0 290
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎,沒(méi)想到半個(gè)月后,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 49,542評(píng)論 1 335
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 41,287評(píng)論 3 358
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 43,486評(píng)論 1 374
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情,我是刑警寧澤,帶...
    沈念sama閱讀 39,030評(píng)論 5 363
  • 正文 年R本政府宣布,位于F島的核電站,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 44,710評(píng)論 3 348
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧,春花似錦、人聲如沸。這莊子的主人今日做“春日...
    開(kāi)封第一講書(shū)人閱讀 35,116評(píng)論 0 28
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)。三九已至,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背。 一陣腳步聲響...
    開(kāi)封第一講書(shū)人閱讀 36,412評(píng)論 1 294
  • 我被黑心中介騙來(lái)泰國(guó)打工, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 52,224評(píng)論 3 398
  • 正文 我出身青樓,卻偏偏與公主長(zhǎng)得像,于是被迫代替她去往敵國(guó)和親。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 48,462評(píng)論 2 378

推薦閱讀更多精彩內(nèi)容

  • ?構(gòu)造過(guò)程是使用類(lèi)、結(jié)構(gòu)體或枚舉類(lèi)型一個(gè)實(shí)例的準(zhǔn)備過(guò)程。在新實(shí)例可用前必須執(zhí)行這個(gè)過(guò)程,具體操作包括設(shè)置實(shí)例中每個(gè)...
    EndEvent閱讀 647評(píng)論 0 3
  • importUIKit classViewController:UITabBarController{ enumD...
    明哥_Young閱讀 3,858評(píng)論 1 10
  • 構(gòu)造過(guò)程是使用類(lèi)、結(jié)構(gòu)體或枚舉類(lèi)型的實(shí)例之前的準(zhǔn)備過(guò)程。在新實(shí)例可用前必須執(zhí)行這個(gè)過(guò)程,具體操作包括設(shè)置實(shí)例中每個(gè)...
    GY1994閱讀 205評(píng)論 0 0
  • Swift 構(gòu)造過(guò)程 step 1. 首先從Objective-C的構(gòu)造開(kāi)始說(shuō)起 在Objective-C的構(gòu)造函...
    小梁同學(xué)閱讀 1,671評(píng)論 0 2
  • 本文對(duì)Swift51.com的swift 3.0教程進(jìn)行了摘錄 構(gòu)造過(guò)程 構(gòu)造過(guò)程是使用類(lèi)、結(jié)構(gòu)體或枚舉類(lèi)型的實(shí)例...
    動(dòng)物園園長(zhǎng)熊熊醬閱讀 365評(píng)論 0 0