這里的教程為Swift官方教程中文版。

聲明(Declarations)

聲明(declaration) 用以向程序里引入新的名字或者結(jié)構(gòu)。舉例來說,可以使用聲明來引入函數(shù)和方法,變量和常量,或者定義新的具有命名的枚舉、結(jié)構(gòu)體、類和協(xié)議類型。還可以使用聲明來擴(kuò)展一個(gè)既有的具有命名的類型的行為,或者在程序里引入在其它地方聲明的符號(hào)。

在 Swift 中,大多數(shù)聲明在某種意義上講也是定義,因?yàn)樗鼈冊(cè)诼暶鲿r(shí)往往伴隨著實(shí)現(xiàn)或初始化。由于協(xié)議并不提供實(shí)現(xiàn),大多數(shù)協(xié)議成員僅僅只是聲明而已。為了方便起見,也是因?yàn)檫@些區(qū)別在 Swift 中并不是很重要,“聲明”這個(gè)術(shù)語同時(shí)包含了聲明和定義兩種含義。

聲明語法

declaration

聲明導(dǎo)入聲明

聲明常量聲明

聲明變量聲明

聲明類型別名聲明

聲明函數(shù)聲明

聲明枚舉聲明

聲明結(jié)構(gòu)體聲明

聲明類聲明

聲明協(xié)議聲明

聲明構(gòu)造器聲明

聲明析構(gòu)器聲明

聲明擴(kuò)展聲明

聲明下標(biāo)聲明

聲明運(yùn)算符聲明

declarations

多條聲明聲明 多條聲明可選

頂級(jí)代碼

Swift 的源文件中的頂級(jí)代碼(top-level code)由零個(gè)或多個(gè)語句、聲明和表達(dá)式組成。默認(rèn)情況下,在一個(gè)源文件的頂層聲明的變量,常量和其他具有命名的聲明可以被同模塊中的每一個(gè)源文件中的代碼訪問??梢允褂靡粋€(gè)訪問級(jí)別修飾符來標(biāo)記聲明來覆蓋這種默認(rèn)行為,請(qǐng)參閱 訪問控制級(jí)別。

頂級(jí)聲明語法

頂級(jí)聲明多條語句可選

代碼塊

代碼塊(code block) 可以將一些聲明和控制結(jié)構(gòu)體組織在一起。它有如下的形式:

{
    語句
}

代碼塊中的“語句”包括聲明、表達(dá)式和各種其他類型的語句,它們按照在源碼中的出現(xiàn)順序被依次執(zhí)行。

代碼塊語法

code-block

代碼塊{ 多條語句可選 }

導(dǎo)入聲明

導(dǎo)入聲明(import declaration) 讓你可以使用在其他文件中聲明的內(nèi)容。導(dǎo)入語句的基本形式是導(dǎo)入整個(gè)模塊,它由 import 關(guān)鍵字和緊隨其后的模塊名組成:

import 模塊

可以對(duì)導(dǎo)入操作提供更細(xì)致的控制,如指定一個(gè)特殊的子模塊或者指定一個(gè)模塊或子模塊中的某個(gè)聲明。提供了這些限制后,在當(dāng)前作用域中,只有被導(dǎo)入的符號(hào)是可用的,而不是整個(gè)模塊中的所有聲明。

import 導(dǎo)入類型 模塊.符號(hào)名
import 模塊.子模塊

grammer-of-an-import-declaration

導(dǎo)入聲明語法

import-declaration

導(dǎo)入聲明特性列表可選 import 導(dǎo)入類型可選 導(dǎo)入路徑

import-kind

導(dǎo)入類型typealias | struct | class | enum | protocol | let | var | func

import-path

導(dǎo)入路徑導(dǎo)入路徑標(biāo)識(shí)符 | 導(dǎo)入路徑標(biāo)識(shí)符 . 導(dǎo)入路徑

import-path-identifier

導(dǎo)入路徑標(biāo)識(shí)符標(biāo)識(shí)符 | 運(yùn)算符

常量聲明

常量聲明(constant declaration) 可以在程序中引入一個(gè)具有命名的常量。常量以關(guān)鍵字 let 來聲明,遵循如下格式:

let 常量名稱: 類型 = 表達(dá)式

常量聲明在“常量名稱”和用于初始化的“表達(dá)式”的值之間定義了一種不可變的綁定關(guān)系;當(dāng)常量的值被設(shè)定之后,它就無法被更改。這意味著,如果常量以類對(duì)象來初始化,對(duì)象本身的內(nèi)容是可以改變的,但是常量和該對(duì)象之間的綁定關(guān)系是不能改變的。

當(dāng)一個(gè)常量被聲明為全局常量時(shí),它必須擁有一個(gè)初始值。在函數(shù)或者方法中聲明一個(gè)常量時(shí),它并不需要擁有一個(gè)初始值,只需要保證在第一次對(duì)其進(jìn)行讀操作之前為其設(shè)置一個(gè)值。在類或者結(jié)構(gòu)體中聲明一個(gè)常量時(shí),它將作為常量屬性(constant property)。常量聲明不能是計(jì)算型屬性,因此也沒有存取方法。

如果常量名稱是元組形式,元組中每一項(xiàng)的名稱都會(huì)和初始化表達(dá)式中對(duì)應(yīng)的值進(jìn)行綁定。

let (firstNumber, secondNumber) = (10, 42)

在上例中,firstNumber 是一個(gè)值為 10 的常量,secnodeName 是一個(gè)值為 42 的常量。所有常量都可以獨(dú)立地使用:

print("The first number is \(firstNumber).")
// 打印“The first number is 10.”
print("The second number is \(secondNumber).")
// 打印“The second number is 42.”

當(dāng)常量名稱的類型(: 類型)可以被推斷出時(shí),類型注解在常量聲明中是可選的,正如 類型推斷 中所描述的。

聲明一個(gè)常量類型屬性要使用 static 聲明修飾符。類的常量類型屬性總是隱式地被標(biāo)記為 final ;你無法用 classfinal 聲明修飾符實(shí)現(xiàn)允許或禁止被子類重寫的目的。類型屬性在 類型屬性 中有介紹。

如果還想獲得更多關(guān)于常量的信息或者想在使用中獲得幫助,請(qǐng)參閱 常量和變量存儲(chǔ)屬性。

grammer-of-a-constant-declaration

常量聲明語法

constant-declaration

常量聲明特性列表可選 聲明修飾符列表可選 let 模式構(gòu)造器列表

pattern-initializer-list

模式構(gòu)造器列表模式構(gòu)造器 | 模式構(gòu)造器 , 模式構(gòu)造器列表

pattern-initializer

模式構(gòu)造器模式 構(gòu)造器可選

initializer

構(gòu)造器= 表達(dá)式

變量聲明

變量聲明(variable declaration) 可以在程序中引入一個(gè)具有命名的變量,它以關(guān)鍵字 var 來聲明。

變量聲明有幾種不同的形式,可以聲明不同種類的命名值和可變值,如存儲(chǔ)型和計(jì)算型變量和屬性,屬性觀察器,以及靜態(tài)變量屬性。所使用的聲明形式取決于變量聲明的適用范圍和打算聲明的變量類型。

注意

也可以在協(xié)議聲明中聲明屬性,詳情請(qǐng)參閱 協(xié)議屬性聲明。

可以在子類中重寫繼承來的變量屬性,使用 override 聲明修飾符標(biāo)記屬性的聲明即可,詳情請(qǐng)參閱 重寫。

存儲(chǔ)型變量和存儲(chǔ)型變量屬性

使用如下形式聲明一個(gè)存儲(chǔ)型變量或存儲(chǔ)型變量屬性:

var 變量名稱: 類型 = 表達(dá)式

可以在全局范圍,函數(shù)內(nèi)部,或者在類和結(jié)構(gòu)體的聲明中使用這種形式來聲明一個(gè)變量。當(dāng)變量以這種形式在全局范圍或者函數(shù)內(nèi)部被聲明時(shí),它代表一個(gè)存儲(chǔ)型變量。當(dāng)它在類或者結(jié)構(gòu)體中被聲明時(shí),它代表一個(gè)存儲(chǔ)型變量屬性(stored variable property)

用于初始化的表達(dá)式不可以在協(xié)議的聲明中出現(xiàn),在其他情況下,該表達(dá)式是可選的。如果沒有初始化表達(dá)式,那么變量聲明必須包含類型注解(: type)。

如同常量聲明,如果變量名稱是元組形式,元組中每一項(xiàng)的名稱都會(huì)和初始化表達(dá)式中對(duì)應(yīng)的值進(jìn)行綁定。

正如名字所示,存儲(chǔ)型變量和存儲(chǔ)型變量屬性的值會(huì)存儲(chǔ)在內(nèi)存中。

計(jì)算型變量和計(jì)算型屬性

使用如下形式聲明一個(gè)計(jì)算型變量或計(jì)算型屬性:

var 變量名稱: 類型 {
    get {
        語句
    }
    set(setter 名稱) {
        語句
    }
}

可以在全局范圍、函數(shù)內(nèi)部,以及類、結(jié)構(gòu)體、枚舉、擴(kuò)展的聲明中使用這種形式的聲明。當(dāng)變量以這種形式在全局范圍或者函數(shù)內(nèi)部被聲明時(shí),它表示一個(gè)計(jì)算型變量。當(dāng)它在類、結(jié)構(gòu)體、枚舉、擴(kuò)展聲明的上下文中被聲明時(shí),它表示一個(gè)計(jì)算型屬性(computed property)。

getter 用來讀取變量值,setter 用來寫入變量值。setter 子句是可選的,getter 子句是必須的。不過也可以將這些子句都省略,直接返回請(qǐng)求的值,正如在 只讀計(jì)算型屬性 中描述的那樣。但是如果提供了一個(gè) setter 子句,就必須也提供一個(gè) getter 子句。

setter 的圓括號(hào)以及 setter 名稱是可選的。如果提供了 setter 名稱,它就會(huì)作為 setter 的參數(shù)名稱使用。如果不提供 setter 名稱,setter 的參數(shù)的默認(rèn)名稱為 newValue,正如在 便捷 setter 聲明 中描述的那樣。

與存儲(chǔ)型變量和存儲(chǔ)型屬性不同,計(jì)算型變量和計(jì)算型屬性的值不存儲(chǔ)在內(nèi)存中。

要獲得更多關(guān)于計(jì)算型屬性的信息和例子,請(qǐng)參閱 計(jì)算型屬性。

存儲(chǔ)型變量和屬性的觀察器

可以在聲明存儲(chǔ)型變量或?qū)傩詴r(shí)提供 willSetdidSet 觀察器。一個(gè)包含觀察器的存儲(chǔ)型變量或?qū)傩砸匀缦滦问铰暶鳎?/p>

var 變量名稱: 類型 = 表達(dá)式 {
    willSet(setter 名稱) {
        語句
    }
    didSet(setter 名稱) {
        語句
    }
}

可以在全局范圍、函數(shù)內(nèi)部,或者類、結(jié)構(gòu)體的聲明中使用這種形式的聲明。當(dāng)變量以這種形式在全局范圍或者函數(shù)內(nèi)部被聲明時(shí),觀察器表示一個(gè)存儲(chǔ)型變量觀察器。當(dāng)它在類和結(jié)構(gòu)體的聲明中被聲明時(shí),觀察器表示一個(gè)屬性觀察器。

可以為任何存儲(chǔ)型屬性添加觀察器。也可以通過重寫父類屬性的方式為任何繼承的屬性(無論是存儲(chǔ)型還是計(jì)算型的)添加觀察器 ,正如 重寫屬性觀察器 中所描述的。

用于初始化的表達(dá)式在類或者結(jié)構(gòu)的聲明中是可選的,但是在其他聲明中則是必須的。如果可以從初始化表達(dá)式中推斷出類型信息,那么可以不提供類型注解。

當(dāng)變量或?qū)傩缘闹当桓淖儠r(shí),willSetdidSet 觀察器提供了一種觀察方法。觀察器會(huì)在變量的值被改變時(shí)調(diào)用,但不會(huì)在初始化時(shí)被調(diào)用。

willSet 觀察器只在變量或?qū)傩缘闹当桓淖冎罢{(diào)用。新的值作為一個(gè)常量傳入 willSet 觀察器,因此不可以在 willSet 中改變它。didSet 觀察器在變量或?qū)傩缘闹当桓淖兒罅⒓凑{(diào)用。和 willSet 觀察器相反,為了方便獲取舊值,舊值會(huì)傳入 didSet 觀察器。這意味著,如果在變量或?qū)傩缘?didiset 觀察器中設(shè)置值,設(shè)置的新值會(huì)取代剛剛在 willSet 觀察器中傳入的那個(gè)值。

willSetdidSet 中,圓括號(hào)以及其中的 setter 名稱是可選的。如果提供了一個(gè) setter 名稱,它就會(huì)作為 willSetdidSet 的參數(shù)被使用。如果不提供 setter 名稱,willSet 觀察器的默認(rèn)參數(shù)名為 newValue,didSet 觀察器的默認(rèn)參數(shù)名為 oldValue。

提供了 willSet 時(shí),didSet 是可選的。同樣的,提供了 didSet 時(shí),willSet 則是可選的。

要獲得更多信息以及查看如何使用屬性觀察器的例子,請(qǐng)參閱 屬性觀察器。

類型變量屬性

要聲明一個(gè)類型變量屬性,用 static 聲明修飾符標(biāo)記該聲明。類可以改用 class 聲明修飾符標(biāo)記類的類型計(jì)算型屬性從而允許子類重寫超類的實(shí)現(xiàn)。類型屬性在 類型屬性 章節(jié)有詳細(xì)討論。

grammer-of-a-variable-declaration

變量聲明語法

variable-declaration

變量聲明變量聲明頭 模式構(gòu)造器列表

變量聲明變量聲明頭 變量名稱 類型注解 代碼塊

變量聲明變量聲明頭 變量名稱 類型注解 getter-setter 代碼塊

變量聲明變量聲明頭 變量名稱 類型注解 getter-setter 關(guān)鍵字代碼塊

變量聲明變量聲明頭 變量名稱 構(gòu)造器 willSet-didSet 代碼塊

變量聲明變量聲明頭 變量名稱 類型注解 構(gòu)造器可選 willSet-didSet 代碼塊

variable-declaration-head

變量聲明頭特性列表可選 聲明修飾符列表可選 var

variable-name

變量名稱標(biāo)識(shí)符

getter-setter-block

getter-setter 代碼塊代碼塊

getter-setter 代碼塊{ getter 子句 setter 子句可選 }

getter-setter 代碼塊{ setter 子句 getter 子句 }

getter-clause

getter 子句特性列表可選 get 代碼塊

setter-clause

setter 子句特性列表可選 set setter 名稱可選 代碼塊

setter-name

setter 名稱( 標(biāo)識(shí)符 )

getter-setter-keyword-block

getter-setter 關(guān)鍵字代碼塊{ getter 關(guān)鍵字子句 setter 關(guān)鍵字子句可選 }

getter-setter 關(guān)鍵字代碼塊{ setter 關(guān)鍵字子句 getter 關(guān)鍵字子句 }

getter-keyword-clause

getter 關(guān)鍵字子句特性列表可選 get

setter-keyword-clause

setter 關(guān)鍵字子句特性列表可選 set

willSet-didSet-block

willSet-didSet 代碼塊{ willSet 子句 didSet 子句可選 }

willSet-didSet 代碼塊{ didSet 子句 willSet 子句可選 }

willSet-clause

willSet 子句特性列表可選 willSet setter 名稱可選 代碼塊

didSet-clause

didSet 子句特性列表可選 didSet setter 名稱可選 代碼塊

類型別名聲明

類型別名(type alias) 聲明可以在程序中為一個(gè)既有類型聲明一個(gè)別名。類型別名聲明語句使用關(guān)鍵字 typealias 聲明,遵循如下的形式:

typealias 類型別名 = 現(xiàn)存類型

當(dāng)聲明一個(gè)類型的別名后,可以在程序的任何地方使用“別名”來代替現(xiàn)有類型?,F(xiàn)有類型可以是具有命名的類型或者混合類型。類型別名不產(chǎn)生新的類型,它只是使用別名來引用現(xiàn)有類型。

類型別名聲明可以通過泛型參數(shù)來給一個(gè)現(xiàn)有泛型類型提供名稱。類型別名為現(xiàn)有類型的一部分或者全部泛型參數(shù)提供具體類型。例如:

typealias StringDictionary<Value> = Dictionary<String, Value>

// 下列兩個(gè)字典擁有同樣的類型
var dictionary1: StringDictionary<Int> = [:]
var dictionary2: Dictionary<String, Int> = [:]

當(dāng)一個(gè)類型別名帶著泛型參數(shù)一起被聲明時(shí),這些參數(shù)的約束必須與現(xiàn)有參數(shù)的約束完全匹配。例如:

typealias DictionaryOfInts<Key: Hashable> = Dictionary<Key, Int>

因?yàn)轭愋蛣e名可以和現(xiàn)有類型相互交換使用,類型別名不可以引入額外的類型約束。

如果在聲明處省略所有泛型參數(shù),一個(gè)類型別名可以傳遞已有類型的所有泛型參數(shù)。例如,此處聲明的 Diccionario 類型別名擁有和 Dictionary 同樣的約束和泛型參數(shù)。

typealias Diccionario = Dictionary

在協(xié)議聲明中,類型別名可以為那些經(jīng)常使用的類型提供一個(gè)更短更方便的名稱,例如:

protocol Sequence {
    associatedtype Iterator: IteratorProtocol
    typealias Element = Iterator.Element
}

func sum<T: Sequence>(_ sequence: T) -> Int where T.Element == Int {
    // ...
}

假如沒有類型別名,sum 函數(shù)將必須引用關(guān)聯(lián)類型通過 T.Iterator.Element 的形式來替代 T.Element。

另請(qǐng)參閱 協(xié)議關(guān)聯(lián)類型聲明

grammer-of-a-type-alias-declaration

類型別名聲明語法

typealias-declaration

類型別名聲明特性列表可選 訪問級(jí)別修飾符可選 typealias 類型別名名稱 類型別子句 類型別名賦值

typealias-name

類型別名名稱標(biāo)識(shí)符

typealias-assignment

類型別名賦值= 類型

函數(shù)聲明

使用函數(shù)聲明(function declaration) 在程序中引入新的函數(shù)或者方法。在類、結(jié)構(gòu)體、枚舉,或者協(xié)議中聲明的函數(shù)會(huì)作為方法。函數(shù)聲明使用關(guān)鍵字 func,遵循如下的形式:

func 函數(shù)名稱(參數(shù)列表) -> 返回類型 {
    語句
}

如果函數(shù)返回 Void 類型,返回類型可以省略,如下所示:

func 函數(shù)名稱(參數(shù)列表) {
    語句
}

每個(gè)參數(shù)的類型都要標(biāo)明,因?yàn)樗鼈儾荒鼙煌茢喑鰜?。如果您在某個(gè)參數(shù)類型前面加上了 inout,那么這個(gè)參數(shù)就可以在這個(gè)函數(shù)作用域當(dāng)中被修改。更多關(guān)于 inout 參數(shù)的討論,請(qǐng)參閱 輸入輸出參數(shù)。

函數(shù)聲明中語句只包含一個(gè)表達(dá)式,可以理解為返回該表達(dá)式的值。

函數(shù)可以使用元組類型作為返回類型來返回多個(gè)值。

函數(shù)定義可以出現(xiàn)在另一個(gè)函數(shù)聲明內(nèi)。這種函數(shù)被稱作嵌套函數(shù)(nested function)。

大多數(shù)時(shí)候,嵌套函數(shù)都是可逃逸的函數(shù)。僅當(dāng)一個(gè)嵌套函數(shù)捕獲了某個(gè)確保了永不逃逸的值——例如一個(gè)輸入輸出參數(shù)——或者傳入一個(gè)非逃逸函數(shù)參數(shù)的時(shí)候,這個(gè)嵌套函數(shù)才是非逃逸的。

更多關(guān)于嵌套函數(shù)的討論,請(qǐng)參閱 嵌套函數(shù)

參數(shù)名

函數(shù)的參數(shù)列表由一個(gè)或多個(gè)函數(shù)參數(shù)組成,參數(shù)間以逗號(hào)分隔。函數(shù)調(diào)用時(shí)的參數(shù)順序必須和函數(shù)聲明時(shí)的參數(shù)順序一致。最簡單的參數(shù)列表有著如下的形式:

參數(shù)名稱: 參數(shù)類型

每個(gè)參數(shù)有一個(gè)參數(shù)名稱,這個(gè)名稱與實(shí)參標(biāo)簽一樣都可以在函數(shù)體內(nèi)被使用。默認(rèn)情況下,參數(shù)名也會(huì)被作為實(shí)參標(biāo)簽來使用。例如:

func f(x: Int, y: Int) -> Int { return x + y }
f(x: 1, y: 2) // 參數(shù) x 和 y 都有標(biāo)簽

可以按照如下兩種形式之一,重寫參數(shù)名稱的默認(rèn)行為:

實(shí)參標(biāo)簽 參數(shù)名稱: 參數(shù)類型 _ 參數(shù)名稱: 參數(shù)類型

在參數(shù)名稱前的名稱會(huì)作為這個(gè)參數(shù)的顯式實(shí)參標(biāo)簽,它可以和參數(shù)名稱不同。在函數(shù)或方法調(diào)用時(shí),相對(duì)應(yīng)的參數(shù)必須使用這個(gè)實(shí)參標(biāo)簽。

參數(shù)名稱前的下劃線(_)可以去除參數(shù)的實(shí)參標(biāo)簽。在函數(shù)或方法調(diào)用時(shí),相對(duì)應(yīng)的參數(shù)必須去除標(biāo)簽。

func repeatGreeting(_ greeting: String, count n: Int) { /* Greet n times */ }
repeatGreeting("Hello, world!", count: 2) //  count 有標(biāo)簽, greeting 沒有

輸入輸出參數(shù)

輸入輸出參數(shù)被傳遞時(shí)遵循如下規(guī)則:

  1. 函數(shù)調(diào)用時(shí),參數(shù)的值被拷貝。
  2. 函數(shù)體內(nèi)部,拷貝后的值被修改。
  3. 函數(shù)返回后,拷貝后的值被賦值給原參數(shù)。

這種行為被稱為拷入拷出(copy-in copy-out)值結(jié)果調(diào)用(call by value result)。例如,當(dāng)一個(gè)計(jì)算型屬性或者一個(gè)具有屬性觀察器的屬性被用作函數(shù)的輸入輸出參數(shù)時(shí),其 getter 會(huì)在函數(shù)調(diào)用時(shí)被調(diào)用,而其 setter 會(huì)在函數(shù)返回時(shí)被調(diào)用。

作為一種優(yōu)化手段,當(dāng)參數(shù)值存儲(chǔ)在內(nèi)存中的物理地址時(shí),在函數(shù)體內(nèi)部和外部均會(huì)使用同一內(nèi)存位置。這種優(yōu)化行為被稱為引用調(diào)用(call by reference),它滿足了拷入拷出模式的所有要求,且消除了復(fù)制帶來的開銷。在代碼中,要規(guī)范使用拷入拷出模式,不要依賴于引用調(diào)用。

不要使用傳遞給輸入輸出參數(shù)的值,即使原始值在當(dāng)前作用域中依然可用。當(dāng)函數(shù)返回時(shí),你對(duì)原始值所做的更改會(huì)被拷貝的值所覆蓋。不要依賴于引用調(diào)用的優(yōu)化機(jī)制來試圖避免這種覆蓋。

不能將同一個(gè)值傳遞給多個(gè)輸入輸出參數(shù),因?yàn)檫@種情況下的拷貝與覆蓋行為的順序是不確定的,因此原始值的最終值也將無法確定。

更多關(guān)于內(nèi)存安全和內(nèi)存獨(dú)占權(quán)的討論,請(qǐng)參閱 內(nèi)存安全。

如果一個(gè)閉包或者嵌套函數(shù)捕獲了一個(gè)輸入輸出參數(shù),那么這個(gè)閉包或者嵌套函數(shù)必須是非逃逸的。如果你需要捕獲一個(gè)輸入輸出參數(shù),但并不對(duì)其進(jìn)行修改或者在其他代碼中觀察其值變化,那么你可以使用捕獲列表來顯式地表明這是個(gè)不可變捕獲。

func someFunction(a: inout Int) -> () -> Int {
    return { [a] in return a + 1 }
}

如果你需要捕獲并修改一個(gè)輸入輸出參數(shù),使用一個(gè)顯式局部拷貝來進(jìn)行修改操作,在一些例如多線程的場景中,這樣做可以確保函數(shù)返回之前所有的修改都已完成。

如果嵌套函數(shù)在外層函數(shù)返回后才調(diào)用,嵌套函數(shù)對(duì)輸入輸出參數(shù)造成的任何改變將不會(huì)影響到原始值。例如:

func multithreadedFunction(queue: DispatchQueue, x: inout Int) {
    // 創(chuàng)建一個(gè)局部拷貝并在適當(dāng)時(shí)候手動(dòng)拷貝回去
    var localX = x
    defer { x = localX }

    // 并行地操作 localX,然后在函數(shù)返回前一直等待
    queue.async { someMutatingOperation(&localX) }
    queue.sync {}
}

關(guān)于輸入輸出參數(shù)的詳細(xì)討論,請(qǐng)參閱 輸入輸出參數(shù)。

特殊參數(shù)

參數(shù)可以被忽略,數(shù)量可以不固定,還可以為其提供默認(rèn)值,使用形式如下:

_ : 參數(shù)類型
參數(shù)名稱: 參數(shù)類型...
參數(shù)名稱: 參數(shù)類型 = 默認(rèn)參數(shù)值

以下劃線(_)命名的參數(shù)會(huì)被顯式忽略,無法在函數(shù)內(nèi)使用。

一個(gè)參數(shù)的基本類型名稱如果緊跟著三個(gè)點(diǎn)(...),會(huì)被視為可變參數(shù)。一個(gè)函數(shù)至多可以擁有一個(gè)可變參數(shù),且必須是最后一個(gè)參數(shù)。可變參數(shù)會(huì)作為包含該參數(shù)類型元素的數(shù)組處理。舉例來講,可變參數(shù) Int... 會(huì)作為 [Int] 來處理。關(guān)于使用可變參數(shù)的例子,請(qǐng)參閱 可變參數(shù)。

如果在參數(shù)類型后面有一個(gè)以等號(hào)(=)連接的表達(dá)式,該參數(shù)會(huì)擁有默認(rèn)值,即給定表達(dá)式的值。當(dāng)函數(shù)被調(diào)用時(shí),給定的表達(dá)式會(huì)被求值。如果參數(shù)在函數(shù)調(diào)用時(shí)被省略了,就會(huì)使用其默認(rèn)值。

func f(x: Int = 42) -> Int { return x }

f()     // 有效,使用默認(rèn)值
f(7)    // 有效,提供了值
f(x: 7) // 無效,該參數(shù)沒有外部名稱

特殊方法

枚舉或結(jié)構(gòu)體的方法如果會(huì)修改 self,則必須以 mutating 聲明修飾符標(biāo)記。

子類重寫超類中的方法必須以 override 聲明修飾符標(biāo)記。重寫方法時(shí)不使用 override 修飾符,或者被 override 修飾符修飾的方法并未對(duì)超類方法構(gòu)成重寫,都會(huì)導(dǎo)致編譯錯(cuò)誤。

枚舉或者結(jié)構(gòu)體中的類型方法,要以 static 聲明修飾符標(biāo)記,而對(duì)于類中的類型方法,除了使用 static,還可使用 class 聲明修飾符標(biāo)記。類中使用 class 聲明修飾的方法可以被子類實(shí)現(xiàn)重寫;類中使用 class finalstatic 聲明修飾的方法不可被重寫。

拋出錯(cuò)誤的函數(shù)和方法

可以拋出錯(cuò)誤的函數(shù)或方法必須使用 throws 關(guān)鍵字標(biāo)記。這類函數(shù)和方法被稱為拋出函數(shù)和拋出方法。它們有著下面的形式:

func 函數(shù)名稱(參數(shù)列表) throws -> 返回類型 {
    語句
}

拋出函數(shù)或拋出方法的調(diào)用必須包裹在 try 或者 try! 表達(dá)式中(也就是說,在作用域內(nèi)使用 try 或者 try! 運(yùn)算符)。

throws 關(guān)鍵字是函數(shù)的類型的一部分,非拋出函數(shù)是拋出函數(shù)的子類型。所以,可以在使用拋出函數(shù)的地方使用非拋出函數(shù)。

不能僅基于函數(shù)能否拋出錯(cuò)誤來進(jìn)行函數(shù)重寫。也就是說,可以基于函數(shù)的函數(shù)類型的參數(shù)能否拋出錯(cuò)誤來進(jìn)行函數(shù)重寫。

拋出方法不能重寫非拋出方法,而且拋出方法不能滿足協(xié)議對(duì)于非拋出方法的要求。也就是說,非拋出方法可以重寫拋出方法,而且非拋出方法可以滿足協(xié)議對(duì)于拋出方法的要求。

重拋錯(cuò)誤的函數(shù)和方法

函數(shù)或方法可以使用 rethrows 關(guān)鍵字來聲明,從而表明僅當(dāng)該函數(shù)或方法的一個(gè)函數(shù)類型的參數(shù)拋出錯(cuò)誤時(shí),該函數(shù)或方法才拋出錯(cuò)誤。這類函數(shù)和方法被稱為重拋函數(shù)和重拋方法。重新拋出錯(cuò)誤的函數(shù)或方法必須至少有一個(gè)參數(shù)的類型為拋出函數(shù)。

func someFunction(callback: () throws -> Void) rethrows {
    try callback()
}

重拋函數(shù)或者方法不能夠從自身直接拋出任何錯(cuò)誤,這意味著它不能夠包含 throw 語句。它只能夠傳遞作為參數(shù)的拋出函數(shù)所拋出的錯(cuò)誤。例如,在 do-catch 代碼塊中調(diào)用拋出函數(shù),并在 catch 子句中拋出其它錯(cuò)誤都是不允許的。

func alwaysThrows() throws {
    throw SomeError.error
}
func someFunction(callback: () throws -> Void) rethrows {
    do {
        try callback()
        try alwaysThrows()  // 非法, alwaysThrows() 不是一個(gè)拋出函數(shù)類型的參數(shù)
    } catch {
        throw AnotherError.error
    }
}

拋出方法不能重寫重拋方法,而且拋出方法不能滿足協(xié)議對(duì)于重拋方法的要求。也就是說,重拋方法可以重寫拋出方法,而且重拋方法可以滿足協(xié)議對(duì)于拋出方法的要求。

永不返回的函數(shù)

Swift 定義了 Never 類型,它表示函數(shù)或者方法不會(huì)返回給它的調(diào)用者。Never 返回類型的函數(shù)或方法可以稱為不歸,不歸函數(shù)、方法要么引發(fā)不可恢復(fù)的錯(cuò)誤,要么永遠(yuǎn)不停地運(yùn)作,這會(huì)使調(diào)用后本應(yīng)執(zhí)行得代碼就不再執(zhí)行了。但即使是不歸函數(shù)、方法,拋錯(cuò)函數(shù)和重拋出函數(shù)也可以將程序控制轉(zhuǎn)移到合適的 catch 代碼塊。

不歸函數(shù)、方法可以在 guard 語句的 else 字句中調(diào)用,具體討論在 Guard 語句。

你可以重寫一個(gè)不歸方法,但是新的方法必須保持原有的返回類型和沒有返回的行為。

grammer-of-a-function-declaration

函數(shù)聲明語法

function-declaration

函數(shù)聲明函數(shù)頭 函數(shù)名 泛型形參子句可選 函數(shù)簽名 泛型 where 子句 函數(shù)體可選

function-head

函數(shù)頭特性列表可選 聲明修飾符列表可選 func

function-name

函數(shù)名標(biāo)識(shí)符 | 運(yùn)算符

function-signature

函數(shù)簽名參數(shù)子句列表 throws可選 函數(shù)結(jié)果可選

函數(shù)簽名參數(shù)子句列表 rethrows 函數(shù)結(jié)果可選

function-result

函數(shù)結(jié)果-> 特性列表可選 類型

function-body

函數(shù)體代碼塊

parameter-clause

參數(shù)子句( ) | ( 參數(shù)列表 )

parameter-list

參數(shù)列表參數(shù) | 參數(shù) , 參數(shù)列表

parameter

參數(shù)外部參數(shù)名可選 內(nèi)部參數(shù)名 類型注解 默認(rèn)參數(shù)子句可選

參數(shù)外部參數(shù)名可選 內(nèi)部參數(shù)名 類型注解

參數(shù)外部參數(shù)名可選 內(nèi)部參數(shù)名 類型注解 ...

external-parameter-name

外部參數(shù)名標(biāo)識(shí)符 | -

local-parameter-name

內(nèi)部參數(shù)名標(biāo)識(shí)符 | -

default-argument-clause

默認(rèn)參數(shù)子句= 表達(dá)式

枚舉聲明

在程序中使用枚舉聲明(enumeration declaration) 來引入一個(gè)枚舉類型。

枚舉聲明有兩種基本形式,使用關(guān)鍵字 enum 來聲明。枚舉聲明體包含零個(gè)或多個(gè)值,稱為枚舉用例,還可包含任意數(shù)量的聲明,包括計(jì)算型屬性、實(shí)例方法、類型方法、構(gòu)造器、類型別名,甚至其他枚舉、結(jié)構(gòu)體和類。枚舉聲明不能包含析構(gòu)器或者協(xié)議聲明。

枚舉類型可以采納任意數(shù)量的協(xié)議,但是枚舉不能從類、結(jié)構(gòu)體和其他枚舉繼承。

不同于類或者結(jié)構(gòu)體,枚舉類型并不隱式提供默認(rèn)構(gòu)造器,所有構(gòu)造器必須顯式聲明。一個(gè)構(gòu)造器可以委托給枚舉中的其他構(gòu)造器,但是構(gòu)造過程僅當(dāng)構(gòu)造器將一個(gè)枚舉用例賦值給 self 后才算完成。

和結(jié)構(gòu)體類似但是和類不同,枚舉是值類型。枚舉實(shí)例在被賦值到變量或常量時(shí),或者傳遞給函數(shù)作為參數(shù)時(shí)會(huì)被復(fù)制。更多關(guān)于值類型的信息,請(qǐng)參閱 結(jié)構(gòu)體和枚舉是值類型。

可以擴(kuò)展枚舉類型,正如在 擴(kuò)展聲明 中討論的一樣。

任意類型的枚舉用例

如下的形式聲明了一個(gè)包含任意類型枚舉用例的枚舉變量:

enum 枚舉名稱: 采納的協(xié)議 {
    case 枚舉用例1
    case 枚舉用例2(關(guān)聯(lián)值類型)
}

這種形式的枚舉聲明在其他語言中有時(shí)被叫做可識(shí)別聯(lián)合。

在這種形式中,每個(gè)用例塊由關(guān)鍵字 case 開始,后面緊接一個(gè)或多個(gè)以逗號(hào)分隔的枚舉用例。每個(gè)用例名必須是獨(dú)一無二的。每個(gè)用例也可以指定它所存儲(chǔ)的指定類型的值,這些類型在關(guān)聯(lián)值類型的元組中被指定,緊跟用例名之后。

具有關(guān)聯(lián)值的枚舉用例可以像函數(shù)一樣使用,通過指定的關(guān)聯(lián)值創(chuàng)建枚舉實(shí)例。和真正的函數(shù)一樣,你可以獲取枚舉用例的引用,然后在后續(xù)代碼中調(diào)用它。

enum Number {
    case integer(Int)
    case real(Double)
}

// f 的類型為 (Int) -> Number
let f = Number.integer

// 利用 f 把一個(gè)整數(shù)數(shù)組轉(zhuǎn)成 Number 數(shù)組
let evenInts: [Number] = [0, 2, 4, 6].map(f)

要獲得更多關(guān)于具有關(guān)聯(lián)值的枚舉用例的信息和例子,請(qǐng)參閱 關(guān)聯(lián)值。

遞歸枚舉

枚舉類型可以具有遞歸結(jié)構(gòu),就是說,枚舉用例的關(guān)聯(lián)值類型可以是枚舉類型自身。然而,枚舉類型的實(shí)例具有值語義,這意味著它們?cè)趦?nèi)存中有固定布局。為了支持遞歸,編譯器必須插入一個(gè)間接層。

要讓某個(gè)枚舉用例支持遞歸,使用 indirect 聲明修飾符標(biāo)記該用例。

enum Tree<T> {
    case empty
    indirect case node(value: T, left: Tree, right:Tree)
}

要讓一個(gè)枚舉類型的所有用例都支持遞歸,使用 indirect 修飾符標(biāo)記整個(gè)枚舉類型,當(dāng)枚舉有多個(gè)用例且每個(gè)用例都需要使用 indirect 修飾符標(biāo)記的時(shí)候這將非常便利。

indirect 修飾符標(biāo)記的枚舉用例必須有一個(gè)關(guān)聯(lián)值。使用 indirect 修飾符標(biāo)記的枚舉類型可以既包含有關(guān)聯(lián)值的用例,同時(shí)還可包含沒有關(guān)聯(lián)值的用例。但是,它不能再單獨(dú)使用 indirect 修飾符來標(biāo)記某個(gè)用例。

擁有原始值的枚舉用例

以下形式聲明了一種枚舉類型,其中各個(gè)枚舉用例的類型均為同一種基本類型:

enum 枚舉名稱: 原始值類型, 采納的協(xié)議 {
    case 枚舉用例1 = 原始值1
    case 枚舉用例2 = 原始值2
}

在這種形式中,每一個(gè)用例塊由 case 關(guān)鍵字開始,后面緊跟一個(gè)或多個(gè)以逗號(hào)分隔的枚舉用例。和第一種形式的枚舉用例不同,這種形式的枚舉用例包含一個(gè)基礎(chǔ)值,叫做原始值,各個(gè)枚舉用例的原始值的類型必須相同。這些原始值的類型通過原始值類型指定,必須表示一個(gè)整數(shù)、浮點(diǎn)數(shù)、字符串或者字符。原始值類型必須符合 Equatable 協(xié)議和下列字面量轉(zhuǎn)換協(xié)議中的一種:整型字面量需符合 IntergerLiteralConvertible 協(xié)議,浮點(diǎn)型字面量需符合 FloatingPointLiteralConvertible 協(xié)議,包含任意數(shù)量字符的字符串型字面量需符合 StringLiteralConvertible 協(xié)議,僅包含一個(gè)單一字符的字符串型字面量需符合 ExtendedGraphemeClusterLiteralConvertible 協(xié)議。每一個(gè)用例的名字和原始值必須唯一。

如果原始值類型被指定為 Int,則不必為用例顯式地指定原始值,它們會(huì)隱式地被賦值 0、1、2 等。每個(gè)未被賦值的 Int 類型的用例會(huì)被隱式地賦值,其值為上一個(gè)用例的原始值加 1。

enum ExampleEnum: Int {
    case a, b, c = 5, d
}

在上面的例子中,ExampleEnum.A 的原始值是 0,ExampleEnum.B 的原始值是 1。因?yàn)?ExampleEnum.C 的原始值被顯式地設(shè)定為 5,因此 ExampleEnum.D 的原始值會(huì)自動(dòng)增長為 6

如果原始值類型被指定為 String 類型,你不用明確地為用例指定原始值,每個(gè)沒有指定原始值的用例會(huì)隱式地將用例名字作為原始值。

enum GamePlayMode: String {
    case cooperative, individual, competitive
}

在上面這個(gè)例子中,GamePlayMode.cooperative 的原始值是 "cooperative",GamePlayMode.individual 的原始值是 "individual",GamePlayMode.competitive 的原始值是 "competitive"。

枚舉用例具有原始值的枚舉類型隱式地符合定義在 Swift 標(biāo)準(zhǔn)庫中的 RawRepresentable 協(xié)議。所以,它們擁有一個(gè) rawValue 屬性和一個(gè)可失敗構(gòu)造器 init?(rawValue: RawValue)??梢允褂?rawValue 屬性去獲取枚舉用例的原始值,例如 ExampleEnum.b.rawValue。還可以根據(jù)原始值來創(chuàng)建一個(gè)相對(duì)應(yīng)的枚舉用例,只需調(diào)用枚舉的可失敗構(gòu)造器,例如 ExampleEnum(rawValue: 5),這個(gè)可失敗構(gòu)造器返回一個(gè)可選類型的用例。要獲得更多關(guān)于具有原始值的枚舉用例的信息和例子,請(qǐng)參閱 原始值。

訪問枚舉用例

使用點(diǎn)語法(.)來引用枚舉類型的枚舉用例,例如 EnumerationType.enumerationCase。當(dāng)枚舉類型可以由上下文推斷而出時(shí),可以省略它(但是 . 仍然需要),正如 枚舉語法顯式成員表達(dá)式 所述。

可以使用 switch 語句來檢驗(yàn)枚舉用例的值,正如 使用 switch 語句匹配枚舉值 所述。枚舉類型是模式匹配的,依靠 switch 語句 case 塊中的枚舉用例模式,正如 枚舉用例模式 所述。

grammer-of-an-enumeration-declaration

枚舉聲明語法

enum-declaration

枚舉聲明特性列表可選 訪問級(jí)別修飾符可選 聯(lián)合風(fēng)格枚舉

枚舉聲明特性列表可選 訪問級(jí)別修飾符 可選 原始值風(fēng)格枚舉

聯(lián)合風(fēng)格枚舉indirect可選 enum 枚舉名稱 泛型形參子句可選 類型繼承子句可選 { 多個(gè)聯(lián)合風(fēng)格枚舉成員可選 }

union-style-enum-members

多個(gè)聯(lián)合風(fēng)格枚舉成員聯(lián)合風(fēng)格枚舉成員 多個(gè)聯(lián)合風(fēng)格枚舉成員可選

union-style-enum-member

聯(lián)合風(fēng)格枚舉成員聲明 | 聯(lián)合風(fēng)格枚舉用例子句 | 編譯控制流語句

union-style-enum-case-clause

聯(lián)合風(fēng)格枚舉用例子句特性列表可選 indirect可選 case 聯(lián)合風(fēng)格枚舉用例列表

union-style-enum-case-list

聯(lián)合風(fēng)格枚舉用例列表聯(lián)合風(fēng)格枚舉用例 | 聯(lián)合風(fēng)格枚舉用例 , 聯(lián)合風(fēng)格枚舉用例列表

union-style-enum-case

聯(lián)合風(fēng)格枚舉用例枚舉用例名稱 元組類型可選

enum-name

枚舉名稱標(biāo)識(shí)符

enum-case-name

枚舉用例名稱標(biāo)識(shí)符

raw-value-style-enum

原始值風(fēng)格枚舉enum 枚舉名稱 泛型形參子句可選 類型繼承子句 泛型 where 子句 { 多個(gè)原始值風(fēng)格枚舉成員 }

raw-value-style-enum-members

多個(gè)原始值風(fēng)格枚舉成員原始值風(fēng)格枚舉成員 多個(gè)原始值風(fēng)格枚舉成員可選

raw-value-style-enum-member

原始值風(fēng)格枚舉成員聲明 | 原始值風(fēng)格枚舉用例子句 | 編譯控制流語句

raw-value-style-enum-case-clause

原始值風(fēng)格枚舉用例子句特性列表可選 case 原始值風(fēng)格枚舉用例列表

raw-value-style-enum-case-list

原始值風(fēng)格枚舉用例列表原始值風(fēng)格枚舉用例 | 原始值風(fēng)格枚舉用例 , 原始值風(fēng)格枚舉用例列表

raw-value-style-enum-case

原始值風(fēng)格枚舉用例枚舉用例名稱 原始值賦值可選

raw-value-assignment

原始值賦值= 原始值字面量

raw-value-literal

原始值字面量數(shù)字型字面量 | 字符串型字面量 | 布爾型字面量

結(jié)構(gòu)體聲明

使用結(jié)構(gòu)體聲明(structure declaration) 可以在程序中引入一個(gè)結(jié)構(gòu)體類型。結(jié)構(gòu)體聲明使用 struct 關(guān)鍵字,遵循如下的形式:

struct 結(jié)構(gòu)體名稱: 采納的協(xié)議 {
    多條聲明
}

結(jié)構(gòu)體內(nèi)可包含零個(gè)或多個(gè)聲明。這些聲明可以包括存儲(chǔ)型和計(jì)算型屬性、類型屬性、實(shí)例方法、類型方法、構(gòu)造器、下標(biāo)、類型別名,甚至其他結(jié)構(gòu)體、類、和枚舉聲明。結(jié)構(gòu)體聲明不能包含析構(gòu)器或者協(xié)議聲明。關(guān)于結(jié)構(gòu)體的詳細(xì)討論和示例,請(qǐng)參閱 類和結(jié)構(gòu)體。

結(jié)構(gòu)體可以采納任意數(shù)量的協(xié)議,但是不能繼承自類、枚舉或者其他結(jié)構(gòu)體。

有三種方法可以創(chuàng)建一個(gè)已聲明的結(jié)構(gòu)體實(shí)例:

  • 調(diào)用結(jié)構(gòu)體內(nèi)聲明的構(gòu)造器,正如 構(gòu)造器 所述。

  • 如果沒有聲明構(gòu)造器,調(diào)用結(jié)構(gòu)體的成員逐一構(gòu)造器,正如 結(jié)構(gòu)體類型的成員逐一構(gòu)造器 所述。

  • 如果沒有聲明構(gòu)造器,而且結(jié)構(gòu)體的所有屬性都有初始值,調(diào)用結(jié)構(gòu)體的默認(rèn)構(gòu)造器,正如 默認(rèn)構(gòu)造器 所述。

結(jié)構(gòu)體的構(gòu)造過程請(qǐng)參閱 構(gòu)造過程

結(jié)構(gòu)體實(shí)例的屬性可以用點(diǎn)語法(.)來訪問,正如 訪問屬性 所述。

結(jié)構(gòu)體是值類型。結(jié)構(gòu)體的實(shí)例在被賦予變量或常量,或傳遞給函數(shù)作為參數(shù)時(shí)會(huì)被復(fù)制。關(guān)于值類型的更多信息,請(qǐng)參閱 結(jié)構(gòu)體和枚舉是值類型。

可以使用擴(kuò)展聲明來擴(kuò)展結(jié)構(gòu)體類型的行為,請(qǐng)參閱 擴(kuò)展聲明

grammer-of-a-structure-declaration

結(jié)構(gòu)體聲明語法

struct-declaration

結(jié)構(gòu)體聲明特性列表可選 訪問級(jí)別修飾符 可選 struct 結(jié)構(gòu)體名稱 泛型形參子句可選 類型繼承子句可選 泛型 where 子句可選 結(jié)構(gòu)體主體

struct-name

結(jié)構(gòu)體名稱標(biāo)識(shí)符

struct-body

結(jié)構(gòu)體主體{ 多條聲明可選 }

struct-name

結(jié)構(gòu)體多個(gè)成員結(jié)構(gòu)體成員 結(jié)構(gòu)體多個(gè)成員可選

struct-member

結(jié)構(gòu)體成員聲明 | 編譯控制流語句

類聲明

可以在程序中使用類聲明(class declaration) 來引入一個(gè)類。類聲明使用關(guān)鍵字 class,遵循如下的形式:

class 類名: 超類, 采納的協(xié)議 {
    多條聲明
}

類內(nèi)可以包含零個(gè)或多個(gè)聲明。這些聲明可以包括存儲(chǔ)型和計(jì)算型屬性、實(shí)例方法、類型方法、構(gòu)造器、唯一的析構(gòu)器、下標(biāo)、類型別名,甚至其他結(jié)構(gòu)體、類和枚舉聲明。類聲明不能包含協(xié)議聲明。關(guān)于類的詳細(xì)討論和示例,請(qǐng)參閱 類和結(jié)構(gòu)體。

一個(gè)類只能繼承自一個(gè)超類,但是可以采納任意數(shù)量的協(xié)議。超類緊跟在類名和冒號(hào)后面,其后跟著采納的協(xié)議。泛型類可以繼承自其它泛型類和非泛型類,但是非泛型類只能繼承自其它非泛型類。當(dāng)在冒號(hào)后面寫泛型超類的名稱時(shí),必須寫上泛型類的全名,包括它的泛型形參子句。

正如 構(gòu)造器聲明 所討論的,類可以有指定構(gòu)造器和便利構(gòu)造器。類的指定構(gòu)造器必須初始化類中聲明的所有屬性,并且必須在調(diào)用超類構(gòu)造器之前。

類可以重寫屬性、方法、下標(biāo)以及構(gòu)造器。重寫的屬性、方法、下標(biāo)和指定構(gòu)造器必須以 override 聲明修飾符標(biāo)記。

為了要求子類去實(shí)現(xiàn)超類的構(gòu)造器,使用 required 聲明修飾符標(biāo)記超類的構(gòu)造器。子類實(shí)現(xiàn)超類構(gòu)造器時(shí)也必須使用 required 聲明修飾符。

雖然超類屬性和方法聲明可以被當(dāng)前類繼承,但是超類聲明的指定構(gòu)造器卻不能。即便如此,如果當(dāng)前類重寫了超類的所有指定構(gòu)造器,它就會(huì)繼承超類的所有便利構(gòu)造器。Swift 的類并不繼承自一個(gè)通用基礎(chǔ)類。

有兩種方法來創(chuàng)建已聲明的類的實(shí)例:

  • 調(diào)用類中聲明的構(gòu)造器,請(qǐng)參閱 構(gòu)造器

  • 如果沒有聲明構(gòu)造器,而且類的所有屬性都被賦予了初始值,調(diào)用類的默認(rèn)構(gòu)造器,請(qǐng)參閱 默認(rèn)構(gòu)造器

類實(shí)例屬性可以用點(diǎn)語法(.)來訪問,請(qǐng)參閱 訪問屬性

類是引用類型。當(dāng)被賦予常量或變量,或者傳遞給函數(shù)作為參數(shù)時(shí),類的實(shí)例會(huì)被引用,而不是被復(fù)制。關(guān)于引用類型的更多信息,請(qǐng)參閱 結(jié)構(gòu)體和枚舉是值類型。

可以使用擴(kuò)展聲明來擴(kuò)展類的行為,請(qǐng)參閱 擴(kuò)展聲明。

grammer-of-a-class-declaration

類聲明語法

class-declaration

類聲明特性列表可選 訪問級(jí)別修飾符可選 final可選 class 類名 泛型形參子句可選 類型繼承子句可選 泛型 where 子句可選 類主體

類聲明特性列表可選 final 訪問級(jí)別修飾符可選 class 類名 泛型形參子句可選 類型繼承子句可選 泛型 where 子句可選 類主體

class-name

類名標(biāo)識(shí)符

class-body

類主體{ 多條聲明可選 }

類多個(gè)成員類成員 類多個(gè)成員可選

class-member

類成員聲明 | 編譯控制流語句

協(xié)議聲明

協(xié)議聲明(protocol declaration) 可以為程序引入一個(gè)命名的協(xié)議類型。協(xié)議聲明只能在全局區(qū)域使用 protocol 關(guān)鍵字來進(jìn)行聲明,并遵循如下形式:

protocol 協(xié)議名稱: 繼承的協(xié)議 {
    協(xié)議成員聲明
}

協(xié)議的主體包含零個(gè)或多個(gè)協(xié)議成員聲明,這些成員描述了任何采納該協(xié)議的類型必須滿足的一致性要求。一個(gè)協(xié)議可以聲明采納者必須實(shí)現(xiàn)的某些屬性、方法、構(gòu)造器以及下標(biāo)。協(xié)議也可以聲明各種各樣的類型別名,叫做關(guān)聯(lián)類型,它可以指定協(xié)議的不同聲明之間的關(guān)系。協(xié)議聲明不能包括類、結(jié)構(gòu)體、枚舉或者其它協(xié)議的聲明。協(xié)議成員聲明會(huì)在后面進(jìn)行討論。

協(xié)議類型可以繼承自任意數(shù)量的其它協(xié)議。當(dāng)一個(gè)協(xié)議類型繼承自其它協(xié)議的時(shí)候,來自其它協(xié)議的所有要求會(huì)聚合在一起,而且采納當(dāng)前協(xié)議的類型必須符合所有的這些要求。關(guān)于如何使用協(xié)議繼承的例子,請(qǐng)參閱 協(xié)議繼承

注意

也可以使用協(xié)議合成類型來聚合多個(gè)協(xié)議的一致性要求,請(qǐng)參閱 協(xié)議合成類型協(xié)議合成。

可以通過類型的擴(kuò)展聲明來采納協(xié)議,從而為之前聲明的類型添加協(xié)議一致性。在擴(kuò)展中,必須實(shí)現(xiàn)所有采納協(xié)議的要求。如果該類型已經(jīng)實(shí)現(xiàn)了所有的要求,可以讓這個(gè)擴(kuò)展聲明的主體留空。

默認(rèn)地,符合某個(gè)協(xié)議的類型必須實(shí)現(xiàn)所有在協(xié)議中聲明的屬性、方法和下標(biāo)。即便如此,可以用 optional 聲明修飾符標(biāo)注協(xié)議成員聲明,以指定它們的實(shí)現(xiàn)是可選的。optional 修飾符僅僅可以用于使用 objc 特性標(biāo)記過的協(xié)議。因此,僅僅類類型可以采用并符合包含可選成員要求的協(xié)議。更多關(guān)于如何使用 optional 聲明修飾符的信息,以及如何訪問可選協(xié)議成員的指導(dǎo)——例如不能確定采納協(xié)議的類型是否實(shí)現(xiàn)了它們時(shí)——請(qǐng)參閱 可選協(xié)議要求

為了限制協(xié)議只能被類類型采納,需要使用 AnyObject 關(guān)鍵字來標(biāo)記協(xié)議,將 AnyObject 關(guān)鍵在寫在冒號(hào)后面的繼承的協(xié)議列表的首位。例如,下面的協(xié)議只能被類類型采納:

protocol SomeProtocol: AnyObject {
    /* 這里是協(xié)議成員 */
}

任何繼承自標(biāo)記有 AnyObject 關(guān)鍵字的協(xié)議的協(xié)議也僅能被類類型采納。

注意

如果協(xié)議已經(jīng)用 objc 特性標(biāo)記了,AnyObject 要求就隱式地應(yīng)用于該協(xié)議,無需顯式使用 AnyObject 關(guān)鍵字。

協(xié)議類型是命名的類型,因此它們可以像其他命名類型一樣使用,正如 協(xié)議作為類型 所討論的。然而,不能構(gòu)造一個(gè)協(xié)議的實(shí)例,因?yàn)閰f(xié)議實(shí)際上不提供它們指定的要求的實(shí)現(xiàn)。

可以使用協(xié)議來聲明作為代理的類或者結(jié)構(gòu)體應(yīng)該實(shí)現(xiàn)的方法,正如 委托(代理)模式 中所述。

grammer-of-a-protocol-declaration

協(xié)議聲明語法

protocol-declaration

協(xié)議聲明特性列表可選 訪問級(jí)別修飾符可選 protocol 協(xié)議名稱 類型繼承子句可選 泛型 where 子句可選 協(xié)議主體

protocol-name

協(xié)議名稱標(biāo)識(shí)符

protocol-body

協(xié)議主體{ 協(xié)議成員聲明列表可選 }

協(xié)議多個(gè)成員協(xié)議成員 協(xié)議多個(gè)成員可選

protocol-member

協(xié)議成員協(xié)議成員聲明 | 編譯控制流語句

protocol-member-declaration

協(xié)議成員聲明協(xié)議屬性聲明

協(xié)議成員聲明協(xié)議方法聲明

協(xié)議成員聲明協(xié)議構(gòu)造器聲明

協(xié)議成員聲明協(xié)議下標(biāo)聲明

協(xié)議成員聲明協(xié)議關(guān)聯(lián)類型聲明

protocol-member-declarations

協(xié)議成員聲明列表協(xié)議成員聲明 協(xié)議成員聲明列表可選

協(xié)議屬性聲明

協(xié)議可以通過在協(xié)議聲明主體中引入一個(gè)協(xié)議屬性聲明,來聲明符合的類型必須實(shí)現(xiàn)的屬性。協(xié)議屬性聲明有一種特殊的變量聲明形式:

var 屬性名: 類型 { get set }

同其它協(xié)議成員聲明一樣,這些屬性聲明僅僅針對(duì)符合該協(xié)議的類型聲明了 getter 和 setter 要求,你不能在協(xié)議中直接實(shí)現(xiàn) getter 和 setter。

符合類型可以通過多種方式滿足 getter 和 setter 要求。如果屬性聲明包含 getset 關(guān)鍵字,符合類型就可以用存儲(chǔ)型變量屬性或可讀可寫的計(jì)算型屬性來滿足此要求,但是屬性不能以常量屬性或只讀計(jì)算型屬性實(shí)現(xiàn)。如果屬性聲明僅僅包含 get 關(guān)鍵字的話,它可以作為任意類型的屬性被實(shí)現(xiàn)。關(guān)于如何實(shí)現(xiàn)協(xié)議中的屬性要求的例子,請(qǐng)參閱 屬性要求 。

協(xié)議聲明中聲明一個(gè)類型屬性,屬性聲明語句必須用 static 聲明修飾符。當(dāng)結(jié)構(gòu)體和枚舉遵循該協(xié)議時(shí),使用 static 關(guān)鍵字修飾,而類遵循該協(xié)議時(shí),使用 staticclass 關(guān)鍵字皆可。當(dāng)結(jié)構(gòu)體,枚舉或類添加擴(kuò)展遵循協(xié)議時(shí),和之前擴(kuò)展用到的關(guān)鍵字保持一致。擴(kuò)展為類屬性提供默認(rèn)實(shí)現(xiàn)時(shí),必須使用 static 關(guān)鍵字修飾。

另請(qǐng)參閱 變量聲明。

grammer-of-an-import-declaration

協(xié)議屬性聲明語法

protocol-property-declaration

協(xié)議屬性聲明變量聲明頭 變量名稱 類型注解 getter-setter 關(guān)鍵字代碼塊

協(xié)議方法聲明

協(xié)議可以通過在協(xié)議聲明主體中引入一個(gè)協(xié)議方法聲明,來聲明符合的類型必須實(shí)現(xiàn)的方法。協(xié)議方法聲明和函數(shù)方法聲明有著相同的形式,但有兩項(xiàng)例外:它們不包括函數(shù)體,也不能包含默認(rèn)參數(shù)。關(guān)于如何實(shí)現(xiàn)協(xié)議中的方法要求的例子,請(qǐng)參閱 方法要求。

協(xié)議聲明中聲明一個(gè)類型方法,方法聲明語句必須用 static 聲明修飾符。結(jié)構(gòu)體和枚舉遵循協(xié)議時(shí),必須使用 static 關(guān)鍵字修飾,而類遵循協(xié)議時(shí),使用 staticclass 關(guān)鍵字皆可。當(dāng)結(jié)構(gòu)體,枚舉或類添加擴(kuò)展遵循協(xié)議時(shí),和之前擴(kuò)展用到的關(guān)鍵字保持一致。擴(kuò)展為類方法提供默認(rèn)實(shí)現(xiàn)時(shí),必須使用 static 關(guān)鍵字修飾。

另請(qǐng)參閱 函數(shù)聲明

grammer-of-a-protocol-declaration

協(xié)議方法聲明語法

protocol-method-declaration

協(xié)議方法聲明函數(shù)頭 函數(shù)名 泛型形參子句可選 函數(shù)簽名 泛型 where 子句可選

協(xié)議構(gòu)造器聲明

協(xié)議可以通過在協(xié)議聲明主體中引入一個(gè)協(xié)議構(gòu)造器聲明,來聲明符合的類型必須實(shí)現(xiàn)的構(gòu)造器。協(xié)議構(gòu)造器聲明 除了不包含實(shí)現(xiàn)主體外,和構(gòu)造器聲明有著相同的形式。

符合類型可以通過實(shí)現(xiàn)一個(gè)非可失敗構(gòu)造器或者 init! 可失敗構(gòu)造器來滿足一個(gè)非可失敗協(xié)議構(gòu)造器的要求,可以通過實(shí)現(xiàn)任意類型的構(gòu)造器來滿足一個(gè)可失敗協(xié)議構(gòu)造器的要求。

類在實(shí)現(xiàn)一個(gè)構(gòu)造器去滿足一個(gè)協(xié)議的構(gòu)造器要求時(shí),如果這個(gè)類還沒有用 final 聲明修飾符標(biāo)記,這個(gè)構(gòu)造器必須用 required 聲明修飾符標(biāo)記。

另請(qǐng)參閱 構(gòu)造器聲明。

grammer-of-a-protocol-initializer-declaration

協(xié)議構(gòu)造器聲明語法

protocol-initializer-declaration

協(xié)議構(gòu)造器聲明構(gòu)造器頭 泛型形參子句可選 參數(shù)子句 throws可選 泛型 where 子句可選

協(xié)議構(gòu)造器聲明構(gòu)造器頭 泛型形參子句可選 參數(shù)子句 rethrows 泛型 where 子句可選

協(xié)議下標(biāo)聲明

協(xié)議可以通過在協(xié)議聲明主體中引入一個(gè)協(xié)議下標(biāo)聲明,來聲明符合的類型必須實(shí)現(xiàn)的下標(biāo)。協(xié)議下標(biāo)聲明有一個(gè)特殊的下標(biāo)聲明形式:

subscript (參數(shù)列表) -> 返回類型 { get set }

下標(biāo)聲明只為符合類型聲明了 getter 和 setter 要求。如果下標(biāo)聲明包含 getset 關(guān)鍵字,符合類型也必須實(shí)現(xiàn) getter 和 setter 子句。如果下標(biāo)聲明只包含 get 關(guān)鍵字,符合類型必須實(shí)現(xiàn) getter 子句,可以選擇是否實(shí)現(xiàn) setter 子句。

協(xié)議聲明中聲明一個(gè)靜態(tài)下標(biāo),下標(biāo)聲明語句必須用 static 聲明修飾符。當(dāng)結(jié)構(gòu)體和枚舉遵循該協(xié)議時(shí),下標(biāo)聲明使用 static 關(guān)鍵字修飾,而類遵循該協(xié)議時(shí),使用 staticclass 關(guān)鍵字皆可。當(dāng)結(jié)構(gòu)體,枚舉或類添加擴(kuò)展遵循協(xié)議時(shí),和之前擴(kuò)展用到的關(guān)鍵字保持一致。擴(kuò)展為下標(biāo)聲明提供默認(rèn)實(shí)現(xiàn)時(shí),必須使用 static 關(guān)鍵字修飾。

另請(qǐng)參閱 下標(biāo)聲明

grammer-of-a-protocol-subscript-declaration

協(xié)議下標(biāo)聲明語法

protocol-subscript-declaration

協(xié)議下標(biāo)聲明下標(biāo)頭 下標(biāo)結(jié)果 泛型 where 子句可選 getter-setter 關(guān)鍵字代碼塊

協(xié)議關(guān)聯(lián)類型聲明

使用關(guān)鍵字 associatedtype 來聲明協(xié)議關(guān)聯(lián)類型。關(guān)聯(lián)類型為作為協(xié)議聲明的一部分,為某種類型提供了一個(gè)別名。關(guān)聯(lián)類型和泛型參數(shù)子句中的類型參數(shù)很相似,但是它們和 Self 一樣,用于協(xié)議中。Self 指代采納協(xié)議的類型。要獲得更多信息和例子,請(qǐng)參閱 關(guān)聯(lián)類型。

在協(xié)議聲明中使用泛型 where 子句來為繼承的協(xié)議關(guān)聯(lián)類型添加約束,且不需要重新聲明關(guān)聯(lián)類型。例如下面代碼中的 SubProtocol 聲明。

protocol SomeProtocol {
    associatedtype SomeType
}

protocol SubProtocolA: SomeProtocol {
    // 此類語法會(huì)引發(fā)警告。
    associatedtype SomeType: Equatable
}

// 建議使用此語法。
protocol SubProtocolB: SomeProtocol where SomeType: Equatable { }

另請(qǐng)參閱 類型別名聲明。

grammer-of-a-protocol-associated-type-declaration

協(xié)議關(guān)聯(lián)類型聲明語法

protocol-associated-type-declaration

協(xié)議關(guān)聯(lián)類型聲明特性列表可選 訪問級(jí)別修飾符可選 associatedtype 類型別名頭 類型繼承子句可選 類型別名賦值可選 泛型 where 子句可選

構(gòu)造器聲明

構(gòu)造器聲明會(huì)為程序中的類、結(jié)構(gòu)體或枚舉引入構(gòu)造器。構(gòu)造器使用關(guān)鍵字 init 來聲明,有兩種基本形式。

結(jié)構(gòu)體、枚舉、類可以有任意數(shù)量的構(gòu)造器,但是類的構(gòu)造器具有不同的規(guī)則和行為。不同于結(jié)構(gòu)體和枚舉,類有兩種構(gòu)造器,即指定構(gòu)造器和便利構(gòu)造器,請(qǐng)參閱 構(gòu)造過程。

采用如下形式聲明結(jié)構(gòu)體和枚舉的構(gòu)造器,以及類的指定構(gòu)造器:

init(參數(shù)列表) {
    構(gòu)造語句
}

類的指定構(gòu)造器直接將類的所有屬性初始化。它不能調(diào)用類中的其他構(gòu)造器,如果類有超類,則必須調(diào)用超類的一個(gè)指定構(gòu)造器。如果該類從它的超類繼承了屬性,必須在調(diào)用超類的指定構(gòu)造器后才能修改這些屬性。

指定構(gòu)造器只能在類聲明中聲明,不能在擴(kuò)展聲明中聲明。

結(jié)構(gòu)體和枚舉的構(gòu)造器可以調(diào)用其他已聲明的構(gòu)造器,從而委托其他構(gòu)造器來進(jìn)行部分或者全部構(gòu)造過程。

要為類聲明一個(gè)便利構(gòu)造器,用 convenience 聲明修飾符來標(biāo)記構(gòu)造器聲明:

convenience init(參數(shù)列表) {
    構(gòu)造語句
}

便利構(gòu)造器可以將構(gòu)造過程委托給另一個(gè)便利構(gòu)造器或一個(gè)指定構(gòu)造器。但是,類的構(gòu)造過程必須以一個(gè)將類中所有屬性完全初始化的指定構(gòu)造器的調(diào)用作為結(jié)束。便利構(gòu)造器不能調(diào)用超類的構(gòu)造器。

可以使用 required 聲明修飾符,將便利構(gòu)造器和指定構(gòu)造器標(biāo)記為每個(gè)子類都必須實(shí)現(xiàn)的構(gòu)造器。這種構(gòu)造器的子類實(shí)現(xiàn)也必須使用 required 聲明修飾符標(biāo)記。

默認(rèn)情況下,超類中的構(gòu)造器不會(huì)被子類繼承。但是,如果子類的所有存儲(chǔ)型屬性都有默認(rèn)值,而且子類自身沒有定義任何構(gòu)造器,它將繼承超類的構(gòu)造器。如果子類重寫了超類的所有指定構(gòu)造器,子類將繼承超類的所有便利構(gòu)造器。

和方法、屬性和下標(biāo)一樣,需要使用 override 聲明修飾符標(biāo)記重寫的指定構(gòu)造器。

注意

如果使用 required 聲明修飾符標(biāo)記一個(gè)構(gòu)造器,在子類中重寫這種構(gòu)造器時(shí),無需使用 override 修飾符。

就像函數(shù)和方法,構(gòu)造器也可以拋出或者重拋錯(cuò)誤,你可以在構(gòu)造器參數(shù)列表的圓括號(hào)之后使用 throwsrethrows 關(guān)鍵字來表明相應(yīng)的拋出行為。

關(guān)于在不同類型中聲明構(gòu)造器的例子,請(qǐng)參閱 構(gòu)造過程。

可失敗構(gòu)造器

可失敗構(gòu)造器可以生成所屬類型的可選實(shí)例或者隱式解包可選實(shí)例,因此,這種構(gòu)造器通過返回 nil 來指明構(gòu)造過程失敗。

聲明生成可選實(shí)例的可失敗構(gòu)造器時(shí),在構(gòu)造器聲明的 init 關(guān)鍵字后加追加一個(gè)問號(hào)(init?)。聲明生成隱式解包可選實(shí)例的可失敗構(gòu)造器時(shí),在構(gòu)造器聲明后追加一個(gè)嘆號(hào)(init!)。使用 init? 可失敗構(gòu)造器生成結(jié)構(gòu)體的一個(gè)可選實(shí)例的例子如下。

struct SomeStruct {
    let string: String
    //生成一個(gè) SomeStruct 的可選實(shí)例
    init?(input: String) {
        if input.isEmpty {
            // 丟棄 self,并返回 nil
            return nil
        }
        string = input
    }
}

調(diào)用 init? 可失敗構(gòu)造器和調(diào)用非可失敗構(gòu)造器的方式相同,不過你需要處理可選類型的返回值。

if let actualInstance = SomeStruct(input: "Hello") {
    // 利用 SomeStruct 實(shí)例做些事情
} else {
    // SomeStruct 實(shí)例的構(gòu)造過程失敗,構(gòu)造器返回了 nil
}

可失敗構(gòu)造器可以在構(gòu)造器實(shí)現(xiàn)中的任意位置返回 nil

可失敗構(gòu)造器可以委托任意種類的構(gòu)造器。非可失敗可以委托其它非可失敗構(gòu)造器或者 init! 可失敗構(gòu)造器。非可失敗構(gòu)造器可以委托超類的 init? 可失敗指定構(gòu)造器,但是需要使用強(qiáng)制解包,例如 super.init()!。

構(gòu)造過程失敗通過構(gòu)造器委托來傳遞。具體來說,如果可失敗構(gòu)造器委托的可失敗構(gòu)造器構(gòu)造過程失敗并返回 nil,那么該可失敗構(gòu)造器也會(huì)構(gòu)造失敗并隱式地返回 nil。如果非可失敗構(gòu)造器委托的 init! 可失敗構(gòu)造器構(gòu)造失敗并返回了 nil,那么會(huì)發(fā)生運(yùn)行時(shí)錯(cuò)誤(如同使用 ! 操作符去強(qiáng)制解包一個(gè)值為 nil 的可選值)。

子類可以用任意種類的指定構(gòu)造器重寫超類的可失敗指定構(gòu)造器,但是只能用非可失敗指定構(gòu)造器重寫超類的非可失敗指定構(gòu)造器。

更多關(guān)于可失敗構(gòu)造器的信息和例子,請(qǐng)參閱 可失敗構(gòu)造器。

grammer-of-an-initializer-declaration

構(gòu)造器聲明語法

initializer-declaration

構(gòu)造器聲明構(gòu)造器頭 泛型形參子句可選 參數(shù)子句 throws可選 泛型 where 子句可選 構(gòu)造器主體

構(gòu)造器聲明構(gòu)造器頭 泛型形參子句可選 參數(shù)子句 rethrows可選 泛型 where 子句可選 構(gòu)造器主體

initializer-head

構(gòu)造器頭特性列表可選 聲明修飾符列表可選 init

構(gòu)造器頭特性列表可選 聲明修飾符列表可選 init ?

構(gòu)造器頭特性列表可選 聲明修飾符列表可選 init !

initializer-body

構(gòu)造器主體代碼塊

析構(gòu)器聲明

析構(gòu)器聲明(deinitializer declaration) 可以為類聲明一個(gè)析構(gòu)器。析構(gòu)器沒有參數(shù),遵循如下格式:

deinit {
    語句
}

當(dāng)沒有任何強(qiáng)引用引用著類的對(duì)象,對(duì)象即將被釋放時(shí),析構(gòu)器會(huì)被自動(dòng)調(diào)用。析構(gòu)器只能在類主體的聲明中聲明,不能在類的擴(kuò)展聲明中聲明,并且每個(gè)類最多只能有一個(gè)析構(gòu)器。

子類會(huì)繼承超類的析構(gòu)器,并會(huì)在子類對(duì)象將要被釋放時(shí)隱式調(diào)用。繼承鏈上的所有析構(gòu)器全部調(diào)用完畢后子類對(duì)象才會(huì)被釋放。

析構(gòu)器不能直接調(diào)用。

關(guān)于如何在類聲明中使用析構(gòu)器的例子,請(qǐng)參閱 析構(gòu)過程。

grammer-of-a-deinitializer-declaration

析構(gòu)器聲明語法

deinitializer-declaration

析構(gòu)器聲明特性列表可選 deinit 代碼塊

擴(kuò)展聲明

擴(kuò)展聲明(extension declaration) 可以擴(kuò)展一個(gè)現(xiàn)存的類型的行為。擴(kuò)展聲明使用關(guān)鍵字 extension,遵循如下格式:

extension 類型名稱 where 要求 {
    聲明語句
}

擴(kuò)展聲明體可包含零個(gè)或多個(gè)聲明語句。這些聲明語句可以包括計(jì)算型屬性、計(jì)算型類型屬性、實(shí)例方法、類型方法、構(gòu)造器、下標(biāo)聲明,甚至是類、結(jié)構(gòu)體和枚舉聲明。擴(kuò)展聲明不能包含析構(gòu)器、協(xié)議聲明、存儲(chǔ)型屬性、屬性觀察器或其他擴(kuò)展聲明。關(guān)于擴(kuò)展聲明的詳細(xì)討論,以及各種擴(kuò)展聲明的例子,請(qǐng)參閱 擴(kuò)展。

如果類型為類,結(jié)構(gòu)體,或枚舉類型,則擴(kuò)展聲明會(huì)擴(kuò)展相應(yīng)的類型。如果類型為協(xié)議類型,則擴(kuò)展聲明會(huì)擴(kuò)展所有遵守這個(gè)協(xié)議的類型。在擴(kuò)展的協(xié)議體中聲明語句不能使用 final 標(biāo)識(shí)符。

擴(kuò)展聲明可以為現(xiàn)存的類、結(jié)構(gòu)體、枚舉添加協(xié)議一致性,但是不能為類添加超類,因此在擴(kuò)展聲明的類型名稱的冒號(hào)后面僅能指定一個(gè)協(xié)議列表。

擴(kuò)展聲明可以包含構(gòu)造器聲明。這意味著,如果被擴(kuò)展的類型在其他模塊中定義,構(gòu)造器聲明必須委托另一個(gè)在那個(gè)模塊中聲明的構(gòu)造器,以確保該類型能被正確地初始化。

現(xiàn)存類型的屬性、方法、構(gòu)造器不能在擴(kuò)展中被重寫。

通過指定采納的協(xié)議,擴(kuò)展聲明可以為一個(gè)現(xiàn)有的類、結(jié)構(gòu)體或者枚舉類型添加協(xié)議遵循:

extension 類型名稱: 采納的協(xié)議 where 約束條件 {
    多條聲明
}

協(xié)議聲明不能為現(xiàn)有的類添加類的繼承關(guān)系,因此你只能在 “類型名稱” 的冒號(hào)后面添加一系列協(xié)議。

條件遵循

你可以擴(kuò)展一個(gè)泛型類型并使其有條件地遵循某協(xié)議,此后此類型的實(shí)例只有在特定的限制條件滿足時(shí)才遵循此協(xié)議。在擴(kuò)展聲明中加入限制條件來為協(xié)議添加條件遵循。

已重寫的限制條件會(huì)在某些泛型上下文中失效

對(duì)于一些通過條件遵循獲得了特定行為的類型,在某些泛型上下文中,并不能夠確保能夠使用協(xié)議限制中的特定實(shí)現(xiàn)。為了說明這個(gè)行為,下面的例子中定義了兩個(gè)協(xié)議以及一個(gè)有條件地遵循兩個(gè)協(xié)議的泛型類型。

protocol Loggable {
    func log()
}
extension Loggable {
    func log() {
        print(self)
    }
}

protocol TitledLoggable: Loggable {
    static var logTitle: String { get }
}
extension TitledLoggable {
    func log() {
        print("\(Self.logTitle): \(self)")
    }
}

struct Pair<T>: CustomStringConvertible {
    let first: T
    let second: T
    var description: String {
        return "(\(first), \(second))"
    }
}

extension Pair: Loggable where T: Loggable { }
extension Pair: TitledLoggable where T: TitledLoggable {
    static var logTitle: String {
        return "Pair of '\(T.logTitle)'"
    }
}

extension String: TitledLoggable {
    static var logTitle: String {
        return "String"
    }
}

當(dāng)其泛型類型遵循 Loggable 協(xié)議以及 TitleLoggale 協(xié)議時(shí),結(jié)構(gòu)體 Pair 遵循 Loggable 協(xié)議以及 TitleLoggale 協(xié)議。下面的例子中,oneAndTwoPair<String> 的一個(gè)實(shí)例。因?yàn)?String 遵循 TitleLoggable ,因此 oneAndTwo 也遵循此協(xié)議。當(dāng) log() 方法被 oneAndTwo 直接調(diào)用時(shí),此方法使用的是包含標(biāo)題的特定版本。

let oneAndTwo = Pair(first: "one", second: "two")
oneAndTwo.log()
// Prints "Pair of 'String': (one, two)"

雖然如此,當(dāng) oneAndTwo 在泛型上下文中使用,或者它是 Loggable 類型的實(shí)例時(shí),包含標(biāo)題的特定版本 log() 方法不會(huì)被使用。Swift 只會(huì)根據(jù)這樣的規(guī)則來選擇 log() 的實(shí)現(xiàn)版本—— Pair 遵循 Loggable 所需要的最少的限制條件。因此 Loggable 所提供的默認(rèn)實(shí)現(xiàn)版本會(huì)被使用。

func doSomething<T: Loggable>(with x: T) {
    x.log()
}
doSomething(with: oneAndTwo)
// Prints "(one, two)"

當(dāng)傳入 doSomething(_:) 的實(shí)例調(diào)用 log() 時(shí),打印結(jié)果省略了自定義標(biāo)題。

協(xié)議遵循決不能冗余

一個(gè)具體的類型只能夠遵循某特定協(xié)議一次。Swift 會(huì)把冗余的協(xié)議遵循標(biāo)記為錯(cuò)誤。你會(huì)在兩種場景中遇到這種錯(cuò)誤。第一種場景是,使用不同的限制條件來多次顯式地遵循同一協(xié)議。第二種場景是,多次隱式地繼承同一協(xié)議。以上兩種場景會(huì)在下面章節(jié)中討論。

解決顯式冗余

對(duì)同一具體類型的多個(gè)擴(kuò)展不能遵循同一協(xié)議,即便這些擴(kuò)展有不同的顯式限制條件。這個(gè)限制的具體示例在下面的例子中。兩個(gè)擴(kuò)展聲明都試圖添加對(duì) Serializable 的條件遵循,一個(gè)為 Int 類型元素的數(shù)組,另一個(gè)為 String 類型元素的數(shù)組。

protocol Serializable {
    func serialize() -> Any
}

extension Array: Serializable where Element == Int {
    func serialize() -> Any {
        // implementation
    }
}
extension Array: Serializable where Element == String {
    func serialize() -> Any {
        // implementation
    }
}
// 報(bào)錯(cuò): redundant conformance of 'Array<Element>' to protocol 'Serializable'

如果你需要基于多個(gè)具體類型來添加條件遵循,那么創(chuàng)建一個(gè)新的協(xié)議,然后讓每個(gè)類型都遵循此協(xié)議,最后在聲明條件遵循時(shí)使用此協(xié)議作為條件限制。

protocol SerializableInArray { }
extension Int: SerializableInArray { }
extension String: SerializableInArray { }

extension Array: Serializable where Element: SerializableInArray {
    func serialize() -> Any {
        // 具體實(shí)現(xiàn)
    }
}

解決隱式冗余

當(dāng)一個(gè)具體類型有條件地遵循某協(xié)議,此類型會(huì)隱式地使用相同的條件遵循任一父協(xié)議。

如果你需要讓一個(gè)類型有條件地遵循兩個(gè)繼承自同一父協(xié)議的協(xié)議,請(qǐng)顯式地聲明對(duì)父協(xié)議的遵循。這可以避免使用不同的限制條件隱式遵循同一父協(xié)議兩次。

下面的例子中顯式地聲明了 Array 對(duì) Loggable 的條件遵循,避免了在聲明對(duì) TitledLoggableTitledLoggable 聲明條件遵循時(shí)發(fā)生沖突。

protocol MarkedLoggable: Loggable {
    func markAndLog()
}

extension MarkedLoggable {
    func markAndLog() {
        print("----------")
        log()
    }
}

extension Array: Loggable where Element: Loggable { }
extension Array: TitledLoggable where Element: TitledLoggable {
    static var logTitle: String {
        return "Array of '\(Element.logTitle)'"
    }
}
extension Array: MarkedLoggable where Element: MarkedLoggable { }

如果不顯式聲明對(duì) Loggable 的條件遵循,Array 其他的擴(kuò)展會(huì)隱式地創(chuàng)建此聲明,并引發(fā)錯(cuò)誤:

extension Array: Loggable where Element: TitledLoggable { }
extension Array: Loggable where Element: MarkedLoggable { }
// 報(bào)錯(cuò): redundant conformance of 'Array<Element>' to protocol 'Loggable'

grammer-of-an-extension-declaration

擴(kuò)展聲明語法

extension-declaration

擴(kuò)展聲明特性可選 訪問級(jí)別修飾符可選 extension 類型標(biāo)識(shí)符 類型-繼承-子句可選 泛型 where 子句可選 擴(kuò)展主體

extension-body

擴(kuò)展主體{ 多條聲明可選 }

多條聲明單條聲明 多條聲明 可選

單條聲明聲明語句 | 編譯控制流語句

下標(biāo)聲明

下標(biāo)聲明(subscript declaration) 用于為特定類型的對(duì)象添加下標(biāo)支持,通常也用于為訪問集合、列表和序列中的元素提供語法便利。下標(biāo)聲明使用關(guān)鍵字 subscript,形式如下:

subscript (參數(shù)列表) -> 返回類型 {
    get {
        語句
    }
    set(setter 名稱) {
        語句
    }
}

下標(biāo)聲明只能出現(xiàn)在類、結(jié)構(gòu)體、枚舉、擴(kuò)展和協(xié)議的聲明中。

參數(shù)列表指定一個(gè)或多個(gè)用于在相關(guān)類型的下標(biāo)表達(dá)式中訪問元素的索引(例如,表達(dá)式 object[i] 中的 i)。索引可以是任意類型,但是必須包含類型注解。返回類型指定了被訪問的元素的類型。

和計(jì)算型屬性一樣,下標(biāo)聲明支持對(duì)元素的讀寫操作。getter 用于讀取值,setter 用于寫入值。setter 子句是可選的,當(dāng)僅需要一個(gè) getter 子句時(shí),可以將二者都忽略,直接返回請(qǐng)求的值即可。但是,如果提供了 setter 子句,就必須提供 getter 子句。

圓括號(hào)以及其中的 setter 名稱是可選的。如果提供了 setter 名稱,它會(huì)作為 setter 的參數(shù)名稱。如果不提供 setter 名稱,那么 setter 的參數(shù)名稱默認(rèn)是 value。setter 的參數(shù)類型必須與返回類型相同。

可以重寫下標(biāo),只要參數(shù)列表或返回類型不同即可。還可以重寫繼承自超類的下標(biāo),此時(shí)必須使用 override 聲明修飾符聲明被重寫的下標(biāo)。

下標(biāo)參數(shù)遵循與函數(shù)參數(shù)相同的規(guī)則,但有兩個(gè)例外。默認(rèn)情況下,下標(biāo)中使用的參數(shù)不需要指定標(biāo)簽,這與函數(shù),方法和構(gòu)造器不同。但是你也可以同它們一樣,顯式地提供參數(shù)標(biāo)簽。此外,下標(biāo)不能有 In-out 參數(shù)。

同樣可以在協(xié)議聲明中聲明下標(biāo),正如 協(xié)議下標(biāo)聲明 中所述。

更多關(guān)于下標(biāo)的信息和例子,請(qǐng)參閱 下標(biāo)。

類型下標(biāo)聲明

聲明一個(gè)由類型而不是類型實(shí)例公開的下標(biāo),請(qǐng)使用 static 聲明修飾符標(biāo)記下標(biāo)聲明。類可以使用 class 聲明修飾符標(biāo)記類型計(jì)算屬性,以允許子類重寫父類的實(shí)現(xiàn)。在類聲明中,static 關(guān)鍵字具有與用 classfinal 聲明修飾符標(biāo)記聲明相同的效果。

grammer-of-a-subscript-declaration

下標(biāo)聲明語法

subscript-declaration

下標(biāo)聲明下標(biāo)頭 下標(biāo)結(jié)果 泛型 where 子句可選 代碼塊

下標(biāo)聲明下標(biāo)頭 下標(biāo)結(jié)果 泛型 where 子句可選 getter-setter 代碼塊

下標(biāo)聲明下標(biāo)頭 下標(biāo)結(jié)果 泛型 where 子句可選 getter-setter 關(guān)鍵字代碼塊

subscript-head

下標(biāo)頭特性列表可選 聲明修飾符列表可選 subscript 泛型參數(shù)子句可選 參數(shù)子句

subscript-result

下標(biāo)結(jié)果-> 特性列表可選 類型

運(yùn)算符聲明

運(yùn)算符聲明(operator declaration) 會(huì)向程序中引入中綴、前綴或后綴運(yùn)算符,使用關(guān)鍵字 operator 來聲明。

可以聲明三種不同的綴性:中綴、前綴和后綴。運(yùn)算符的綴性指定了運(yùn)算符與其運(yùn)算對(duì)象的相對(duì)位置。

運(yùn)算符聲明有三種基本形式,每種綴性各一種。運(yùn)算符的綴性通過在 operator 關(guān)鍵字之前添加聲明修飾符 infix,prefixpostfix 來指定。每種形式中,運(yùn)算符的名字只能包含 運(yùn)算符 中定義的運(yùn)算符字符。

下面的形式聲明了一個(gè)新的中綴運(yùn)算符:

infix operator 運(yùn)算符名稱: 優(yōu)先級(jí)組

中綴運(yùn)算符是二元運(yùn)算符,置于兩個(gè)運(yùn)算對(duì)象之間,例如加法運(yùn)算符(+)位于表達(dá)式 1 + 2 的中間。

中綴運(yùn)算符可以選擇指定優(yōu)先級(jí)組。如果沒有為運(yùn)算符設(shè)置優(yōu)先級(jí)組,Swift 會(huì)設(shè)置默認(rèn)優(yōu)先級(jí)組 DefaultPrecedence,它的優(yōu)先級(jí)比三目優(yōu)先級(jí) TernaryPrecedence 要高,更多內(nèi)容參考優(yōu)先級(jí)組聲明

下面的形式聲明了一個(gè)新的前綴運(yùn)算符:

prefix operator 運(yùn)算符名稱 {}

出現(xiàn)在運(yùn)算對(duì)象前邊的前綴運(yùn)算符是一元運(yùn)算符,例如表達(dá)式 !a 中的前綴非運(yùn)算符(!)。

前綴運(yùn)算符的聲明中不指定優(yōu)先級(jí),而且前綴運(yùn)算符是非結(jié)合的。

下面的形式聲明了一個(gè)新的后綴運(yùn)算符:

postfix operator 運(yùn)算符名稱 {}

緊跟在運(yùn)算對(duì)象后邊的后綴運(yùn)算符是一元運(yùn)算符,例如表達(dá)式 a! 中的后綴強(qiáng)制解包運(yùn)算符(!)。

和前綴運(yùn)算符一樣,后綴運(yùn)算符的聲明中不指定優(yōu)先級(jí),而且后綴運(yùn)算符是非結(jié)合的。

聲明了一個(gè)新的運(yùn)算符以后,需要實(shí)現(xiàn)一個(gè)跟這個(gè)運(yùn)算符同名的函數(shù)來實(shí)現(xiàn)這個(gè)運(yùn)算符。如果是實(shí)現(xiàn)一個(gè)前綴或者后綴運(yùn)算符,也必須使用相符的 prefix 或者 postfix 聲明修飾符標(biāo)記函數(shù)聲明。如果是實(shí)現(xiàn)中綴運(yùn)算符,則不需要使用 infix 聲明修飾符標(biāo)記函數(shù)聲明。關(guān)于如何實(shí)現(xiàn)一個(gè)新的運(yùn)算符的例子,請(qǐng)參閱 自定義運(yùn)算符

grammer-of-an-operator-declaration

運(yùn)算符聲明語法

operator-declaration

運(yùn)算符聲明前綴運(yùn)算符聲明 | 后綴運(yùn)算符聲明 | 中綴運(yùn)算符聲明

prefix-operator-declaration

前綴運(yùn)算符聲明prefix 運(yùn)算符 運(yùn)算符 { }

postfix-operator-declaration

后綴運(yùn)算符聲明postfix 運(yùn)算符 運(yùn)算符 { }

infix-operator-declaration

中綴運(yùn)算符聲明infix 運(yùn)算符 運(yùn)算符 { 中綴運(yùn)算符屬性可選 }

infix-operator-group

中綴運(yùn)算符組優(yōu)先級(jí)組名稱

優(yōu)先級(jí)組聲明

優(yōu)先級(jí)組聲明(A precedence group declaration) 會(huì)向程序的中綴運(yùn)算符引入一個(gè)全新的優(yōu)先級(jí)組。當(dāng)沒有用圓括號(hào)分組時(shí),運(yùn)算符優(yōu)先級(jí)反應(yīng)了運(yùn)算符與它的操作數(shù)的關(guān)系的緊密程度。 優(yōu)先級(jí)組的聲明如下所示:

precedencegroup 優(yōu)先級(jí)組名稱{
    higherThan: 較低優(yōu)先級(jí)組的名稱
    lowerThan: 較高優(yōu)先級(jí)組的名稱
    associativity: 結(jié)合性
    assignment: 賦值性
}

較低優(yōu)先級(jí)組和較高優(yōu)先級(jí)組的名稱說明了新建的優(yōu)先級(jí)組是依賴于現(xiàn)存的優(yōu)先級(jí)組的。lowerThan 優(yōu)先級(jí)組的屬性只可以引用當(dāng)前模塊外的優(yōu)先級(jí)組。當(dāng)兩個(gè)運(yùn)算符為同一個(gè)操作數(shù)競爭時(shí),比如表達(dá)式 2 + 3 * 5,優(yōu)先級(jí)更高的運(yùn)算符將優(yōu)先參與運(yùn)算。

注意

使用較低和較高優(yōu)先級(jí)組相互聯(lián)系的優(yōu)先級(jí)組必須保持單一層次關(guān)系,但它們不必是線性關(guān)系。這意味著優(yōu)先級(jí)組也許會(huì)有未定義的相關(guān)優(yōu)先級(jí)。這些優(yōu)先級(jí)組的運(yùn)算符在沒有用圓括號(hào)分組的情況下是不能緊鄰著使用的。

Swift 定義了大量的優(yōu)先級(jí)組來與標(biāo)準(zhǔn)庫的運(yùn)算符配合使用,例如相加(+)和相減(-)屬于 AdditionPrecedence 組,相乘(*)和相除(/)屬于 MultiplicationPrecedence 組,詳細(xì)關(guān)于 Swift 標(biāo)準(zhǔn)庫中一系列運(yùn)算符和優(yōu)先級(jí)組內(nèi)容,參閱 Swift 標(biāo)準(zhǔn)庫操作符參考

運(yùn)算符的結(jié)合性表示在沒有圓括號(hào)分組的情況下,同樣優(yōu)先級(jí)的一系列運(yùn)算符是如何被分組的。你可以指定運(yùn)算符的結(jié)合性通過上下文關(guān)鍵字 left、right 或者 none,如果沒有指定結(jié)合性,默認(rèn)是 none 關(guān)鍵字。左關(guān)聯(lián)性的運(yùn)算符是從左至右分組的,例如,相減操作符(-)是左關(guān)聯(lián)性的,所以表達(dá)式 4 - 5 - 6 被分組為 (4 - 5) - 6,得出結(jié)果-7。右關(guān)聯(lián)性的運(yùn)算符是從右往左分組的,指定為 none 結(jié)合性的運(yùn)算符就沒有結(jié)合性。同樣優(yōu)先級(jí)沒有結(jié)合性的運(yùn)算符不能相鄰出現(xiàn),例如 < 運(yùn)算符是 none 結(jié)合性,那表示 1 < 2 < 3 就不是一個(gè)有效表達(dá)式。

優(yōu)先級(jí)組的賦值性表示在包含可選鏈操作時(shí)的運(yùn)算符優(yōu)先級(jí)。當(dāng)設(shè)為 true 時(shí),與優(yōu)先級(jí)組對(duì)應(yīng)的運(yùn)算符在可選鏈操作中使用和標(biāo)準(zhǔn)庫中賦值運(yùn)算符同樣的分組規(guī)則,當(dāng)設(shè)為 false 或者不設(shè)置,該優(yōu)先級(jí)組的運(yùn)算符與不賦值的運(yùn)算符遵循同樣的可選鏈規(guī)則。

grammer-of-a-precedence-group-declaration

優(yōu)先級(jí)組聲明語法

precedence-group-declaration

優(yōu)先級(jí)組聲明precedence優(yōu)先級(jí)組名稱{多優(yōu)先級(jí)組屬性可選 }

precedence-group-attributes

優(yōu)先級(jí)組屬性優(yōu)先級(jí)組屬性多優(yōu)先級(jí)組屬性可選 { }

precedence-group-attribute

優(yōu)先級(jí)組屬性優(yōu)先級(jí)組關(guān)系

優(yōu)先級(jí)組屬性優(yōu)先級(jí)組賦值性

優(yōu)先級(jí)組屬性優(yōu)先級(jí)組相關(guān)性

precedence-group-relation

優(yōu)先級(jí)組關(guān)系higherThan:多優(yōu)先級(jí)組名稱

優(yōu)先級(jí)組關(guān)系lowerThan:多優(yōu)先級(jí)組名稱

precedence-group-assignment

優(yōu)先級(jí)組賦值assignment:布爾字面值

precedence-group-associativity

優(yōu)先級(jí)組結(jié)合性associativity:left

優(yōu)先級(jí)組結(jié)合性associativity:right

優(yōu)先級(jí)組結(jié)合性associativity:none

precedence-group-names

多優(yōu)先級(jí)組名稱優(yōu)先級(jí)組名稱 | 優(yōu)先級(jí)組名稱 | 優(yōu)先級(jí)組名稱

precedence-group-name

優(yōu)先級(jí)組名稱標(biāo)識(shí)符

聲明修飾符

聲明修飾符都是關(guān)鍵字或上下文相關(guān)的關(guān)鍵字,可以修改一個(gè)聲明的行為或者含義??梢栽诼暶鞯奶匦裕ㄈ绻嬖冢┖鸵朐撀暶鞯年P(guān)鍵字之間,利用聲明修飾符的關(guān)鍵字或上下文相關(guān)的關(guān)鍵字指定一個(gè)聲明修飾符。

class

該修飾符用于修飾任何類成員,表明是類自身的成員,而不是類實(shí)例的成員。父類中使用該修飾符標(biāo)記或者未被 final 修飾符標(biāo)記的成員,都允許被子類重寫。

dynamic

該修飾符用于修飾任何兼容 Objective-C 的類的成員。訪問被 dynamic 修飾符標(biāo)記的類成員將總是由 Objective-C 運(yùn)行時(shí)系統(tǒng)進(jìn)行動(dòng)態(tài)派發(fā),而不會(huì)由編譯器進(jìn)行內(nèi)聯(lián)或消虛擬化。

因?yàn)楸粯?biāo)記 dynamic 修飾符的類成員會(huì)由 Objective-C 運(yùn)行時(shí)系統(tǒng)進(jìn)行動(dòng)態(tài)派發(fā),所以它們會(huì)被隱式標(biāo)記 objc 特性。

final

該修飾符用于修飾類或類中的屬性、方法以及下標(biāo)。如果用它修飾一個(gè)類,那么這個(gè)類不能被繼承。如果用它修飾類中的屬性、方法或下標(biāo),那么它們不能在子類中被重寫。

lazy

該修飾符用于修飾類或結(jié)構(gòu)體中的存儲(chǔ)型變量屬性,表示該屬性的初始值最多只被計(jì)算和存儲(chǔ)一次,且發(fā)生在它被第一次訪問時(shí)。關(guān)于如何使用 lazy 修飾符的例子,請(qǐng)參閱 惰性存儲(chǔ)型屬性

optional

該修飾符用于修飾協(xié)議中的屬性、方法以及下標(biāo)成員,表示符合類型可以不實(shí)現(xiàn)這些成員要求。

只能將 optional 修飾符用于被 objc 特性標(biāo)記的協(xié)議。這樣一來,就只有類類型可以采納并符合擁有可選成員要求的協(xié)議。關(guān)于如何使用 optional 修飾符,以及如何訪問可選協(xié)議成員(比如,不確定符合類型是否已經(jīng)實(shí)現(xiàn)了這些可選成員)的信息,請(qǐng)參閱 可選協(xié)議要求

required

該修飾符用于修飾類的指定構(gòu)造器或便利構(gòu)造器,表示該類所有的子類都必須實(shí)現(xiàn)該構(gòu)造器。在子類實(shí)現(xiàn)該構(gòu)造器時(shí),必須同樣使用 required 修飾符修飾該構(gòu)造器。

static

該修飾符用于修飾結(jié)構(gòu)體、類、枚舉或協(xié)議的成員,表明是類型成員,而不是類型實(shí)例的成員。在類聲明的作用范圍內(nèi),使用 static 修飾符標(biāo)記成員聲明語句,同 classfinal 修飾符具有相同的效果。但是類的常量類型屬性是一個(gè)例外: static 沒有問題,但是你無法為常量聲明使用 classfinal 修飾符。

unowned

該修飾符用于修飾存儲(chǔ)型變量、常量或者存儲(chǔ)型變量屬性,表示該變量或?qū)傩猿钟衅浯鎯?chǔ)對(duì)象的無主引用。如果在此存儲(chǔ)對(duì)象釋放后嘗試訪問該對(duì)象,會(huì)引發(fā)運(yùn)行時(shí)錯(cuò)誤。如同弱引用一樣,該引用類型的變量或?qū)傩员仨毷穷愵愋?。與弱引用不同的是,這種類型的變量或?qū)傩允欠强蛇x的。關(guān)于 unowned 更多的信息和例子,請(qǐng)參閱 無主引用

unowned(safe)

unowned 的顯式寫法

unowned(unsafe)

該修飾符用于修飾存儲(chǔ)型變量、常量或者存儲(chǔ)型變量屬性,表示該變量或?qū)傩猿钟衅浯鎯?chǔ)對(duì)象的無主引用。如果在此存儲(chǔ)對(duì)象釋放后嘗試訪問該對(duì)象,會(huì)直接訪問該對(duì)象釋放前存儲(chǔ)的內(nèi)存地址,因此這是非內(nèi)存安全的操作。如同弱引用一樣,該引用類型的變量或?qū)傩员仨毷穷愵愋汀Ec弱引用不同的是,這種類型的變量或?qū)傩允欠强蛇x的。關(guān)于 unowned 更多的信息和例子,請(qǐng)參閱 無主引用

weak

該修飾符用于修飾變量或存儲(chǔ)型變量屬性,表示該變量或?qū)傩猿钟衅浯鎯?chǔ)的對(duì)象的弱引用。這種變量或?qū)傩缘念愋捅仨毷强蛇x的類類型。使用 weak 修飾符可避免強(qiáng)引用循環(huán)。關(guān)于 weak 修飾符的更多信息和例子,請(qǐng)參閱 弱引用。

訪問控制級(jí)別

Swift 提供了三個(gè)級(jí)別的訪問控制:public、internalprivate??梢允褂靡韵氯我庖环N訪問級(jí)別修飾符來指定聲明的訪問級(jí)別。訪問控制在 訪問控制 中有詳細(xì)討論。

public

該修飾符表示聲明可被同模塊的代碼訪問,只要其他模塊導(dǎo)入了聲明所在的模塊,也可以進(jìn)行訪問。

internal

該修飾符表示聲明只能被同模塊的代碼訪問。默認(rèn)情況下,絕大多數(shù)聲明會(huì)被隱式標(biāo)記 internal 訪問級(jí)別修飾符。

private

該修飾符表示聲明只能被所在源文件的代碼訪問。

以上訪問級(jí)別修飾符都可以選擇帶上一個(gè)參數(shù),該參數(shù)由一對(duì)圓括號(hào)和其中的 set 關(guān)鍵字組成(例如,private(set))。使用這種形式的訪問級(jí)別修飾符來限制某個(gè)屬性或下標(biāo)的 setter 的訪問級(jí)別低于其本身的訪問級(jí)別,正如 Getter 和 Setter 中所討論的。

grammer-of-a-declaration-modifier

聲明修飾符的語法

declaration-modifier

聲明修飾符class | convenience| dynamic | final | infix | lazy | mutating | nonmutating | optional | override | postfix | prefix | required | static | unowned | unowned ( safe ) | unowned ( unsafe ) | weak

聲明修飾符 → 訪問級(jí)別修飾符

declaration-modifiers

聲明修飾符列表聲明修飾符 聲明修飾符列表可選

access-level-modifier

訪問級(jí)別修飾符 → internal | internal ( set )

訪問級(jí)別修飾符 → private | private ( set )

訪問級(jí)別修飾符 → public | public ( set )

? 語句 特性 ?
?