Swift 訪問控制
訪問控制可以限定其他源文件或模塊中代碼對你代碼的訪問級別。
你可以明確地給單個類型(類、結(jié)構(gòu)體、枚舉)設(shè)置訪問級別,也可以給這些類型的屬性、函數(shù)、初始化方法、基本類型、下標(biāo)索引等設(shè)置訪問級別。
協(xié)議也可以被限定在一定的范圍內(nèi)使用,包括協(xié)議里的全局常量、變量和函數(shù)。
訪問控制基于模塊與源文件。
模塊指的是以獨立單元構(gòu)建和發(fā)布的Framework或Application。在Swift 中的一個模塊可以使用import關(guān)鍵字引入另外一個模塊。
源文件是單個源碼文件,它通常屬于一個模塊, 源文件可以包含多個類和函數(shù) 的定義。
Swift 為代碼中的實體提供了三種不同的訪問級別:public、internal、private。
訪問級別 | 定義 |
---|---|
Public | 可以訪問自己模塊中源文件里的任何實體,別人也可以通過引入該模塊來訪問源文件里的所有實體。 |
Internal | :可以訪問自己模塊中源文件里的任何實體,但是別人不能訪問該模塊中源文件里的實體。 |
Private | 只能在當(dāng)前源文件中使用的實體,稱為私有實體。 |
public為最高級訪問級別,private為最低級訪問級別。
語法
通過修飾符public、internal、private來聲明實體的訪問級別:
public class SomePublicClass {} internal class SomeInternalClass {} private class SomePrivateClass {} public var somePublicVariable = 0 internal let someInternalConstant = 0 private func somePrivateFunction() {}
除非有特殊的說明,否則實體都使用默認(rèn)的訪問級別internal。
函數(shù)類型訪問權(quán)限
函數(shù)的訪問級別需要根據(jù)該函數(shù)的參數(shù)類型和返回類型的訪問級別得出。
下面的例子定義了一個名為someFunction全局函數(shù),并且沒有明確地申明其訪問級別。
func someFunction() -> (SomeInternalClass, SomePrivateClass) { // 函數(shù)實現(xiàn) }
函數(shù)中其中一個類 SomeInternalClass 的訪問級別是internal,另一個 SomePrivateClass 的訪問級別是private。所以根據(jù)元組訪問級別的原則,該元組的訪問級別是private。
因為該函數(shù)返回類型的訪問級別是private,所以你必須使用private修飾符,明確的聲明該函數(shù):private func someFunction() -> (SomeInternalClass, SomePrivateClass) { // 函數(shù)實現(xiàn) }
將該函數(shù)申明為public或internal,或者使用默認(rèn)的訪問級別internal都是錯誤的。
枚舉類型訪問權(quán)限
枚舉中成員的訪問級別繼承自該枚舉,你不能為枚舉中的成員單獨申明不同的訪問級別。
實例
比如下面的例子,枚舉 Student 被明確的申明為 public 級別,那么它的成員 Name,Mark 的訪問級別同樣也是 public:
public enum Student { case Name(String) case Mark(Int,Int,Int) } var studDetails = Student.Name("Swift") var studMarks = Student.Mark(98,97,95) switch studMarks { case .Name(let studName): print("學(xué)生名: \(studName).") case .Mark(let Mark1, let Mark2, let Mark3): print("學(xué)生成績: \(Mark1),\(Mark2),\(Mark3)") }
以上程序執(zhí)行輸出結(jié)果為:
學(xué)生成績: 98,97,95
子類訪問權(quán)限
子類的訪問級別不得高于父類的訪問級別。比如說,父類的訪問級別是internal,子類的訪問級別就不能申明為public。
public class SuperClass { private func show() { print("超類") } } // 訪問級別不能低于超類 internal > public internal class SubClass: SuperClass { override internal func show() { print("子類") } } let sup = SuperClass() sup.show() let sub = SubClass() sub.show()
以上程序執(zhí)行輸出結(jié)果為:
超類 子類
常量、變量、屬性、下標(biāo)訪問權(quán)限
常量、變量、屬性不能擁有比它們的類型更高的訪問級別。
比如說,你定義一個public級別的屬性,但是它的類型是private級別的,這是編譯器所不允許的。
同樣,下標(biāo)也不能擁有比索引類型或返回類型更高的訪問級別。
如果常量、變量、屬性、下標(biāo)索引的定義類型是private級別的,那么它們必須要明確的申明訪問級別為private:
private var privateInstance = SomePrivateClass()
Getter 和 Setter訪問權(quán)限
常量、變量、屬性、下標(biāo)索引的Getters和Setters的訪問級別繼承自它們所屬成員的訪問級別。
Setter的訪問級別可以低于對應(yīng)的Getter的訪問級別,這樣就可以控制變量、屬性或下標(biāo)索引的讀寫權(quán)限。
class Samplepgm { private var counter: Int = 0{ willSet(newTotal){ print("計數(shù)器: \(newTotal)") } didSet{ if counter > oldValue { print("新增加數(shù)量 \(counter - oldValue)") } } } } let NewCounter = Samplepgm() NewCounter.counter = 100 NewCounter.counter = 800
以上程序執(zhí)行輸出結(jié)果為:
計數(shù)器: 100 新增加數(shù)量 100 計數(shù)器: 800 新增加數(shù)量 700
構(gòu)造器和默認(rèn)構(gòu)造器訪問權(quán)限
初始化
我們可以給自定義的初始化方法申明訪問級別,但是要不高于它所屬類的訪問級別。但必要構(gòu)造器例外,它的訪問級別必須和所屬類的訪問級別相同。
如同函數(shù)或方法參數(shù),初始化方法參數(shù)的訪問級別也不能低于初始化方法的訪問級別。
默認(rèn)初始化方法
Swift為結(jié)構(gòu)體、類都提供了一個默認(rèn)的無參初始化方法,用于給它們的所有屬性提供賦值操作,但不會給出具體值。
默認(rèn)初始化方法的訪問級別與所屬類型的訪問級別相同。
實例
在每個子類的 init() 方法前使用 required 關(guān)鍵字聲明訪問權(quán)限。
class classA { required init() { var a = 10 print(a) } } class classB: classA { required init() { var b = 30 print(b) } } let res = classA() let show = classB()
以上程序執(zhí)行輸出結(jié)果為:
10 30 10
協(xié)議訪問權(quán)限
如果想為一個協(xié)議明確的申明訪問級別,那么需要注意一點,就是你要確保該協(xié)議只在你申明的訪問級別作用域中使用。
如果你定義了一個public訪問級別的協(xié)議,那么實現(xiàn)該協(xié)議提供的必要函數(shù)也會是public的訪問級別。這一點不同于其他類型,比如,public訪問級別的其他類型,他們成員的訪問級別為internal。
public protocol TcpProtocol { init(no1: Int) } public class MainClass { var no1: Int // local storage init(no1: Int) { self.no1 = no1 // initialization } } class SubClass: MainClass, TcpProtocol { var no2: Int init(no1: Int, no2 : Int) { self.no2 = no2 super.init(no1:no1) } // Requires only one parameter for convenient method required override convenience init(no1: Int) { self.init(no1:no1, no2:0) } } let res = MainClass(no1: 20) let show = SubClass(no1: 30, no2: 50) print("res is: \(res.no1)") print("res is: \(show.no1)") print("res is: \(show.no2)")
以上程序執(zhí)行輸出結(jié)果為:
res is: 20 res is: 30 res is: 50
擴展訪問權(quán)限
你可以在條件允許的情況下對類、結(jié)構(gòu)體、枚舉進行擴展。擴展成員應(yīng)該具有和原始類成員一致的訪問級別。比如你擴展了一個公共類型,那么你新加的成員應(yīng)該具有和原始成員一樣的默認(rèn)的internal訪問級別。
或者,你可以明確申明擴展的訪問級別(比如使用private extension)給該擴展內(nèi)所有成員申明一個新的默認(rèn)訪問級別。這個新的默認(rèn)訪問級別仍然可以被單獨成員所申明的訪問級別所覆蓋。
泛型訪問權(quán)限
泛型類型或泛型函數(shù)的訪問級別取泛型類型、函數(shù)本身、泛型類型參數(shù)三者中的最低訪問級別。
public struct TOS<T> { var items = [T]() private mutating func push(item: T) { items.append(item) } mutating func pop() -> T { return items.removeLast() } } var tos = TOS<String>() tos.push("Swift") print(tos.items) tos.push("泛型") print(tos.items) tos.push("類型參數(shù)") print(tos.items) tos.push("類型參數(shù)名") print(tos.items) let deletetos = tos.pop()
以上程序執(zhí)行輸出結(jié)果為:
["Swift"] ["Swift", "泛型"] ["Swift", "泛型", "類型參數(shù)"] ["Swift", "泛型", "類型參數(shù)", "類型參數(shù)名"]
類型別名
任何你定義的類型別名都會被當(dāng)作不同的類型,以便于進行訪問控制。一個類型別名的訪問級別不可高于原類型的訪問級別。
比如說,一個private級別的類型別名可以設(shè)定給一個public、internal、private的類型,但是一個public級別的類型別名只能設(shè)定給一個public級別的類型,不能設(shè)定給internal或private 級別的類型。
注意:這條規(guī)則也適用于為滿足協(xié)議一致性而給相關(guān)類型命名別名的情況。
public protocol Container { typealias ItemType mutating func append(item: ItemType) var count: Int { get } subscript(i: Int) -> ItemType { get } } struct Stack<T>: Container { // original Stack<T> implementation var items = [T]() mutating func push(item: T) { items.append(item) } mutating func pop() -> T { return items.removeLast() } // conformance to the Container protocol mutating func append(item: T) { self.push(item) } var count: Int { return items.count } subscript(i: Int) -> T { return items[i] } } func allItemsMatch< C1: Container, C2: Container where C1.ItemType == C2.ItemType, C1.ItemType: Equatable> (someContainer: C1, anotherContainer: C2) -> Bool { // check that both containers contain the same number of items if someContainer.count != anotherContainer.count { return false } // check each pair of items to see if they are equivalent for i in 0..<someContainer.count { if someContainer[i] != anotherContainer[i] { return false } } // all items match, so return true return true } var tos = Stack<String>() tos.push("Swift") print(tos.items) tos.push("泛型") print(tos.items) tos.push("Where 語句") print(tos.items) var eos = ["Swift", "泛型", "Where 語句"] print(eos)
以上程序執(zhí)行輸出結(jié)果為:
["Swift"] ["Swift", "泛型"] ["Swift", "泛型", "Where 語句"] ["Swift", "泛型", "Where 語句"]
更多建議: