# Swift 訪問控制
訪問控制可以限定其他源文件或模塊中代碼對你代碼的訪問級別。
你可以明確地給單個類型(類、結構體、枚舉)設置訪問級別,也可以給這些類型的屬性、函數、初始化方法、基本類型、下標索引等設置訪問級別。
協議也可以被限定在一定的范圍內使用,包括協議里的全局常量、變量和函數。
訪問控制基于模塊與源文件。
模塊指的是以獨立單元構建和發布的Framework或Application。在Swift 中的一個模塊可以使用import關鍵字引入另外一個模塊。
源文件是單個源碼文件,它通常屬于一個模塊, 源文件可以包含多個類和函數 的定義。
Swift 為代碼中的實體提供了三種不同的訪問級別:public、internal、private。
| 訪問級別 | 定義 |
| --- | --- |
| Public | 可以訪問自己模塊中源文件里的任何實體,別人也可以通過引入該模塊來訪問源文件里的所有實體。 |
| Internal | :可以訪問自己模塊中源文件里的任何實體,但是別人不能訪問該模塊中源文件里的實體。 |
| Private | 只能在當前源文件中使用的實體,稱為私有實體。 |
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() {}
```
除非有特殊的說明,否則實體都使用默認的訪問級別internal。
## 函數類型訪問權限
函數的訪問級別需要根據該函數的參數類型和返回類型的訪問級別得出。
下面的例子定義了一個名為someFunction全局函數,并且沒有明確地申明其訪問級別。
```
func someFunction() -> (SomeInternalClass, SomePrivateClass) {
// 函數實現
}
```
函數中其中一個類 SomeInternalClass 的訪問級別是internal,另一個 SomePrivateClass 的訪問級別是private。所以根據元組訪問級別的原則,該元組的訪問級別是private。
```
private func someFunction() -> (SomeInternalClass, SomePrivateClass) {
// 函數實現
}
```
將該函數申明為public或internal,或者使用默認的訪問級別internal都是錯誤的。
## 枚舉類型訪問權限
枚舉中成員的訪問級別繼承自該枚舉,你不能為枚舉中的成員單獨申明不同的訪問級別。
### 實例
比如下面的例子,枚舉 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("學生名: \(studName).")
case .Mark(let Mark1, let Mark2, let Mark3):
print("學生成績: \(Mark1),\(Mark2),\(Mark3)")
}
```
以上程序執行輸出結果為:
```
學生成績: 98,97,95
```
## 子類訪問權限
子類的訪問級別不得高于父類的訪問級別。比如說,父類的訪問級別是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()
```
以上程序執行輸出結果為:
```
超類
子類
```
## 常量、變量、屬性、下標訪問權限
常量、變量、屬性不能擁有比它們的類型更高的訪問級別。
比如說,你定義一個public級別的屬性,但是它的類型是private級別的,這是編譯器所不允許的。
同樣,下標也不能擁有比索引類型或返回類型更高的訪問級別。
如果常量、變量、屬性、下標索引的定義類型是private級別的,那么它們必須要明確的申明訪問級別為private:
```
private var privateInstance = SomePrivateClass()
```
## Getter 和 Setter訪問權限
常量、變量、屬性、下標索引的Getters和Setters的訪問級別繼承自它們所屬成員的訪問級別。
Setter的訪問級別可以低于對應的Getter的訪問級別,這樣就可以控制變量、屬性或下標索引的讀寫權限。
```
class Samplepgm {
private var counter: Int = 0{
willSet(newTotal){
print("計數器: \(newTotal)")
}
didSet{
if counter > oldValue {
print("新增加數量 \(counter - oldValue)")
}
}
}
}
let NewCounter = Samplepgm()
NewCounter.counter = 100
NewCounter.counter = 800
```
以上程序執行輸出結果為:
```
計數器: 100
新增加數量 100
計數器: 800
新增加數量 700
```
## 構造器和默認構造器訪問權限
### 初始化
我們可以給自定義的初始化方法申明訪問級別,但是要不高于它所屬類的訪問級別。但必要構造器例外,它的訪問級別必須和所屬類的訪問級別相同。
如同函數或方法參數,初始化方法參數的訪問級別也不能低于初始化方法的訪問級別。
### 默認初始化方法
Swift為結構體、類都提供了一個默認的無參初始化方法,用于給它們的所有屬性提供賦值操作,但不會給出具體值。
默認初始化方法的訪問級別與所屬類型的訪問級別相同。
### 實例
在每個子類的 init() 方法前使用 required 關鍵字聲明訪問權限。
```
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()
```
以上程序執行輸出結果為:
```
10
30
10
```
## 協議訪問權限
如果想為一個協議明確的申明訪問級別,那么需要注意一點,就是你要確保該協議只在你申明的訪問級別作用域中使用。
如果你定義了一個public訪問級別的協議,那么實現該協議提供的必要函數也會是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)")
```
以上程序執行輸出結果為:
```
res is: 20
res is: 30
res is: 50
```
## 擴展訪問權限
你可以在條件允許的情況下對類、結構體、枚舉進行擴展。擴展成員應該具有和原始類成員一致的訪問級別。比如你擴展了一個公共類型,那么你新加的成員應該具有和原始成員一樣的默認的internal訪問級別。
或者,你可以明確申明擴展的訪問級別(比如使用private extension)給該擴展內所有成員申明一個新的默認訪問級別。這個新的默認訪問級別仍然可以被單獨成員所申明的訪問級別所覆蓋。
## 泛型訪問權限
泛型類型或泛型函數的訪問級別取泛型類型、函數本身、泛型類型參數三者中的最低訪問級別。
```
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("類型參數")
print(tos.items)
tos.push("類型參數名")
print(tos.items)
let deletetos = tos.pop()
```
以上程序執行輸出結果為:
```
["Swift"]
["Swift", "泛型"]
["Swift", "泛型", "類型參數"]
["Swift", "泛型", "類型參數", "類型參數名"]
```
## 類型別名
任何你定義的類型別名都會被當作不同的類型,以便于進行訪問控制。一個類型別名的訪問級別不可高于原類型的訪問級別。
比如說,一個private級別的類型別名可以設定給一個public、internal、private的類型,但是一個public級別的類型別名只能設定給一個public級別的類型,不能設定給internal或private 級別的類型。
> 注意:
這條規則也適用于為滿足協議一致性而給相關類型命名別名的情況。
```
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)
```
以上程序執行輸出結果為:
```
["Swift"]
["Swift", "泛型"]
["Swift", "泛型", "Where 語句"]
["Swift", "泛型", "Where 語句"]
```
- Swift 簡介
- Swift 環境搭建
- Swift 基本語法
- Swift 數據類型
- Swift 變量
- Swift 可選(Optionals)類型
- Swift 常量
- Swift 字面量
- Swift 運算符
- Swift 條件語句
- Swift if 語句
- Swift if...else 語句
- Swift if...else if...else 語句
- Swift 嵌套 if 語句
- Swift switch 語句
- Swift 循環
- Swift for-in 循環
- Swift for 循環
- Swift While 循環
- Swift repeat...while 循環
- Swift Continue 語句
- Swift Break 語句
- Swift Fallthrough 語句
- Swift 字符串
- Swift 字符(Character)
- Swift 數組
- Swift 字典
- Swift 函數
- Swift 閉包
- Swift 枚舉
- Swift 結構體
- Swift 類
- Swift 屬性
- Swift 方法
- Swift 下標腳本
- Swift 繼承
- Swift 構造過程
- Swift 析構過程
- Swift 可選鏈
- Swift 自動引用計數(ARC)
- Swift 類型轉換
- Swift 擴展
- Swift 協議
- Swift 泛型
- Swift 訪問控制