25_訪問控制

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

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

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

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

模塊和源文件

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

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

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

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

訪問級別

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

  • OpenPublic 級別可以讓實體被同一模塊源文件中的所有實體訪問簸州,在模塊外也可以通過導(dǎo)入該模塊來訪問源文件里的所有實體鉴竭。通常情況下歧譬,你會使用 Open 或 Public 級別來指定框架的外部接口。Open 和 Public 的區(qū)別在后面會提到搏存。
  • Internal 級別讓實體被同一模塊源文件中的任何實體訪問瑰步,但是不能被模塊外的實體訪問。通常情況下璧眠,如果某個接口只在應(yīng)用程序或框架內(nèi)部使用缩焦,就可以將其設(shè)置為 Internal 級別。
  • File-private 限制實體只能在其定義的文件內(nèi)部訪問责静。如果功能的部分細節(jié)只需要在文件內(nèi)使用時袁滥,可以使用 File-private 來將其隱藏。
  • Private 限制實體只能在其定義的作用域灾螃,以及同一文件內(nèi)的 extension 訪問呻拌。如果功能的部分細節(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 中的訪問級別遵循一個基本原則:不可以在某個實體中定義訪問級別更低(更嚴(yán)格)的實體

例如:

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

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

默認(rèn)訪問級別

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

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

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

框架的訪問級別

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

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

單元測試 target 的訪問級別

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

訪問控制語法

通過修飾符 open斜筐,public龙致,internalfileprivate顷链,private 來聲明實體的訪問級別:

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() {}

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

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

自定義類型

如果想為一個自定義類型指定訪問級別榛了,在定義類型時進行指定即可在讶。新類型只能在它的訪問級別限制范圍內(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)部訪問捎废。

重要
上面提到笑窜,一個 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 類成員
}

元組類型

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

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

函數(shù)類型

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

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

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

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

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

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

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

枚舉類型

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

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 觀察器實現(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)體的定義中進行賦值甜滨。numberOfEdits 屬性的 Getter 依然是默認(rèn)的訪問級別 internal乐严,但是 Setter 的訪問級別是 private,這表示該屬性只能在內(nèi)部修改衣摩,而在結(jié)構(gòu)體的外部則表現(xiàn)為一個只讀屬性昂验。

如果你實例化 TrackedString 結(jié)構(gòu)體,并多次對 value 屬性的值進行修改艾扮,你就會看到 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”

雖然你可以在其他的源文件中實例化該結(jié)構(gòu)體并且獲取到 numberOfEdits 屬性的值既琴,但是你不能對其進行賦值。這一限制保護了該記錄功能的實現(xiàn)細節(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)造器

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é)議的所有實現(xiàn)也會是 public 訪問級別涎永。這一點不同于其他類型,例如鹿响,當(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é)議很魂,那么實現(xiàn)了協(xié)議的所有要求后爬骤,你必須確保這些實現(xiàn)的訪問級別不能低于協(xié)議的訪問級別。例如莫换,一個 public 級別的類型霞玄,采納了 internal 級別的協(xié)議,那么協(xié)議的實現(xiàn)至少也得是 internal 級別拉岁。

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

Extension

Extension 可以在訪問級別允許的情況下對類陵叽、結(jié)構(gòu)體狞尔、枚舉進行擴展。Extension 的成員具有和原始類型成員一致的訪問級別巩掺。例如偏序,你使用 extension 擴展了一個 public 或者 internal 類型,extension 中的成員就默認(rèn)使用 internal 訪問級別胖替,和原始類型中的成員一致研儒。如果你使用 extension 擴展了一個 private 類型,則 extension 的成員默認(rèn)使用 private 訪問級別独令。

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

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

Extension 的私有成員

擴展同一文件內(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)作不同的類型量瓜,以便于進行訪問控制司恳。類型別名的訪問級別不可高于其表示的類型的訪問級別。例如绍傲,private 級別的類型別名可以作為 private扔傅,file-privateinternal烫饼,public或者open類型的別名猎塞,但是 public 級別的類型別名只能作為 public 類型的別名,不能作為 internal杠纵,file-private荠耽,或 private 類型的別名。

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

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末骇塘,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子韩容,更是在濱河造成了極大的恐慌,老刑警劉巖唐瀑,帶你破解...
    沈念sama閱讀 206,214評論 6 481
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件群凶,死亡現(xiàn)場離奇詭異,居然都是意外死亡哄辣,警方通過查閱死者的電腦和手機请梢,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,307評論 2 382
  • 文/潘曉璐 我一進店門赠尾,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人毅弧,你說我怎么就攤上這事气嫁。” “怎么了够坐?”我有些...
    開封第一講書人閱讀 152,543評論 0 341
  • 文/不壞的土叔 我叫張陵寸宵,是天一觀的道長。 經(jīng)常有香客問我元咙,道長梯影,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 55,221評論 1 279
  • 正文 為了忘掉前任庶香,我火速辦了婚禮甲棍,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘赶掖。我一直安慰自己感猛,他們只是感情好,可當(dāng)我...
    茶點故事閱讀 64,224評論 5 371
  • 文/花漫 我一把揭開白布奢赂。 她就那樣靜靜地躺著陪白,像睡著了一般。 火紅的嫁衣襯著肌膚如雪呈驶。 梳的紋絲不亂的頭發(fā)上拷泽,一...
    開封第一講書人閱讀 49,007評論 1 284
  • 那天,我揣著相機與錄音袖瞻,去河邊找鬼司致。 笑死,一個胖子當(dāng)著我的面吹牛聋迎,可吹牛的內(nèi)容都是我干的脂矫。 我是一名探鬼主播,決...
    沈念sama閱讀 38,313評論 3 399
  • 文/蒼蘭香墨 我猛地睜開眼霉晕,長吁一口氣:“原來是場噩夢啊……” “哼庭再!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起牺堰,我...
    開封第一講書人閱讀 36,956評論 0 259
  • 序言:老撾萬榮一對情侶失蹤拄轻,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后伟葫,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體恨搓,經(jīng)...
    沈念sama閱讀 43,441評論 1 300
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 35,925評論 2 323
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了斧抱。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片常拓。...
    茶點故事閱讀 38,018評論 1 333
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖辉浦,靈堂內(nèi)的尸體忽然破棺而出弄抬,到底是詐尸還是另有隱情,我是刑警寧澤宪郊,帶...
    沈念sama閱讀 33,685評論 4 322
  • 正文 年R本政府宣布掂恕,位于F島的核電站,受9級特大地震影響废膘,放射性物質(zhì)發(fā)生泄漏竹海。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點故事閱讀 39,234評論 3 307
  • 文/蒙蒙 一丐黄、第九天 我趴在偏房一處隱蔽的房頂上張望斋配。 院中可真熱鬧,春花似錦灌闺、人聲如沸艰争。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,240評論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽甩卓。三九已至,卻和暖如春蕉斜,著一層夾襖步出監(jiān)牢的瞬間逾柿,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 31,464評論 1 261
  • 我被黑心中介騙來泰國打工宅此, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留机错,地道東北人。 一個月前我還...
    沈念sama閱讀 45,467評論 2 352
  • 正文 我出身青樓父腕,卻偏偏與公主長得像弱匪,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子璧亮,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 42,762評論 2 345

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