訪問控制(Access Control)

目錄

[toc]

模塊和源文件

  • 模塊:獨立的代碼單元
  • 框架或應用程序會作為一個獨立的模塊來構建和發(fā)布
  • 一個模塊可以使用import關鍵字導入另外一個模塊
  • Xcode的每個target(例如框架或應用程序)都被當作獨立的模塊處理
  • 源文件:Swift中的源代碼文件

訪問級別(低-->高)

  • open: 類似public??梢员辉L問和被繼承
  • public: 可以訪問同一模塊源文件中的任何實體,在模塊外也可以通過導入該模塊來訪問源文件里的所有實體。可以被訪問不可以被繼承
  • internal: 可以訪問同一模塊源文件中的任何實體,但是不能從模塊外訪問該模塊源文件中的實體。通常情況下,某個接口只在應用程序或框架內(nèi)部使用時,你可以將其設置為internal級別。
  • fileprivate: 限制實體只能在所在的源文件內(nèi)部使用。
  • private: 只在定義的實體中使用

  • 訪問級別基本原則:不可以在某個實體中定義訪問級別更高的實體
  • 函數(shù)的訪問級別不能高于它的參數(shù)類型和返回類型的訪問級別。
  • 一般,默認為internal級別
  • 在導入應用程序模塊的語句前使用 @testable 特性,然后在允許測試的編譯設置( Build Options -> Enable Testability )下編譯這個應用程序模塊,單元測試 target 就可以訪問應用程序模塊中所有 internal 級別的實體。

訪問控制語法

通過修飾符open,public,internal,fileprivate,private來聲明實體的訪問級別:

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() {}

除非專門指定,否則實體默認的訪問級別為 internal。這意味著在不使用修飾符顯式聲明訪問級別的情況下,SomeInternalClasssomeInternalConstant仍然擁有隱式的internal

class SomeInternalClass {}   // 隱式 internal
var someInternalConstant = 0 // 隱式 internal

自定義類型

  • 一個類型的訪問級別也會影響到類型成員(屬性、方法、構造器、下標)的默認訪問級別。
  • 元組:元組的訪問級別將由元組中訪問級別最嚴格的類型來決定。
  • 函數(shù):函數(shù)的訪問級別根據(jù)訪問級別最嚴格的參數(shù)類型或返回類型的訪問級別來決定。但是,如果這種訪問級別不符合函數(shù)定義所在環(huán)境的默認訪問級別,那么就需要明確地指定該函數(shù)的訪問級別。
  • 枚舉類型:枚舉成員的訪問級別和該枚舉類型相同,你不能為枚舉成員單獨指定不同的訪問級別。枚舉定義中的任何原始值或關聯(lián)值的類型的訪問級別至少不能低于枚舉類型的訪問級別。
public class SomePublicClass {                  // 顯式 public 類
    public var somePublicProperty = 0            // 顯式 public 類成員
    var someInternalProperty = 0                 // 隱式 internal 類成員
    fileprivate func someFilePrivateMethod() {}  // 顯式 fileprivate 類成員
    private func somePrivateMethod() {}          // 顯式 private 類成員
}

class SomeInternalClass {                       // 隱式 internal 類
    var someInternalProperty = 0                 // 隱式 internal 類成員
    fileprivate func someFilePrivateMethod() {}  // 顯式 fileprivate 類成員
    private func somePrivateMethod() {}          // 顯式 private 類成員
}

fileprivate class SomeFilePrivateClass {        // 顯式 fileprivate 類
    func someFilePrivateMethod() {}              // 隱式 fileprivate 類成員
    private func somePrivateMethod() {}          // 顯式 private 類成員
}

private class SomePrivateClass {                // 顯式 private 類
    func somePrivateMethod() {}                  // 隱式 private 類成員
}

子類

  • 子類的訪問級別不得高于父類的訪問級別。
  • 可以在符合當前訪問級別的條件下重寫任意類成員(方法、屬性、構造器、下標等)。
public class A {
    fileprivate func someMethod() {}
}
internal class B: A {
    override internal func someMethod() {
        super.someMethod()
    }
}

常量、變量、屬性、下標

常量、變量、屬性訪問級別不能高于它們所屬的類型。

struct TrackedString {
    private(set) var numberOfEdits = 0
    var value: String = "" {
        didSet {
            numberOfEdits += 1
        }
    }
}
var stringToEdit = TrackedString()
stringToEdit.value = "This string will be tracked."
stringToEdit.value += " This edit will increment numberOfEdits."
stringToEdit.value += " So will this one."
print("The number of edits is \(stringToEdit.numberOfEdits)")  
// 打印 “The number of edits is 3”
public struct TrackedString2 {
    public private(set) var numberOfEdits = 0                       
    // Getter的訪問級別是public,Setter的訪問級別是private。
    public var value: String = "" {
        didSet {
            numberOfEdits += 1
        }
    }
    public init() {}
}

構造器

必要構造器 的訪問級別必須和所屬類型相同。

默認構造器的訪問級別與所屬類型的訪問級別相同,除非類型的訪問級別是public。如果一個類型被指定為public級別,那么默認構造器的訪問級別將為internal。如果你希望一個public級別的類型也能在其他模塊中使用這種無參數(shù)的默認構造器,你只能自己提供一個public訪問級別的無參數(shù)構造器。

協(xié)議

如果想為一個協(xié)議類型明確地指定訪問級別,在定義協(xié)議時指定即可。這將限制該協(xié)議只能在適當?shù)脑L問級別范圍內(nèi)被采納。

協(xié)議中的每一個要求都具有和該協(xié)議相同的訪問級別。你不能將協(xié)議中的要求設置為其他訪問級別。這樣才能確保該協(xié)議的所有要求對于任意采納者都將可用。

注意:如果你定義了一個public訪問級別的協(xié)議,那么該協(xié)議的所有實現(xiàn)也會是public訪問級別。這一點不同于其他類型,例如,當類型是public訪問級別時,其成員的訪問級別卻只是internal。


協(xié)議一致性

一個類型可以采納比自身訪問級別低的協(xié)議。例如,你可以定義一個public級別的類型,它可以在其他模塊中使用,同時它也可以采納一個internal級別的協(xié)議,但是只能在該協(xié)議所在的模塊中作為符合該協(xié)議的類型使用。

采納了協(xié)議的類型的訪問級別取它本身和所采納協(xié)議兩者間最低的訪問級別。也就是說如果一個類型是public級別,采納的協(xié)議是internal級別,那么采納了這個協(xié)議后,該類型作為符合協(xié)議的類型時,其訪問級別也是internal。

如果你采納了協(xié)議,那么實現(xiàn)了協(xié)議的所有要求后,你必須確保這些實現(xiàn)的訪問級別不能低于協(xié)議的訪問級別。例如,一個public級別的類型,采納了internal級別的協(xié)議,那么協(xié)議的實現(xiàn)至少也得是internal級別。

注意SwiftObjective-C一樣,協(xié)議的一致性是全局的,也就是說,在同一程序中,一個類型不可能用兩種不同的方式實現(xiàn)同一個協(xié)議。

Extension

Extension可以在訪問級別允許的情況下對類、結構體、枚舉進行擴展。Extension的成員具有和原始類型成員一致的訪問級別。例如,你使用extension擴展了一個public或者internal類型,extension中的成員就默認使用internal訪問級別,和原始類型中的成員一致。如果你使用extension擴展了一個private類型,則extension的成員默認使用private訪問級別。

或者,你可以明確指定extension的訪問級別(例如,private extension),從而給該extension中的所有成員指定一個新的默認訪問級別。這個新的默認訪問級別仍然可以被單獨指定的訪問級別所覆蓋。

如果你使用extension來遵循協(xié)議的話,就不能顯式地聲明extension的訪問級別。extension每個protocol要求的實現(xiàn)都默認使用protocol的訪問級別。


Extension的私有成員

擴展同一文件內(nèi)的類,結構體或者枚舉,extension里的代碼會表現(xiàn)得跟聲明在原類型里的一模一樣。也就是說你可以這樣:

  • 在類型的聲明里聲明一個私有成員,在同一文件的extension里訪問。
  • extension里聲明一個私有成員,在同一文件的另一個extension里訪問。
  • extension里聲明一個私有成員,在同一文件的類型聲明里訪問。

這意味著你可以像組織的代碼去使用extension,而且不受私有成員的影響。例如,給定下面這樣一個簡單的協(xié)議:

protocol SomeProtocol {
    func doSomething() -> Void
}

你可以使用 extension 來遵守協(xié)議,就想這樣:

struct SomeStruct {
    private var privateVariable = 12
}

extension SomeStruct: SomeProtocol {
    func doSomething() {
        print(privateVariable)
    }
}

泛型

泛型類型或泛型函數(shù)的訪問級別取決于泛型類型或泛型函數(shù)本身的訪問級別,還需結合類型參數(shù)的類型約束的訪問級別,根據(jù)這些訪問級別中的最低訪問級別來確定。

類型別名

類型別名的訪問級別不可高于其表示的類型的訪問級別

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

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

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