Swift 訪問控制
訪問控制可以限定其他原始檔案或模組中代碼對你代碼的訪問級別。
你可以明確地給單個類型(類、結構體、枚舉)設置訪問級別,也可以給這些類型的屬性、函數、初始化方法、基本類型、下標索引等設置訪問級別。
協議也可以被限定在一定的範圍內使用,包括協議裏的全局常量、變數和函數。
訪問控制基於模組與原始檔案。
模組指的是以獨立單元構建和發佈的 Framework 或 Application。在 Swift 中的一個模組可以使用 import 關鍵字引入另外一個模組。
原始檔案是單個源碼檔,它通常屬於一個模組, 原始檔案可以包含多個類和函數 的定義。
Swift 為代碼中的實體提供了四種不同的訪問級別:public、internal、fileprivate、private。
訪問級別 | 定義 |
---|---|
public | 可以訪問自己模組中原始檔案裏的任何實體,別人也可以通過引入該模組來訪問原始檔案裏的所有實體。 |
internal | 可以訪問自己模組中原始檔案裏的任何實體,但是別人不能訪問該模組中原始檔案裏的實體。 |
fileprivate | 檔內私有,只能在當前原始檔案中使用。 |
private | 只能在類中訪問,離開了這個類或者結構體的作用域外面就無法訪問。 |
public 為最高級訪問級別,private 為最低級訪問級別。
語法
通過修飾符public、internal、fileprivate、private來聲明實體的訪問級別:
實例
除非有特殊的說明,否則實體都使用默認的訪問級別 internal。
未指定訪問級別默認為 internal
函數類型訪問許可權
函數的訪問級別需要根據該函數的參數類型和返回類型的訪問級別得出。
下麵的例子定義了一個名為someFunction全局函數,並且沒有明確地申明其訪問級別。
func someFunction() -> (SomeInternalClass, SomePrivateClass) { // 函數實現 }
函數中其中一個類 SomeInternalClass 的訪問級別是 internal,另一個 SomePrivateClass 的訪問級別是 private。所以根據元組訪問級別的原則,該元組的訪問級別是 private(元組的訪問級別與元組中訪問級別最低的類型一致)。
因為該函數返回類型的訪問級別是 private,所以你必須使用 private 修飾符,明確的聲明該函數:
private func someFunction() -> (SomeInternalClass, SomePrivateClass) { // 函數實現 }
將該函數申明為 public 或 internal,或者使用默認的訪問級別 internal 都是錯誤的,因為如果這樣你就無法訪問 private 級別的返回值。
枚舉類型訪問許可權
枚舉中成員的訪問級別繼承自該枚舉,你不能為枚舉中的成員單獨申明不同的訪問級別。
實例
比如下麵的例子,枚舉 Student 被明確的申明為 public 級別,那麼它的成員 Name,Mark 的訪問級別同樣也是 public:
實例
以上程式執行輸出結果為:
學生成績: 98,97,95
子類訪問許可權
子類的訪問級別不得高於父類的訪問級別。比如說,父類的訪問級別是internal,子類的訪問級別就不能申明為public。
實例
以上程式執行輸出結果為:
超類 子類
常量、變數、屬性、下標訪問許可權
常量、變數、屬性不能擁有比它們的類型更高的訪問級別。
比如說,你定義一個public級別的屬性,但是它的類型是private級別的,這是編譯器所不允許的。
同樣,下標也不能擁有比索引類型或返回類型更高的訪問級別。
如果常量、變數、屬性、下標索引的定義類型是private級別的,那麼它們必須要明確的申明訪問級別為private:
private var privateInstance = SomePrivateClass()
Getter 和 Setter訪問許可權
常量、變數、屬性、下標索引的Getters和Setters的訪問級別繼承自它們所屬成員的訪問級別。
Setter的訪問級別可以低於對應的Getter的訪問級別,這樣就可以控制變數、屬性或下標索引的讀寫許可權。
實例
counter 的訪問級別為 fileprivate,在檔內可以訪問。
以上程式執行輸出結果為:
計數器: 100 新增加數量 100 計數器: 800 新增加數量 700
構造器和默認構造器訪問許可權
初始化
我們可以給自定義的初始化方法申明訪問級別,但是要不高於它所屬類的訪問級別。但必要構造器例外,它的訪問級別必須和所屬類的訪問級別相同。
如同函數或方法參數,初始化方法參數的訪問級別也不能低於初始化方法的訪問級別。
默認初始化方法
Swift為結構體、類都提供了一個默認的無參初始化方法,用於給它們的所有屬性提供賦值操作,但不會給出具體值。
默認初始化方法的訪問級別與所屬類型的訪問級別相同。
實例
在每個子類的 init() 方法前使用 required 關鍵字聲明訪問許可權。
實例
以上程式執行輸出結果為:
10 30 10
協議訪問許可權
如果想為一個協議明確的申明訪問級別,那麼需要注意一點,就是你要確保該協議只在你申明的訪問級別作用域中使用。
如果你定義了一個public訪問級別的協議,那麼實現該協議提供的必要函數也會是public的訪問級別。這一點不同於其他類型,比如,public訪問級別的其他類型,他們成員的訪問級別為internal。
實例
以上程式執行輸出結果為:
res is: 20 res is: 30 res is: 50
擴展訪問許可權
你可以在條件允許的情況下對類、結構體、枚舉進行擴展。擴展成員應該具有和原始類成員一致的訪問級別。比如你擴展了一個公共類型,那麼你新加的成員應該具有和原始成員一樣的默認的internal訪問級別。
或者,你可以明確申明擴展的訪問級別(比如使用private extension)給該擴展內所有成員申明一個新的默認訪問級別。這個新的默認訪問級別仍然可以被單獨成員所申明的訪問級別所覆蓋。
泛型訪問許可權
泛型類型或泛型函數的訪問級別取泛型類型、函數本身、泛型類型參數三者中的最低訪問級別。
實例
以上程式執行輸出結果為:
["Swift"] ["Swift", "泛型"] ["Swift", "泛型", "類型參數"] ["Swift", "泛型", "類型參數", "類型參數名"]
類型別名
任何你定義的類型別名都會被當作不同的類型,以便於進行訪問控制。一個類型別名的訪問級別不可高於原類型的訪問級別。
比如說,一個private級別的類型別名可以設定給一個public、internal、private的類型,但是一個public級別的類型別名只能設定給一個public級別的類型,不能設定給internal或private 級別的類型。
注意:這條規則也適用於為滿足協議一致性而給相關類型命名別名的情況。
實例
以上程式執行輸出結果為:
["Swift"] ["Swift", "泛型"] ["Swift", "泛型", "Where 語句"] ["Swift", "泛型", "Where 語句"]