十六、訪問控制

訪問控制

訪問控制

在訪問權(quán)限控制這塊,Swift提供了5個(gè)不同的訪問級別(以下從高到低排列)

  • open:允許在定義實(shí)體的模塊、其他模塊中訪問,允許其他模塊進(jìn)行繼承重寫(open只能用在類、類成員上)
  • public:允許在定義實(shí)體的模塊、其他模塊中訪問,不允許其他模塊進(jìn)行繼承重寫
  • internal:只允許在定義實(shí)體的模塊中訪問,不允許在其他模塊中訪問
  • fileprivate:只允許在定義實(shí)體的源文件中訪問
  • private:只允許在定義實(shí)體的封閉聲明中訪問

絕大部分實(shí)體默認(rèn)都是 internal 級別

訪問級別的使用準(zhǔn)則

一個(gè)實(shí)體不可以被更低訪問級別的實(shí)體定義,比如:

  • 變量、常量類型 >= 變量、常量
  • 參數(shù)類型、返回值類型 >= 函數(shù)
  • 父類 >= 子類
  • 父協(xié)議 >= 子協(xié)議
  • 原類型 >= typealias
  • 原始值類型、關(guān)聯(lián)值類型 >= 枚舉類型
  • 定義類型A時(shí)用到的其他類型 >= 類型A
  • ...
元組類型
  • 元組類型的訪問級別是所有成員類型最低的那個(gè)
internal struct Dog{ }
fileprivate class Car { }

fileprivate var data1:(Dog,Car)
private var data2:(Dog,Car)
//internal var data3:(Dog,Car)//Car的訪問級別低于data3 報(bào)錯(cuò)
//public var data3:(Dog,Car)//Dog Car的訪問級別均低于data3 報(bào)錯(cuò)
泛型類型
  • 泛型類型的訪問級別是類型的訪問級別以及所有泛型類型參數(shù)的訪問級別中最低的那個(gè)
internal struct Dog{ }
fileprivate class Car { }
public class Person<T1,T2>{}
fileprivate var p1 = Person<Car,Dog>()
private var p2 = Person<Car,Dog>()
//internal var p3 = Person<Car,Dog>()//p3的訪問級別高于Car 報(bào)錯(cuò)
成員嵌套類型
  • 類型的訪問級別會影響成員(屬性、方法、初始化器、下標(biāo))、嵌套類型的默認(rèn)訪問級別
  • 一般情況下,類型為privatefileprivate,那么成員、嵌套類型默認(rèn)也是privatefileprivate
  • 一般情況下,類型為internalpublic,那么成員、嵌套類型默認(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{
    func f1(){}//fileprivate
    private func f2(){}//private
}

private class privateClass{
    func f1(){}//private
}
成員的重寫
  • 子類重寫成員的訪問級別必須 >= 子類的訪問級別,或者 >= 父類被重寫的成員的訪問級別
  • 父類的成員不能被成員作用域外定義的子類重寫
class Person {
    internal func run(){}
}

fileprivate class Student : Person{
    fileprivate override func run() {//至少>=子類的訪問級別或者>=重寫方法的訪問級別
        
    }
}
//如果不是定義在全局則會報(bào)錯(cuò)
private class Person{//因?yàn)閜rivate在全局定義  作用域即為該文件 其實(shí)定義的是fileprivate
}
fileprivate class Student :Person{ }


private struct Dog{////因?yàn)閜rivate在全局定義  作用域即為該文件 其實(shí)定義的是fileprivate
    var age = 0 //屬性為fileprivate
    func run() {//方法為fileprivate
    }
}
private struct Woman{
    var dog:Dog = Dog()
    mutating func walk() {
        dog.run()//所以此處可以訪問
        dog.age = 1
    }
}
直接在全局作用域下定義的private等價(jià)于fileprivate
getter、setter
  • gettersetter默認(rèn)自動接收它們所屬環(huán)境的訪問級別
  • 可以給setter單獨(dú)設(shè)置一個(gè)比getter更低的訪問級別,用以限制寫的權(quán)限
fileprivate(set) public var num = 10//訪問權(quán)限為public 寫權(quán)限為fileprivate

class Person {
    private(set) var age = 0//存儲屬性
    fileprivate(set) public var weight: Int{//計(jì)算屬性
        set{}
        get{ 10 }
    }
    internal(set) public subscript(index: Int) -> Int{//下標(biāo)
        set{}
        get{ index }
    }
}

var p = Person()
//p.age = 10 報(bào)錯(cuò)
print(p.age)//輸出:0
初始化器
  • 如果一個(gè)public類想在另一個(gè)模塊調(diào)用編譯生成 的默認(rèn)無參初始化器,必須顯示提供public的無參初始化器, 因?yàn)?strong>public類的默認(rèn)初始化器時(shí)internal級別
  • required初始化器 >= 它的默認(rèn)訪問級別
  • 如果結(jié)構(gòu)體有private\fileprivate的存儲實(shí)例屬性,那么它的成員初始化器也是private\fileprivate,否則就是internal
枚舉類型的case
  • 不能給enum的每個(gè)case單獨(dú)設(shè)置訪問級別
  • 每個(gè)case自動接收enum的訪問級別
協(xié)議
  • 協(xié)議中定義的要求自動接收協(xié)議的訪問級別,不能單獨(dú)設(shè)置訪問級別
  • 協(xié)議實(shí)現(xiàn)的訪問級別必須 >= 類型的訪問級別,或者 >= 協(xié)議的訪問級別
fileprivate protocol Runnable{
    func run()
}

internal class Person : Runnable{
    //訪問權(quán)限至少要大于 Person 的訪問級別 或協(xié)議的訪問級別
    fileprivate func run() {//private修飾則報(bào)錯(cuò)
        
    }
}
擴(kuò)展
  • 如果有顯示設(shè)置擴(kuò)展的訪問級別,擴(kuò)展添加的成員自動接收擴(kuò)展的訪問級別
  • 如果沒有顯示設(shè)置擴(kuò)展的訪問級別,擴(kuò)展添加的成員的默認(rèn)訪問級別,跟直接在類型中定義的成員一樣
  • 可以單獨(dú)給擴(kuò)展添加的成員設(shè)置訪問級別
  • 不能給用于遵守協(xié)議的擴(kuò)展顯示設(shè)置擴(kuò)展的訪問級別(如下例)
fileprivate protocol Runnable{
    func run()
}

class Person{
    
}

internal extension Person : Runnable{//報(bào)錯(cuò):不能修飾任何訪問控制關(guān)鍵字
    func run() {
        
    }
}
  • 在同一文件中的擴(kuò)展,可以寫成類似多個(gè)部分的類型聲明
  • 在原本的聲明中聲明一個(gè)私有成員,可以再同一文件的擴(kuò)展中訪問它
  • 在擴(kuò)展中聲明一個(gè)私有成員,可以在同一文件的其他擴(kuò)展中、原本聲明中訪問它
//可以看做擴(kuò)展中的成員都是在類中定義
public class Person{
    private func run0(){}
    private func eat0(){
        run1()//可以相互調(diào)用
        eat2()
    }
    
}

extension Person{
    private func run1(){}
    private func eat1(){
        run0()
        eat2()
    }
}

extension Person{
    private func eat2(){
        run1()
        eat0()
    }
}
將方法賦值類var/let
  • 方法也可以像函數(shù)那樣,賦值給一個(gè)let或者var
//實(shí)例方法
struct Person {
    var age: Int
    func run(_ v: Int) {
        print("func run",age,v)
    }
}

var fn1 = Person.run//fn1類型: (Person) -> ((Int) -> ())
var fn2 = fn1(Person(age: 10))//fn2類型:(Int) -> ()  先傳Person實(shí)例 返回函數(shù) 再傳10
fn2(10)
//類型方法
struct Person {
    var age: Int
    static func run(_ v: Int) {
        print("func run",v)
    }
}

var fn1 = Person.run//fn1類型: (Int) -> ()
fn1(10)
struct Person {
    var age: Int
    func run(_ v: Int) {
        print("Obj func run",v)
    }
    static func run(_ v: Int) {
        print("Class func run",v)
    }
}

//如果類型方法與實(shí)例方法重名 則聲明類型進(jìn)行區(qū)分
var fn1:(Person) -> ((Int) -> ()) = Person.run
var fn2 = fn1(Person(age: 10))
fn2(20)

var fn3:(Int) -> () = Person.run
fn3(30)
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

  • 訪問控制 可以限定其它源文件或模塊中的代碼對你的代碼的訪問級別。這個(gè)特性可以讓我們隱藏代碼的一些實(shí)現(xiàn)細(xì)節(jié),并且可以...
    答案MK閱讀 327評論 0 0
  • 中文文檔 一、模塊和源文件 Swift 中的訪問控制模型基于模塊和源文件這兩個(gè)概念。 模塊指的是獨(dú)立的代碼單元,框...
    伯wen閱讀 353評論 0 0
  • 本章將會介紹 模塊和源文件訪問級別訪問控制語法自定義類型子類常量、變量、屬性、下標(biāo)構(gòu)造器協(xié)議擴(kuò)展泛型類型別名位運(yùn)算...
    寒橋閱讀 994評論 0 2
  • 訪問控制可以限定其它源文件或模塊中的代碼對你的代碼的訪問級別。這個(gè)特性可以讓我們隱藏代碼的一些實(shí)現(xiàn)細(xì)節(jié),并且可以為...
    Sultan閱讀 169評論 0 0
  • 步驟 1.下載并安裝 360加固保 2.project bulid.gradle : (配置需要用戶路徑和常量) ...
    小王子_c285閱讀 1,400評論 1 7

友情鏈接更多精彩內(nèi)容