訪問控制(Access Control)
- 在訪問權(quán)限控制這塊,Swift提供了5個(gè)不同的訪問級(jí)別(以下是從高到低排列瞒津, 實(shí)體指被訪問級(jí)別修飾的內(nèi)容)
□ open:允許在定義實(shí)體的模塊、其他模塊中訪問腋粥,允許其他模塊進(jìn)行繼承鹰祸、重寫(open只能用在類巩割、類成員上) □ □ public:允許在定義實(shí)體的模塊、其他模塊中訪問亭珍,不允許其他模塊進(jìn)行繼承敷钾、重寫
□ pinternal:只允許在定義實(shí)體的模塊中訪問,不允許在其他模塊中訪問
□ fileprivate:只允許在定義實(shí)體的源文件中訪問
□ private:只允許在定義實(shí)體的封閉聲明中訪問
□ 絕大部分實(shí)體默認(rèn)都是internal 級(jí)別
訪問級(jí)別的使用準(zhǔn)則
- 一個(gè)實(shí)體不可以被更低訪問級(jí)別的實(shí)體定義块蚌,比如
□ 變量\常量類型 ≥ 變量\常量
□ 參數(shù)類型闰非、返回值類型 ≥ 函數(shù)
□ 父類 ≥ 子類
□ 父協(xié)議 ≥ 子協(xié)議
□ 原類型 ≥ typealias p原始值類型、關(guān)聯(lián)值類型 ≥ 枚舉類型 p定義類型A時(shí)用到的其他類型 ≥ 類型A
□ ......
元組類型
- 元組類型的訪問級(jí)別是所有成員類型最低的那個(gè)
internal struct Dog {}
fileprivate class Person {}
// (Dog, Person)的訪問級(jí)別是fileprivate
fileprivate var data1: (Dog, Person)
private var data2: (Dog, Person)
泛型類型
- 泛型類型的訪問級(jí)別是 類型的訪問級(jí)別 以及 所有泛型類型參數(shù)的訪問級(jí)別 中最低的那個(gè)
internal class Car {}
fileprivate class Dog {}
public class Person<T1, T2> {}
// Person<Car, Dog>的訪問級(jí)別是fileprivate
fileprivate var p = Person<Car, Dog>()
成員峭范、嵌套類型
- 類型的訪問級(jí)別會(huì)影響成員(屬性财松、方法、初始化器、下標(biāo))辆毡、嵌套類型的默認(rèn)訪問級(jí)別
- 一般情況下菜秦,類型為private或fileprivate,那么成員\嵌套類型默認(rèn)也是private或fileprivate
- 一般情況下舶掖,類型為internal或public球昨,那么成員\嵌套類型默認(rèn)是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
}
成員的重寫
- 子類重寫成員的訪問級(jí)別必須 ≥ 子類的訪問級(jí)別,或者 ≥ 父類被重寫成員的訪問級(jí)別
- 父類的成員不能被成員作用域外定義的子類重寫
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等價(jià)于fileprivate
getter眨攘、setter
- getter主慰、setter默認(rèn)自動(dòng)接收它們所屬環(huán)境的訪問級(jí)別
- 可以給setter單獨(dú)設(shè)置一個(gè)比getter更低的訪問級(jí)別,用以限制寫的權(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 }
}
}
初始化器
- 如果一個(gè)public類想在另一個(gè)模塊調(diào)用編譯生成的默認(rèn)無(wú)參初始化器鲫售,必須顯式提供public的無(wú)參初始化器
□ 因?yàn)閜ublic類的默認(rèn)初始化器是internal級(jí)別
□ required初始化器 ≥ 它的默認(rèn)訪問級(jí)別
□ 如果結(jié)構(gòu)體有private\fileprivate的存儲(chǔ)實(shí)例屬性共螺,那么它的成員初始化器也是private\fileprivate
□ 否則默認(rèn)就是internal
枚舉類型的case
- 不能給enum的每個(gè)case單獨(dú)設(shè)置訪問級(jí)別
□ 每個(gè)case自動(dòng)接收enum的訪問級(jí)別
□ public enum定義的case也是public
協(xié)議
□ 協(xié)議中定義的要求自動(dòng)接收協(xié)議的訪問級(jí)別,不能單獨(dú)設(shè)置訪問級(jí)別
□ public協(xié)議定義的要求也是public
□ 協(xié)議實(shí)現(xiàn)的訪問級(jí)別必須 ≥ 類型的訪問級(jí)別情竹,或者 ≥ 協(xié)議的訪問級(jí)別
□ 下面代碼能編譯通過么?
public protocol Runnable {
func run()
}
public class Person : Runnable {
func run() {}
}
擴(kuò)展
- 如果有顯式設(shè)置擴(kuò)展的訪問級(jí)別藐不,擴(kuò)展添加的成員自動(dòng)接收擴(kuò)展的訪問級(jí)別
- 如果沒有顯式設(shè)置擴(kuò)展的訪問級(jí)別,擴(kuò)展添加的成員的默認(rèn)訪問級(jí)別秦效,跟直接在類型中定義的成員一樣
- 可以單獨(dú)給擴(kuò)展添加的成員設(shè)置訪問級(jí)別
- 不能給用于遵守協(xié)議的擴(kuò)展顯式設(shè)置擴(kuò)展的訪問級(jí)別
擴(kuò)展
- 在同一文件中的擴(kuò)展雏蛮,可以寫成類似多個(gè)部分的類型聲明
□ 在原本的聲明中聲明一個(gè)私有成員,可以在同一文件的擴(kuò)展中訪問它
□ 在擴(kuò)展中聲明一個(gè)私有成員阱州,可以在同一文件的其他擴(kuò)展中挑秉、原本聲明中訪問它
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ù)那樣,賦值給一個(gè)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