訪問(wèn)控制可以限定其他源文件或模塊中代碼對(duì)你代碼的訪問(wèn)級(jí)別。
你可以明確地給單個(gè)類型(類、結(jié)構(gòu)體、枚舉)設(shè)置訪問(wèn)級(jí)別,也可以給這些類型的屬性、函數(shù)、初始化方法、基本類型、下標(biāo)索引等設(shè)置訪問(wèn)級(jí)別。
協(xié)議也可以被限定在一定的范圍內(nèi)使用,包括協(xié)議里的全局常量、變量和函數(shù)。
訪問(wèn)控制基于模塊與源文件。
模塊指的是以獨(dú)立單元構(gòu)建和發(fā)布的 Framework 或 Application。在 Swift 中的一個(gè)模塊可以使用 import 關(guān)鍵字引入另外一個(gè)模塊。
源文件是單個(gè)源碼文件,它通常屬于一個(gè)模塊, 源文件可以包含多個(gè)類和函數(shù) 的定義。
Swift 為代碼中的實(shí)體提供了四種不同的訪問(wèn)級(jí)別:public、internal、fileprivate、private。
| 訪問(wèn)級(jí)別 | 定義 |
|---|---|
| public | 可以訪問(wèn)自己模塊中源文件里的任何實(shí)體,別人也可以通過(guò)引入該模塊來(lái)訪問(wèn)源文件里的所有實(shí)體。 |
| internal | 可以訪問(wèn)自己模塊中源文件里的任何實(shí)體,但是別人不能訪問(wèn)該模塊中源文件里的實(shí)體。 |
| fileprivate | 文件內(nèi)私有,只能在當(dāng)前源文件中使用。 |
| private | 只能在類中訪問(wèn),離開(kāi)了這個(gè)類或者結(jié)構(gòu)體的作用域外面就無(wú)法訪問(wèn)。 |
public 為最高級(jí)訪問(wèn)級(jí)別,private 為最低級(jí)訪問(wèn)級(jí)別。
通過(guò)修飾符public、internal、fileprivate、private來(lái)聲明實(shí)體的訪問(wèn)級(jí)別:
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() {}除非有特殊的說(shuō)明,否則實(shí)體都使用默認(rèn)的訪問(wèn)級(jí)別 internal。
class SomeInternalClass {} // 訪問(wèn)級(jí)別為 internal
let someInternalConstant = 0 // 訪問(wèn)級(jí)別為 internal函數(shù)的訪問(wèn)級(jí)別需要根據(jù)該函數(shù)的參數(shù)類型和返回類型的訪問(wèn)級(jí)別得出。
下面的實(shí)例定義了一個(gè)名為someFunction全局函數(shù),并且沒(méi)有明確地申明其訪問(wèn)級(jí)別。
func someFunction() -> (SomeInternalClass, SomePrivateClass) {
// 函數(shù)實(shí)現(xiàn)
}函數(shù)中其中一個(gè)類 SomeInternalClass 的訪問(wèn)級(jí)別是 internal,另一個(gè) SomePrivateClass 的訪問(wèn)級(jí)別是 private。所以根據(jù)元組訪問(wèn)級(jí)別的原則,該元組的訪問(wèn)級(jí)別是 private(元組的訪問(wèn)級(jí)別與元組中訪問(wèn)級(jí)別最低的類型一致)。
因?yàn)樵摵瘮?shù)返回類型的訪問(wèn)級(jí)別是 private,所以你必須使用 private 修飾符,明確的聲明該函數(shù):
private func someFunction() -> (SomeInternalClass, SomePrivateClass) {
// 函數(shù)實(shí)現(xiàn)
}將該函數(shù)申明為 public 或 internal,或者使用默認(rèn)的訪問(wèn)級(jí)別 internal 都是錯(cuò)誤的,因?yàn)槿绻@樣你就無(wú)法訪問(wèn) private 級(jí)別的返回值。
枚舉中成員的訪問(wèn)級(jí)別繼承自該枚舉,你不能為枚舉中的成員單獨(dú)申明不同的訪問(wèn)級(jí)別。
比如下面的實(shí)例,枚舉 Student 被明確的申明為 public 級(jí)別,那么它的成員 Name,Mark 的訪問(wèn)級(jí)別同樣也是 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é)生成績(jī): \(Mark1),\(Mark2),\(Mark3)")
}以上程序執(zhí)行輸出結(jié)果為:
學(xué)生成績(jī): 98,97,95
子類的訪問(wèn)級(jí)別不得高于父類的訪問(wèn)級(jí)別。比如說(shuō),父類的訪問(wèn)級(jí)別是internal,子類的訪問(wèn)級(jí)別就不能申明為public。
public class SuperClass {
fileprivate func show() {
print("超類")
}
}
// 訪問(wèn)級(jí)別不能高于超類 internal > public
internal class SubClass: SuperClass {
override internal func show() {
print("子類")
}
}
let sup = SuperClass()
sup.show()
let sub = SubClass()
sub.show()以上程序執(zhí)行輸出結(jié)果為:
超類 子類
常量、變量、屬性不能擁有比它們的類型更高的訪問(wèn)級(jí)別。
比如說(shuō),你定義一個(gè)public級(jí)別的屬性,但是它的類型是private級(jí)別的,這是編譯器所不允許的。
同樣,下標(biāo)也不能擁有比索引類型或返回類型更高的訪問(wèn)級(jí)別。
如果常量、變量、屬性、下標(biāo)索引的定義類型是private級(jí)別的,那么它們必須要明確的申明訪問(wèn)級(jí)別為private:
private var privateInstance = SomePrivateClass()
常量、變量、屬性、下標(biāo)索引的Getters和Setters的訪問(wèn)級(jí)別繼承自它們所屬成員的訪問(wèn)級(jí)別。
Setter的訪問(wèn)級(jí)別可以低于對(duì)應(yīng)的Getter的訪問(wèn)級(jí)別,這樣就可以控制變量、屬性或下標(biāo)索引的讀寫權(quán)限。
class Samplepgm {
fileprivate var counter: Int = 0{
willSet(newTotal){
print("計(jì)數(shù)器: \(newTotal)")
}
didSet{
if counter > oldValue {
print("新增加數(shù)量 \(counter - oldValue)")
}
}
}
}
let NewCounter = Samplepgm()
NewCounter.counter = 100
NewCounter.counter = 800counter 的訪問(wèn)級(jí)別為 fileprivate,在文件內(nèi)可以訪問(wèn)。
以上程序執(zhí)行輸出結(jié)果為:
計(jì)數(shù)器: 100 新增加數(shù)量 100 計(jì)數(shù)器: 800 新增加數(shù)量 700
我們可以給自定義的初始化方法申明訪問(wèn)級(jí)別,但是要不高于它所屬類的訪問(wèn)級(jí)別。但必要構(gòu)造器例外,它的訪問(wèn)級(jí)別必須和所屬類的訪問(wèn)級(jí)別相同。
如同函數(shù)或方法參數(shù),初始化方法參數(shù)的訪問(wèn)級(jí)別也不能低于初始化方法的訪問(wèn)級(jí)別。
Swift為結(jié)構(gòu)體、類都提供了一個(gè)默認(rèn)的無(wú)參初始化方法,用于給它們的所有屬性提供賦值操作,但不會(huì)給出具體值。
默認(rèn)初始化方法的訪問(wèn)級(jí)別與所屬類型的訪問(wèn)級(jí)別相同。
在每個(gè)子類的 init() 方法前使用 required 關(guān)鍵字聲明訪問(wè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
如果想為一個(gè)協(xié)議明確的申明訪問(wèn)級(jí)別,那么需要注意一點(diǎn),就是你要確保該協(xié)議只在你申明的訪問(wèn)級(jí)別作用域中使用。
如果你定義了一個(gè)public訪問(wèn)級(jí)別的協(xié)議,那么實(shí)現(xiàn)該協(xié)議提供的必要函數(shù)也會(huì)是public的訪問(wèn)級(jí)別。這一點(diǎn)不同于其他類型,比如,public訪問(wèn)級(jí)別的其他類型,他們成員的訪問(wèn)級(jí)別為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
你可以在條件允許的情況下對(duì)類、結(jié)構(gòu)體、枚舉進(jìn)行擴(kuò)展。擴(kuò)展成員應(yīng)該具有和原始類成員一致的訪問(wèn)級(jí)別。比如你擴(kuò)展了一個(gè)公共類型,那么你新加的成員應(yīng)該具有和原始成員一樣的默認(rèn)的internal訪問(wèn)級(jí)別。
或者,你可以明確申明擴(kuò)展的訪問(wèn)級(jí)別(比如使用private extension)給該擴(kuò)展內(nèi)所有成員申明一個(gè)新的默認(rèn)訪問(wèn)級(jí)別。這個(gè)新的默認(rèn)訪問(wèn)級(jí)別仍然可以被單獨(dú)成員所申明的訪問(wèn)級(jí)別所覆蓋。
泛型類型或泛型函數(shù)的訪問(wèn)級(jí)別取泛型類型、函數(shù)本身、泛型類型參數(shù)三者中的最低訪問(wèn)級(jí)別。
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ù)名"]
任何你定義的類型別名都會(huì)被當(dāng)作不同的類型,以便于進(jìn)行訪問(wèn)控制。一個(gè)類型別名的訪問(wèn)級(jí)別不可高于原類型的訪問(wèn)級(jí)別。
比如說(shuō),一個(gè)private級(jí)別的類型別名可以設(shè)定給一個(gè)public、internal、private的類型,但是一個(gè)public級(jí)別的類型別名只能設(shè)定給一個(gè)public級(jí)別的類型,不能設(shè)定給internal或private 級(jí)別的類型。
注意:這條規(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 語(yǔ)句")
print(tos.items)
var eos = ["Swift", "泛型", "Where 語(yǔ)句"]
print(eos)以上程序執(zhí)行輸出結(jié)果為:
["Swift"] ["Swift", "泛型"] ["Swift", "泛型", "Where 語(yǔ)句"] ["Swift", "泛型", "Where 語(yǔ)句"]