訪問控制(Access Control)
在訪問權(quán)限控制這塊,Swift提供了5個不同的訪問級別(以下是從高到低排列芳杏, 實體指被訪問級別修飾的內(nèi)容)
- open:允許在定義實體的模塊、其他模塊中訪問狞贱,允許其他模塊進行繼承坛悉、重寫(open只能用在類罐脊、類成員上)
- public:允許在定義實體的模塊、其他模塊中訪問枯怖,不允許其他模塊進行繼承注整、重寫
- internal:只允許在定義實體的模塊中訪問,不允許在其他模塊中訪問
- fileprivate:只允許在定義實體的源文件中訪問
- private:只允許在定義實體的封閉聲明中訪問
- 絕大部分實體默認都是internal 級別
訪問級別的使用準則
一個實體不可以被更低訪問級別的實體定義度硝,比如
- 變量\常量類型≥ 變量\常量
- 參數(shù)類型肿轨、返回值類型≥ 函數(shù)
- 父類≥ 子類
- 父協(xié)議≥ 子協(xié)議
- 原類型≥ typealias
- 原始值類型、關聯(lián)值類型≥ 枚舉類型
- 定義類型A時用到的其他類型≥ 類型A
- ......
元組類型
- 元組類型的訪問級別是所有成員類型最低的那個
internal struct Dog {}
fileprivate class Person {}
// (Dog, Person)的訪問級別是fileprivate
fileprivate var data1: (Dog, Person)
private var data2: (Dog, Person)
泛型類型
- 泛型類型的訪問級別是類型的訪問級別以及所有泛型類型參數(shù)的訪問級別中最低的那個
internal class Car {}
fileprivate class Dog {}
public class Person<T1, T2> {}
// Person<Car, Dog>的訪問級別是fileprivate
fileprivate var p = Person<Car, Dog>()
成員蕊程、嵌套類型
- 類型的訪問級別會影響成員(屬性椒袍、方法、初始化器藻茂、下標)晋柱、嵌套類型的默認訪問級別
- 一般情況下,類型為private或fileprivate焦影,那么成員\嵌套類型默認也是private或fileprivate
- 一般情況下胞谈,類型為internal或public,那么成員\嵌套類型默認是internal
public class PublicClass {
public var p1 = 0 // public
var p2 = 0 // internal
fileprivate func f1() {} // fileprivate
private func f2() {} // private
}
class InternalClass { // internal
var p = 0 // internal
fileprivate func f1() {} // fileprivate
private func f2() {} // private
}
fileprivate class FilePrivateClass { // fileprivate
func f1() {} // fileprivate
private func f2() {} // private
}
private class PrivateClass { // private
func f() {} // private
}
成員的重寫
- 子類重寫成員的訪問級別必須≥ 子類的訪問級別肖油,或者≥ 父類被重寫成員的訪問級別
- 父類的成員不能被成員作用域外定義的子類重寫
public class Person {
private var age: Int = 0
}
public class Student : Person {
override var age: Int {
set {}
get {10}
}
}
public class Person {
private var age: Int = 0
public class Student : Person {
override var age: Int {
set {}
get {10}
}
}
}
下面代碼能否編譯通過兼吓?
private class Person {}
fileprivate class Student : Person {}
private struct Dog {
var age: Int = 0
func run() {}
}
fileprivate struct Person {
var dog: Dog = Dog()
mutating func walk() {
dog.run()
dog.age = 1
}
}
private struct Dog {
private var age: Int = 0
private func run() {}
}
fileprivate struct Person {
var dog: Dog = Dog()
mutating func walk() {
dog.run()
dog.age = 1
}
}
- 直接在全局作用域下定義的private等價于fileprivate
getter、setter
- getter森枪、setter默認自動接收它們所屬環(huán)境的訪問級別
- 可以給setter單獨設置一個比getter更低的訪問級別视搏,用以限制寫的權(quán)限
fileprivate(set) public var num = 10
class Person {
private(set) var age = 0
fileprivate(set) public var weight: Int {
set {}
get { 10 }
}
internal(set) public subscript(index: Int) -> Int {
set {}
get { index }
}
}
初始化器
如果一個public類想在另一個模塊調(diào)用編譯生成的默認無參初始化器审孽,必須顯式提供public的無參初始化器
因為public類的默認初始化器是internal級別required初始化器≥ 它的默認訪問級別
如果結(jié)構(gòu)體有private\fileprivate的存儲實例屬性,那么它的成員初始化器也是private\fileprivate
否則默認就是internal
枚舉類型的case
不能給enum的每個case單獨設置訪問級別
每個case自動接收enum的訪問級別
public enum定義的case也是public
協(xié)議
協(xié)議中定義的要求自動接收協(xié)議的訪問級別浑娜,不能單獨設置訪問級別
public協(xié)議定義的要求也是public協(xié)議實現(xiàn)的訪問級別必須≥ 類型的訪問級別佑力,或者≥ 協(xié)議的訪問級別
下面代碼能編譯通過么?
public protocol Runnable {
func run()
}
public class Person : Runnable {
func run() {}
}
擴展
如果有顯式設置擴展的訪問級別筋遭,擴展添加的成員自動接收擴展的訪問級別
如果沒有顯式設置擴展的訪問級別打颤,擴展添加的成員的默認訪問級別,跟直接在類型中定義的成員一樣
可以單獨給擴展添加的成員設置訪問級別
不能給用于遵守協(xié)議的擴展顯式設置擴展的訪問級別
擴展
- 在同一文件中的擴展漓滔,可以寫成類似多個部分的類型聲明
在原本的聲明中聲明一個私有成員编饺,可以在同一文件的擴展中訪問它
在擴展中聲明一個私有成員,可以在同一文件的其他擴展中响驴、原本聲明中訪問它
public class Person {
private func run0() {}
private func eat0() {
run1()
}
}
extension Person {
private func run1() {}
private func eat1() {
run0()
}
}
extension Person {
private func eat2() {
run1()
}
}
將方法賦值給var\let
- 方法也可以像函數(shù)那樣透且,賦值給一個let或者var
struct Person {
var age: Int
func run(_ v: Int) { print("func run", age, v) }
static func run(_ v: Int) { print("static func run", v) }
}
let fn1 = Person.run
fn1(10) // static func run 10
let fn2: (Int) -> () = Person.run
fn2(20) // static func run 20
let fn3: (Person) -> ((Int) -> ()) = Person.run
fn3(Person(age: 18))(30) // func run 18 30