1. 程式人生 > 其它 >Swift文件Chapter 25 訪問控制

Swift文件Chapter 25 訪問控制

訪問控制可以限定其它原始檔或模組中的程式碼對你的程式碼的訪問級別。

模組和原始檔

模組指的是獨立的程式碼單元,框架或應用程式會作為一個獨立的模組來構建和釋出。在Swift中,一個模組可以使用import關鍵字匯入另外一個模組。
原始檔就是Swift中的原始碼檔案,它通常屬於一個模組,即一個應用程式或者框架。儘管我們一般會將不同的型別分別定義在不同的原始檔中,但是同一個原始檔也可以包含多個型別、函式之類的定義。

訪問級別

Swift提供了5種訪問級別:

  • OpenPublic:讓實體被同一模組原始檔中的所有實體訪問,在模組外也可以通過匯入該模組來訪問原始檔裡的所有實體。一般用來指定外部介面
  • Internal
    :實體被同一模組原始檔中的任何實體訪問,但是不能被模組外的實體訪問。一般指定只在模組內使用的介面。
  • File-private:實體只能在其定義的檔案內部訪問。功能的部分細節只需要在檔案內使用。
  • Private:實體只能在其定義的作用域,以及同一檔案內的extension訪問。功能的部分細節只需要在當前作用域內使用。

Open只能作用於類和類的成員,它和Public的區別如下:

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

訪問級別基本原則

基本原則:實體不能定義在具有更低訪問級別(更嚴格)的實體中。

預設訪問級別

如果你沒有為程式碼中的實體顯式指定訪問級別,那麼它們預設為internal級別。

單target應用程式的訪問級別

當你編寫一個單目標應用程式時,應用的所有功能都是為該應用服務,而不需要提供給其他應用或者模組使用,所以我們不需要明確設定訪問級別,使用預設的訪問級別internal即可。

框架的訪問級別

開發框架時,就需要把一些對外的介面定義為Open或Public,以便使用者匯入該框架後可以正常使用其功能。這些被你定義為對外的介面,就是這個框架的API。

單元測試target的訪問級別

當你的應用程式包含單元測試target時,為了測試,測試模組需要訪問應用程式模組中的程式碼。預設情況下只有open或public級別的實體才可以被其他模組訪問。然而,如果在匯入應用程式模組的語句前使用@testable特性,然後在允許測試的編譯設定(Build Options -> Enable Testability)下編譯這個應用程式模組,單元測試目標就可以訪問應用程式模組中所有內部級別的實體。

訪問控制語法

通過修飾符openpublicinternalfileprivateprivate來宣告實體的訪問級別。除非專門指定,否則實體預設的訪問級別為internal

自定義型別

如果想為一個自定義型別指定訪問級別,在定義型別時進行指定即可。新型別只能在它的訪問級別限制範圍內使用。一個型別的訪問級別也會影響到型別成員(屬性、方法、構造器、下標)的預設訪問級別。如果你將型別指定為private或者fileprivate級別,那麼該型別的所有成員的預設訪問級別也會變成private或者fileprivate級別。如果你將型別指定為internalpublic(或者不明確指定訪問級別,而使用預設的internal),那麼該型別的所有成員的預設訪問級別將是internal

元組型別

元組的訪問級別將由元組中訪問級別最嚴格的型別來決定。

函式型別

函式的訪問級別根據訪問級別最嚴格的引數型別或返回型別的訪問級別來決定。如果這種訪問級別不符合函式定義所在環境的預設訪問級別,那麼就需要明確地指定該函式的訪問級別。

列舉型別

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

原始值和關聯值

列舉定義中的任何原始值或關聯值的型別的訪問級別至少不能低於列舉型別的訪問級別。

巢狀型別

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

子類

子類的訪問級別不得高於父類的訪問級別。我們甚至可以在子類中,用子類成員去訪問訪問級別更低的父類成員,只要這一操作在相應訪問級別的限制範圍內。

常量、變數、屬性、下標

常量、變數、屬性不能擁有比它們的型別更高的訪問級別。

Getter 和 Setter

常量、變數、屬性、下標的 Getters 和 Setters 的訪問級別和它們所屬型別的訪問級別相同。Setter 的訪問級別可以低於對應的 Getter 的訪問級別,這樣就可以控制變數、屬性或下標的讀寫許可權。在 var 或 subscript 關鍵字之前,你可以通過 fileprivate(set),private(set) 或 internal(set) 為它們的寫入許可權指定更低的訪問級別。

構造器

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

預設構造器

預設構造器的訪問級別與所屬型別的訪問級別相同,除非型別的訪問級別是 public。如果一個型別被指定為 public 級別,那麼預設構造器的訪問級別將為 internal。如果你希望一個public級別的型別也能在其他模組中使用這種無引數的預設構造器,你只能自己提供一個public訪問級別的無引數構造器。

結構體預設的成員逐一構造器

如果結構體中任意儲存型屬性的訪問級別為private,那麼該結構體預設的成員逐一構造器的訪問級別就是private。否則,這種構造器的訪問級別依然是internal

協議

如果想為一個協議型別明確地指定訪問級別,在定義協議時指定即可。這將限制該協議只能在適當的訪問級別範圍內被遵循。
協議中的每一個要求都具有和該協議相同的訪問級別。你不能將協議中的要求設定為其他訪問級別。這樣才能確保該協議的所有要求對於任意遵循者都將可用。

協議繼承

如果定義了一個繼承自其他協議的新協議,那麼新協議擁有的訪問級別最高也只能和被繼承協議的訪問級別相同

協議遵循

一個型別可以遵循比它級別更低的協議。遵循協議時的上下文級別是型別和協議中級別最小的那個。當你編寫或擴充套件一個型別讓它遵循一個協議時,你必須確保該型別對協議的每一個要求的實現,至少與遵循協議的上下文級別一致。

Extension


Extension 可以在訪問級別允許的情況下對類、結構體、列舉進行擴充套件。Extension 的成員具有和原始型別成員一致的訪問級別。
你可以明確指定 extension 的訪問級別,從而給該 extension 中的所有成員指定一個新的預設訪問級別。這個新的預設訪問級別仍然可以被單獨指定的訪問級別所覆蓋。
如果你使用 extension 來遵循協議的話,就不能顯式地宣告 extension 的訪問級別。extension 每個 protocol 要求的實現都預設使用 protocol 的訪問級別。

Extension 的私有成員

擴充套件同一檔案內的類,結構體或者列舉,extension 裡的程式碼會表現得跟宣告在原型別裡的一模一樣。

  • 在型別的聲明裡宣告一個私有成員,在同一檔案的 extension 裡訪問。
  • 在 extension 裡宣告一個私有成員,在同一檔案的另一個 extension 裡訪問。
  • 在 extension 裡宣告一個私有成員,在同一檔案的型別聲明裡訪問。

泛型

泛型型別或泛型函式的訪問級別取決於泛型型別或泛型函式本身的訪問級別,還需結合型別引數的型別約束的訪問級別,根據這些訪問級別中的最低訪問級別來確定。

類型別名

你定義的任何類型別名都會被當作不同的型別,以便於進行訪問控制。類型別名的訪問級別不可高於其表示的型別的訪問級別。