代碼中各個實體之間的相互訪問是有限制的难衰,不同的實體可能有不同的訪問等級笆怠。不同的訪問等級由不同的關鍵字標識堕虹,比如很多高級語言中的
public
,private
關鍵字虱黄,就標識了不同的訪問等級
Swift 有5種不同的訪問等級余掖,等級越高表示訪問受限性越小。訪問等級從高到低礁鲁,由關鍵字依次表示為:
open
> public
> internal
> fileprivate
> private
。默認的訪問等級是 internal
模塊與源文件
Swift 中實體之間的訪問是基于模塊和源文件的赁豆,所以仅醇,首先了解一下 Swift 的模塊與源文件:
模塊 (
Module
)一個模塊是代碼分布中一個單一的單元。比如一個能被其它模塊通過
import
關鍵字導入的framework
或 程序在 Xcode 中魔种,每一個
Target
都是一個獨立的模塊源文件 (
Source file
)這個很好理解析二,就是你工程里新建的代碼文件
區(qū)分訪問等級
open
,public
open
和public
定義的實體可以被相同Module
中的源文件訪問,也可以通過import
其它Module
,被這些Module
的源文件訪問叶摄。但open
和public
是有區(qū)別的:open
只作用于類和類成員除了
open
属韧,被其它4個關鍵字修飾的類,只能被相同Module
中的其它類繼承除了
open
蛤吓,被其它4個關鍵字修飾的類成員宵喂,只能被相同Module
中的子類重寫open
修飾的類,既可以被相同Module
中的類繼承会傲,又可以被通過import
導入的Module
中的類繼承open
修飾的類成員锅棕,既可以被相同Module
中的子類重寫,又可以被通過import
導入的Module
中的子類重寫internal
internal
定義的實體只能被相同Module
中的源文件訪問淌山,但不能被其它Module
的源文件訪問fileprivate
fileprivate
定義的實體只能在它被定義的源文件中使用裸燎,如果你不想讓別人知道某個功能的詳細實現(xiàn),使用fileprivate
來修飾這個方法泼疑,那么它的實現(xiàn)過程將被隱藏private
private
定義的實體德绿,只在它被定義的大括號{}
內有效
子類的訪問等級
子類的訪問等級不能超過他的父類。但是對于里面可以重載的 類成員(屬性退渗,方法移稳,構造器),卻有著獨特的一面
- 被子類重載的類成員氓辣,可以擁有比在父類里更高的訪問等級秒裕,如下面的兩個類,類
B
重載了父類的someMethod
方法钞啸,并且賦予了它新的更高的訪問等級internal
public class A {
private func someMethod() {}
}
internal class B:A {
override internal func someMethod() {}
}
- 子類成員可以調用父類成員几蜻,并且這個父類成員比這個子類成員的訪問等級低。這個父類成員需要符合兩條原則:父類和子類定義在相同的源文件中体斩,對于父類的
private
成員梭稚;父類和子類定義在相同的Module
中,對于父類的internal
成員
//兩個類在相同的源文件中
public class A {
private func someMethod() {}
}
internal class B:A {
override internal func someMethod() {
super.someMethod()
}
}
Getter 與 Setter
getter
與 setter
默認和原屬性訪問等級相同絮吵,但是Swift 允許我們給 setter
設置比原屬性低的訪問等級弧烤,這樣可以起到有效的 讀寫保護。語法是蹬敲,在 var
前寫上fileprivate(set)
, private(set)
或 internal(set)
(set
可以換成 get
)
struct TrackedString {
private(set) var numberOfEdits = 0 //記錄 value 被修改的次數(shù)
var value: String = "" {
didSet {
numberOfEdits += 1 //每次 value 被修改之后暇昂,numberOfEdits 都會自動加1
}
}
}
上面的函數(shù)中,我們單獨設置了變量 numberOfEdits
的setter
為 private
伴嗡,而 getter
的訪問等級依然是 internal
(注意:internal
可以顯式的寫在private(set)
前)急波。這樣,在外部 numberOfEdits
呈現(xiàn)出了 read-only
的屬性而不能被修改瘪校,因為它只能在被定義的大括號{}
區(qū)域內被修改澄暮。
var stringToEdit = TrackedString()
stringToEdit.value = "Value changed once"
stringToEdit.value = "Value changed twice"
stringToEdit.value = "Value changed three times"
print("The number of edits is \(stringToEdit.numberOfEdits)") // 打印出 "The number of edits is 3"
枚舉的訪問等級
如果一個枚舉的訪問等級為 public
(或其它)名段,那么它的case
會自動接收相同的 public
(或其它) 訪問等級。并且你不能給 case
指定訪問等級泣懊,它只能隨從它所屬的枚舉伸辟。
嵌套類型的訪問等級
嵌套類型的訪問等級,基本呈現(xiàn)出逐層降低的現(xiàn)象
- 在
private
類型里定義的嵌套馍刮,自動為private
- 在
fileprivate
類型里定義的嵌套信夫,自動為private
- 在
public
或internal
類型里定義的嵌套,自動為internal
渠退。另外忙迁,如果你想把一個在public
里定義的嵌套變?yōu)楣械模敲茨阈枰@示聲明這個嵌套為public
元組的訪問等級
元組類型的訪問等級比較嚴格碎乃,如果它由兩個不同類型組成姊扔,一個是 private
,一個是internal
,那么它們組合成的元組類型的訪問等級將是 private
定義訪問等級的原則
定義一個實體時梅誓,這個實體的訪問等級恰梢,不能高于它所參照的實體的訪問等級 :
- 一個公共變量,不能被定義為
internal
,fileprivate
或private
類型梗掰,因為在這個公共變量使用的地方嵌言,這些類型并不一定都是有效的 - 一個函數(shù)的訪問等級,不能高于它的參數(shù)類型和返回類型的訪問等級及穗,比如下面的函數(shù)摧茴,分析一下,該用哪種訪問等級 埂陆?
func someFunction() -> (SomeInternalClass, SomePrivateClass) {
// function implementation goes here
}
可以看到苛白,它的返回類型是個元組類型,這個元組類型最終的訪問等級將是private
(至于為什么會是private
請參考上面的元組的訪問等級)焚虱。根據(jù)原則购裙,這個函數(shù)要使用 private
修飾。
private func someFunction() -> (SomeInternalClass, SomePrivateClass) {
// function implementation goes here
}