鍍金池/ 教程/ iOS/ 訪問控制
特性(Attributes)
Access Control 權(quán)限控制的黑與白
基本運(yùn)算符(Basic Operators)
基礎(chǔ)部分(The Basics)
閉包(Closures)
擴(kuò)展
泛型參數(shù)(Generic Parameters and Arguments)
訪問控制和 protected
語句(Statements)
模式(Patterns)
WWDC 里面的那個“大炮打氣球”
關(guān)于語言參考(About the Language Reference)
語法總結(jié)(Summary of the Grammar)
嵌套類型
類型(Types)
Swift 初見(A Swift Tour)
泛型
枚舉(Enumerations)
高級運(yùn)算符
繼承
析構(gòu)過程
關(guān)于 Swift(About Swift)
訪問控制
類和結(jié)構(gòu)體
內(nèi)存安全
Swift 與 C 語言指針友好合作
協(xié)議
屬性(Properties)
可選類型完美解決占位問題
錯誤處理
字符串和字符(Strings and Characters)
聲明(Declarations)
自動引用計數(shù)
Swift 里的值類型與引用類型
表達(dá)式(Expressions)
Swift 文檔修訂歷史
造個類型不是夢-白話 Swift 類型創(chuàng)建
歡迎使用 Swift
詞法結(jié)構(gòu)(Lexical Structure)
集合類型(Collection Types)
下標(biāo)
方法(Methods)
可選鏈?zhǔn)秸{(diào)用
版本兼容性
類型轉(zhuǎn)換
構(gòu)造過程
The Swift Programming Language 中文版
函數(shù)(Functions)
Swift 教程
控制流(Control Flow)

訪問控制


1.0 翻譯:JaceFu 校對:ChildhoodAndy

2.0 翻譯+校對:mmoaay

2.1 翻譯:Prayer 校對:shanks,2015-11-01

2.2 翻譯+校對:SketchK 2016-05-17

3.0.1 翻譯+校對: shanks,2016-11-13

4.0 翻譯:kemchenj,2017-09-23

4.1 翻譯+校對:mylittleswift

本頁內(nèi)容包括:

訪問控制可以限定其它源文件或模塊中的代碼對你的代碼的訪問級別。這個特性可以讓我們隱藏代碼的一些實(shí)現(xiàn)細(xì)節(jié),并且可以為其他人可以訪問和使用的代碼提供接口。

你可以明確地給單個類型(類、結(jié)構(gòu)體、枚舉)設(shè)置訪問級別,也可以給這些類型的屬性、方法、構(gòu)造器、下標(biāo)等設(shè)置訪問級別。協(xié)議也可以被限定在一定的范圍內(nèi)使用,包括協(xié)議里的全局常量、變量和函數(shù)。

Swift 不僅提供了多種不同的訪問級別,還為某些典型場景提供了默認(rèn)的訪問級別,這樣就不需要我們在每段代碼中都申明顯式訪問級別。其實(shí),如果只是開發(fā)一個單一 target 的應(yīng)用程序,我們完全可以不用顯式聲明代碼的訪問級別。

注意

為了簡單起見,對于代碼中可以設(shè)置訪問級別的特性(屬性、基本類型、函數(shù)等),在下面的章節(jié)中我們會稱之為“實(shí)體”。

模塊和源文件

Swift 中的訪問控制模型基于模塊和源文件這兩個概念。

模塊指的是獨(dú)立的代碼單元,框架或應(yīng)用程序會作為一個獨(dú)立的模塊來構(gòu)建和發(fā)布。在 Swift 中,一個模塊可以使用 import 關(guān)鍵字導(dǎo)入另外一個模塊。

在 Swift 中,Xcode 的每個 target(例如框架或應(yīng)用程序)都被當(dāng)作獨(dú)立的模塊處理。如果你是為了實(shí)現(xiàn)某個通用的功能,或者是為了封裝一些常用方法而將代碼打包成獨(dú)立的框架,這個框架就是 Swift 中的一個模塊。當(dāng)它被導(dǎo)入到某個應(yīng)用程序或者其他框架時,框架內(nèi)容都將屬于這個獨(dú)立的模塊。

源文件就是 Swift 中的源代碼文件,它通常屬于一個模塊,即一個應(yīng)用程序或者框架。盡管我們一般會將不同的類型分別定義在不同的源文件中,但是同一個源文件也可以包含多個類型、函數(shù)之類的定義。

訪問級別

Swift 為代碼中的實(shí)體提供了五種不同的訪問級別。這些訪問級別不僅與源文件中定義的實(shí)體相關(guān),同時也與源文件所屬的模塊相關(guān)。

  • OpenPublic 級別可以讓實(shí)體被同一模塊源文件中的所有實(shí)體訪問,在模塊外也可以通過導(dǎo)入該模塊來訪問源文件里的所有實(shí)體。通常情況下,你會使用 Open 或 Public 級別來指定框架的外部接口。Open 和 Public 的區(qū)別在后面會提到。
  • Internal 級別讓實(shí)體被同一模塊源文件中的任何實(shí)體訪問,但是不能被模塊外的實(shí)體訪問。通常情況下,如果某個接口只在應(yīng)用程序或框架內(nèi)部使用,就可以將其設(shè)置為 Internal 級別。
  • File-private 限制實(shí)體只能在其定義的文件內(nèi)部訪問。如果功能的部分細(xì)節(jié)只需要在文件內(nèi)使用時,可以使用 File-private 來將其隱藏。
  • Private 限制實(shí)體只能在其定義的作用域,以及同一文件內(nèi)的 extension 訪問。如果功能的部分細(xì)節(jié)只需要在當(dāng)前作用域內(nèi)使用時,可以使用 Private 來將其隱藏。

Open 為最高訪問級別(限制最少),Private 為最低訪問級別(限制最多)。

Open 只能作用于類和類的成員,它和 Public 的區(qū)別如下:

  • Public 或者其它更嚴(yán)訪問級別的類,只能在其定義的模塊內(nèi)部被繼承。
  • Public 或者其它更嚴(yán)訪問級別的類成員,只能在其定義的模塊內(nèi)部的子類中重寫。
  • Open 的類,可以在其定義的模塊中被繼承,也可以在引用它的模塊中被繼承。
  • Open 的類成員,可以在其定義的模塊中子類中重寫,也可以在引用它的模塊中的子類重寫。

把一個類標(biāo)記為 open,明確的表示你已經(jīng)充分考慮過外部模塊使用此類作為父類的影響,并且設(shè)計好了你的類的代碼了。

訪問級別基本原則

Swift 中的訪問級別遵循一個基本原則:不可以在某個實(shí)體中定義訪問級別更低(更嚴(yán)格)的實(shí)體。

例如:

  • 一個 Public 的變量,其類型的訪問級別不能是 Internal,F(xiàn)ile-private 或是 Private。因為無法保證變量的類型在使用變量的地方也具有訪問權(quán)限。
  • 函數(shù)的訪問級別不能高于它的參數(shù)類型和返回類型的訪問級別。因為這樣就會出現(xiàn)函數(shù)可以在任何地方被訪問,但是它的參數(shù)類型和返回類型卻不可以的情況。

關(guān)于此原則在各種情況下的具體表現(xiàn),將在下文有所體現(xiàn)。

默認(rèn)訪問級別

如果你沒有為代碼中的實(shí)體顯式指定訪問級別,那么它們默認(rèn)為 internal 級別(有一些例外情況,稍后會進(jìn)行說明)。因此,在大多數(shù)情況下,我們不需要顯式指定實(shí)體的訪問級別。

單 target 應(yīng)用程序的訪問級別

當(dāng)你編寫一個單目標(biāo)應(yīng)用程序時,應(yīng)用的所有功能都是為該應(yīng)用服務(wù),而不需要提供給其他應(yīng)用或者模塊使用,所以我們不需要明確設(shè)置訪問級別,使用默認(rèn)的訪問級別 Internal 即可。但是,你也可以使用 fileprivate 訪問或 private 訪問級別,用于隱藏一些功能的實(shí)現(xiàn)細(xì)節(jié)。

框架的訪問級別

當(dāng)你開發(fā)框架時,就需要把一些對外的接口定義為 Open 或 Public,以便使用者導(dǎo)入該框架后可以正常使用其功能。這些被你定義為對外的接口,就是這個框架的 API。

注意

框架依然會使用默認(rèn)的 internal ,也可以指定為 fileprivate 訪問或者 private 訪問級別。當(dāng)你想把某個實(shí)體作為框架的 API 的時候,需顯式為其指定開放訪問或公開訪問級別。

單元測試 target 的訪問級別

當(dāng)你的應(yīng)用程序包含單元測試 target 時,為了測試,測試模塊需要訪問應(yīng)用程序模塊中的代碼。默認(rèn)情況下只有 openpublic 級別的實(shí)體才可以被其他模塊訪問。然而,如果在導(dǎo)入應(yīng)用程序模塊的語句前使用 @testable 特性,然后在允許測試的編譯設(shè)置(Build Options -> Enable Testability)下編譯這個應(yīng)用程序模塊,單元測試目標(biāo)就可以訪問應(yīng)用程序模塊中所有內(nèi)部級別的實(shí)體。

訪問控制語法

通過修飾符 openpublic,internalfileprivate,private 來聲明實(shí)體的訪問級別:

public class SomePublicClass {}
internal class SomeInternalClass {}
fileprivate class SomeFilePrivateClass {}
private class SomePrivateClass {}

public var somePublicVariable = 0
internal let someInternalConstant = 0
fileprivate func someFilePrivateFunction() {}
private func somePrivateFunction() {}

除非專門指定,否則實(shí)體默認(rèn)的訪問級別為 internal,可以查閱默認(rèn)訪問級別這一節(jié)。這意味著在不使用修飾符顯式聲明訪問級別的情況下,SomeInternalClasssomeInternalConstant 仍然擁有隱式的 internal

class SomeInternalClass {}   // 隱式 internal
var someInternalConstant = 0 // 隱式 internal

自定義類型

如果想為一個自定義類型指定訪問級別,在定義類型時進(jìn)行指定即可。新類型只能在它的訪問級別限制范圍內(nèi)使用。例如,你定義了一個 fileprivate 級別的類,那這個類就只能在定義它的源文件中使用,可以作為屬性類型、函數(shù)參數(shù)類型或者返回類型,等等。

一個類型的訪問級別也會影響到類型成員(屬性、方法、構(gòu)造器、下標(biāo))的默認(rèn)訪問級別。如果你將類型指定為 private 或者 fileprivate 級別,那么該類型的所有成員的默認(rèn)訪問級別也會變成 private 或者 fileprivate 級別。如果你將類型指定為公開或者 internal (或者不明確指定訪問級別,而使用默認(rèn)的 internal ),那么該類型的所有成員的默認(rèn)訪問級別將是內(nèi)部訪問。

重點(diǎn)

上面提到,一個 public 類型的所有成員的訪問級別默認(rèn)為 internal 級別,而不是 public 級別。如果你想將某個成員指定為 public 級別,那么你必須顯式指定。這樣做的好處是,在你定義公共接口的時候,可以明確地選擇哪些接口是需要公開的,哪些是內(nèi)部使用的,避免不小心將內(nèi)部使用的接口公開。

public class SomePublicClass {                  // 顯式 public 類
    public var somePublicProperty = 0            // 顯式 public 類成員
    var someInternalProperty = 0                 // 隱式 internal 類成員
    fileprivate func someFilePrivateMethod() {}  // 顯式 fileprivate 類成員
    private func somePrivateMethod() {}          // 顯式 private 類成員
}

class SomeInternalClass {                       // 隱式 internal 類
    var someInternalProperty = 0                 // 隱式 internal 類成員
    fileprivate func someFilePrivateMethod() {}  // 顯式 fileprivate 類成員
    private func somePrivateMethod() {}          // 顯式 private 類成員
}

fileprivate class SomeFilePrivateClass {        // 顯式 fileprivate 類
    func someFilePrivateMethod() {}              // 隱式 fileprivate 類成員
    private func somePrivateMethod() {}          // 顯式 private 類成員
}

private class SomePrivateClass {                // 顯式 private 類
    func somePrivateMethod() {}                  // 隱式 private 類成員
}

```swift
<a name="tuple_types"></a>
### 元組類型

元組的訪問級別將由元組中訪問級別最嚴(yán)格的類型來決定。例如,如果你構(gòu)建了一個包含兩種不同類型的元組,其中一個類型為 `internal`,另一個類型為 `private`,那么這個元組的訪問級別為 `private`。

> 注意
> 
> 元組不同于類、結(jié)構(gòu)體、枚舉、函數(shù)那樣有單獨(dú)的定義。元組的訪問級別是在它被使用時自動推斷出的,而無法明確指定。

<a name="function_types"></a>
### 函數(shù)類型

函數(shù)的訪問級別根據(jù)訪問級別最嚴(yán)格的參數(shù)類型或返回類型的訪問級別來決定。但是,如果這種訪問級別不符合函數(shù)定義所在環(huán)境的默認(rèn)訪問級別,那么就需要明確地指定該函數(shù)的訪問級別。

下面的例子定義了一個名為 `someFunction()` 的全局函數(shù),并且沒有明確地指定其訪問級別。也許你會認(rèn)為該函數(shù)應(yīng)該擁有默認(rèn)的訪問級別 `internal`,但事實(shí)并非如此。事實(shí)上,如果按下面這種寫法,代碼將無法通過編譯:

```swift
func someFunction() -> (SomeInternalClass, SomePrivateClass) {
    // 此處是函數(shù)實(shí)現(xiàn)部分
}

我們可以看到,這個函數(shù)的返回類型是一個元組,該元組中包含兩個自定義的類(可查閱自定義類型)。其中一個類的訪問級別是 internal,另一個的訪問級別是 private,所以根據(jù)元組訪問級別的原則,該元組的訪問級別是 private(元組的訪問級別與元組中訪問級別最低的類型一致)。

因為該函數(shù)返回類型的訪問級別是 private,所以你必須使用 private 修飾符,明確指定該函數(shù)的訪問級別:

private func someFunction() -> (SomeInternalClass, SomePrivateClass) {
    // 此處是函數(shù)實(shí)現(xiàn)部分
}

將該函數(shù)指定為 publicinternal,或者使用默認(rèn)的訪問級別 internal 都是錯誤的,因為如果把該函數(shù)當(dāng)做 publicinternal 級別來使用的話,可能會無法訪問 private 級別的返回值。

枚舉類型

枚舉成員的訪問級別和該枚舉類型相同,你不能為枚舉成員單獨(dú)指定不同的訪問級別。

比如下面的例子,枚舉 CompassPoint 被明確指定為 public,那么它的成員 North、SouthEast、West 的訪問級別同樣也是 public

public enum CompassPoint {
    case North
    case South
    case East
    case West
}

原始值和關(guān)聯(lián)值

枚舉定義中的任何原始值或關(guān)聯(lián)值的類型的訪問級別至少不能低于枚舉類型的訪問級別。例如,你不能在一個 internal 的枚舉中定義 private 的原始值類型。

嵌套類型

如果在 private 的類型中定義嵌套類型,那么該嵌套類型就自動擁有 private 訪問級別。如果在 public 或者 internal 級別的類型中定義嵌套類型,那么該嵌套類型自動擁有 internal 訪問級別。如果想讓嵌套類型擁有 public 訪問級別,那么需要明確指定該嵌套類型的訪問級別。

子類

子類的訪問級別不得高于父類的訪問級別。例如,父類的訪問級別是 internal,子類的訪問級別就不能是 public。

此外,你可以在符合當(dāng)前訪問級別的條件下重寫任意類成員(方法、屬性、構(gòu)造器、下標(biāo)等)。

可以通過重寫為繼承來的類成員提供更高的訪問級別。下面的例子中,類 A 的訪問級別是 public,它包含一個方法 someMethod(),訪問級別為 private。類 B 繼承自類 A,訪問級別為 internal,但是在類 B 中重寫了類 A 中訪問級別為 private 的方法 someMethod(),并重新指定為 internal 級別。通過這種方式,我們就可以將某類中 private 級別的類成員重新指定為更高的訪問級別,以便其他人使用:

public class A {
    private func someMethod() {}
}

internal class B: A {
    override internal func someMethod() {}
}

我們甚至可以在子類中,用子類成員去訪問訪問級別更低的父類成員,只要這一操作在相應(yīng)訪問級別的限制范圍內(nèi)(也就是說,在同一源文件中訪問父類 private 級別的成員,在同一模塊內(nèi)訪問父類 internal 級別的成員):

public class A {
    private func someMethod() {}
}

internal class B: A {
    override internal func someMethod() {
        super.someMethod()
    }
}

因為父類 A 和子類 B 定義在同一個源文件中,所以在子類 B 可以在重寫的 someMethod() 方法中調(diào)用 super.someMethod()

常量、變量、屬性、下標(biāo)

常量、變量、屬性不能擁有比它們的類型更高的訪問級別。例如,你不能定義一個 public 級別的屬性,但是它的類型卻是 private 級別的。同樣,下標(biāo)也不能擁有比索引類型或返回類型更高的訪問級別。

如果常量、變量、屬性、下標(biāo)的類型是 private 級別的,那么它們必須明確指定訪問級別為 private

private var privateInstance = SomePrivateClass()

Getter 和 Setter

常量、變量、屬性、下標(biāo)的 GettersSetters 的訪問級別和它們所屬類型的訪問級別相同。

Setter 的訪問級別可以低于對應(yīng)的 Getter 的訪問級別,這樣就可以控制變量、屬性或下標(biāo)的讀寫權(quán)限。在 varsubscript 關(guān)鍵字之前,你可以通過 fileprivate(set)private(set)internal(set) 為它們的寫入權(quán)限指定更低的訪問級別。

注意

這個規(guī)則同時適用于存儲型屬性和計算型屬性。即使你不明確指定存儲型屬性的 GetterSetter,Swift 也會隱式地為其創(chuàng)建 GetterSetter,用于訪問該屬性的后備存儲。使用 fileprivate(set),private(set)internal(set) 可以改變 Setter 的訪問級別,這對計算型屬性也同樣適用。

下面的例子中定義了一個名為 TrackedString 的結(jié)構(gòu)體,它記錄了 value 屬性被修改的次數(shù):

struct TrackedString {
    private(set) var numberOfEdits = 0
    var value: String = "" {
        didSet {
            numberOfEdits += 1
        }
    }
}

TrackedString 結(jié)構(gòu)體定義了一個用于存儲 String 值的屬性 value,并將初始值設(shè)為 ""(一個空字符串)。該結(jié)構(gòu)體還定義了另一個用于存儲 Int 值的屬性 numberOfEdits,它用于記錄屬性 value 被修改的次數(shù)。這個功能通過屬性 valuedidSet 觀察器實(shí)現(xiàn),每當(dāng)給 value 賦新值時就會調(diào)用 didSet 方法,然后將 numberOfEdits 的值加一。

結(jié)構(gòu)體 TrackedString 和它的屬性 value 都沒有顯式地指定訪問級別,所以它們都是用默認(rèn)的訪問級別 internal。但是該結(jié)構(gòu)體的 numberOfEdits 屬性使用了 private(set) 修飾符,這意味著 numberOfEdits 屬性只能在結(jié)構(gòu)體的定義中進(jìn)行賦值。numberOfEdits 屬性的 Getter 依然是默認(rèn)的訪問級別 internal,但是 Setter 的訪問級別是 private,這表示該屬性只能在內(nèi)部修改,而在結(jié)構(gòu)體的外部則表現(xiàn)為一個只讀屬性。

如果你實(shí)例化 TrackedString 結(jié)構(gòu)體,并多次對 value 屬性的值進(jìn)行修改,你就會看到 numberOfEdits 的值會隨著修改次數(shù)而變化:

var stringToEdit = TrackedString()
stringToEdit.value = "This string will be tracked."
stringToEdit.value += " This edit will increment numberOfEdits."
stringToEdit.value += " So will this one."
print("The number of edits is \(stringToEdit.numberOfEdits)")
// 打印 “The number of edits is 3”

雖然你可以在其他的源文件中實(shí)例化該結(jié)構(gòu)體并且獲取到 numberOfEdits 屬性的值,但是你不能對其進(jìn)行賦值。這一限制保護(hù)了該記錄功能的實(shí)現(xiàn)細(xì)節(jié),同時還提供了方便的訪問方式。

你可以在必要時為 GetterSetter 顯式指定訪問級別。下面的例子將 TrackedString 結(jié)構(gòu)體明確指定為了 public 訪問級別。結(jié)構(gòu)體的成員(包括 numberOfEdits 屬性)擁有默認(rèn)的訪問級別 internal。你可以結(jié)合 publicprivate(set) 修飾符把結(jié)構(gòu)體中的 numberOfEdits 屬性的 Getter 的訪問級別設(shè)置為 public,而 Setter 的訪問級別設(shè)置為 private

public struct TrackedString {
    public private(set) var numberOfEdits = 0
    public var value: String = "" {
        didSet {
            numberOfEdits += 1
        }
    }
    public init() {}
}

構(gòu)造器

自定義構(gòu)造器的訪問級別可以低于或等于其所屬類型的訪問級別。唯一的例外是必要構(gòu)造器,它的訪問級別必須和所屬類型的訪問級別相同。

如同函數(shù)或方法的參數(shù),構(gòu)造器參數(shù)的訪問級別也不能低于構(gòu)造器本身的訪問級別。

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

默認(rèn)構(gòu)造器所述,Swift 會為結(jié)構(gòu)體和類提供一個默認(rèn)的無參數(shù)的構(gòu)造器,只要它們?yōu)樗写鎯π蛯傩栽O(shè)置了默認(rèn)初始值,并且未提供自定義的構(gòu)造器。

默認(rèn)構(gòu)造器的訪問級別與所屬類型的訪問級別相同,除非類型的訪問級別是 public。如果一個類型被指定為 public 級別,那么默認(rèn)構(gòu)造器的訪問級別將為 internal。如果你希望一個 public 級別的類型也能在其他模塊中使用這種無參數(shù)的默認(rèn)構(gòu)造器,你只能自己提供一個 public 訪問級別的無參數(shù)構(gòu)造器。

結(jié)構(gòu)體默認(rèn)的成員逐一構(gòu)造器

如果結(jié)構(gòu)體中任意存儲型屬性的訪問級別為 private,那么該結(jié)構(gòu)體默認(rèn)的成員逐一構(gòu)造器的訪問級別就是 private。否則,這種構(gòu)造器的訪問級別依然是 internal。

如同前面提到的默認(rèn)構(gòu)造器,如果你希望一個 public 級別的結(jié)構(gòu)體也能在其他模塊中使用其默認(rèn)的成員逐一構(gòu)造器,你依然只能自己提供一個 public 訪問級別的成員逐一構(gòu)造器。

協(xié)議

如果想為一個協(xié)議類型明確地指定訪問級別,在定義協(xié)議時指定即可。這將限制該協(xié)議只能在適當(dāng)?shù)脑L問級別范圍內(nèi)被采納。

協(xié)議中的每一個要求都具有和該協(xié)議相同的訪問級別。你不能將協(xié)議中的要求設(shè)置為其他訪問級別。這樣才能確保該協(xié)議的所有要求對于任意采納者都將可用。

注意

如果你定義了一個 public 訪問級別的協(xié)議,那么該協(xié)議的所有實(shí)現(xiàn)也會是 public 訪問級別。這一點(diǎn)不同于其他類型,例如,當(dāng)類型是 public 訪問級別時,其成員的訪問級別卻只是 internal。

協(xié)議繼承

如果定義了一個繼承自其他協(xié)議的新協(xié)議,那么新協(xié)議擁有的訪問級別最高也只能和被繼承協(xié)議的訪問級別相同。例如,你不能將繼承自 internal 協(xié)議的新協(xié)議定義為 public 協(xié)議。

協(xié)議一致性

一個類型可以采納比自身訪問級別低的協(xié)議。例如,你可以定義一個 public 級別的類型,它可以在其他模塊中使用,同時它也可以采納一個 internal 級別的協(xié)議,但是只能在該協(xié)議所在的模塊中作為符合該協(xié)議的類型使用。

采納了協(xié)議的類型的訪問級別取它本身和所采納協(xié)議兩者間最低的訪問級別。也就是說如果一個類型是 public 級別,采納的協(xié)議是 internal 級別,那么采納了這個協(xié)議后,該類型作為符合協(xié)議的類型時,其訪問級別也是 internal。

如果你采納了協(xié)議,那么實(shí)現(xiàn)了協(xié)議的所有要求后,你必須確保這些實(shí)現(xiàn)的訪問級別不能低于協(xié)議的訪問級別。例如,一個 public 級別的類型,采納了 internal 級別的協(xié)議,那么協(xié)議的實(shí)現(xiàn)至少也得是 internal 級別。

注意

Swift 和 Objective-C 一樣,協(xié)議的一致性是全局的,也就是說,在同一程序中,一個類型不可能用兩種不同的方式實(shí)現(xiàn)同一個協(xié)議。

Extension

Extension 可以在訪問級別允許的情況下對類、結(jié)構(gòu)體、枚舉進(jìn)行擴(kuò)展。Extension 的成員具有和原始類型成員一致的訪問級別。例如,你使用 extension 擴(kuò)展了一個 public 或者 internal 類型,extension 中的成員就默認(rèn)使用 internal 訪問級別,和原始類型中的成員一致。如果你使用 extension 擴(kuò)展了一個 private 類型,則 extension 的成員默認(rèn)使用 private 訪問級別。

或者,你可以明確指定 extension 的訪問級別(例如,private extension),從而給該 extension 中的所有成員指定一個新的默認(rèn)訪問級別。這個新的默認(rèn)訪問級別仍然可以被單獨(dú)指定的訪問級別所覆蓋。

如果你使用 extension 來遵循協(xié)議的話,就不能顯式地聲明 extension 的訪問級別。extension 每個 protocol 要求的實(shí)現(xiàn)都默認(rèn)使用 protocol 的訪問級別。

Extension 的私有成員

擴(kuò)展同一文件內(nèi)的類,結(jié)構(gòu)體或者枚舉,extension 里的代碼會表現(xiàn)得跟聲明在原類型里的一模一樣。也就是說你可以這樣:

  • 在類型的聲明里聲明一個私有成員,在同一文件的 extension 里訪問。
  • 在 extension 里聲明一個私有成員,在同一文件的另一個 extension 里訪問。
  • 在 extension 里聲明一個私有成員,在同一文件的類型聲明里訪問。

這意味著你可以像組織的代碼去使用 extension,而且不受私有成員的影響。例如,給定下面這樣一個簡單的協(xié)議:

protocol SomeProtocol {
    func doSomething() {}
}

你可以使用 extension 來遵守協(xié)議,就想這樣:

struct SomeStruct {
    private var privateVariable = 12
}

extension SomeStruct: SomeProtocol {
    func doSomething() {
        print(privateVariable)
    }
}

泛型

泛型類型或泛型函數(shù)的訪問級別取決于泛型類型或泛型函數(shù)本身的訪問級別,還需結(jié)合類型參數(shù)的類型約束的訪問級別,根據(jù)這些訪問級別中的最低訪問級別來確定。

類型別名

你定義的任何類型別名都會被當(dāng)作不同的類型,以便于進(jìn)行訪問控制。類型別名的訪問級別不可高于其表示的類型的訪問級別。例如,private 級別的類型別名可以作為 private、file-private、internal、public 或者 open 類型的別名,但是 public 級別的類型別名只能作為 public 類型的別名,不能作為 internal、file-privateprivate 類型的別名。

注意

這條規(guī)則也適用于為滿足協(xié)議一致性而將類型別名用于關(guān)聯(lián)類型的情況。

上一篇:特性(Attributes)下一篇:Swift 教程