自拍偷在线精品自拍偷,亚洲欧美中文日韩v在线观看不卡

The Swift Programming Language--語言附注--訪問控制

移動開發(fā) iOS
蘋果在發(fā)布了Xcode 6 Bate 4后為Swift添加了新的特性--訪問控制(Access Control),并且更新了The Swift Programming Language文檔,我抽空把這篇文檔翻譯了一下,下面讓我們來詳細(xì)了解一下Access Control。

 

蘋果在發(fā)布了Xcode 6 Bate 4后為Swift添加了新的特性--訪問控制(Access Control),并且更新了The Swift Programming Language文檔,我抽空把這篇文檔翻譯了一下,下面讓我們來詳細(xì)了解一下Access Control。

本頁內(nèi)容包括:
1.模塊和源文件
2.訪問級別
(1)訪問級別的使用原則
(2)默認(rèn)訪問級別
(3)單目標(biāo)應(yīng)用程序的訪問級別
(4)Framework的訪問級別
3.訪問控制語法
4.自定義類型
(1)元組類型
(2)函數(shù)類型
(3)枚舉類型
(4)原始值和關(guān)聯(lián)值
(5)嵌套類型
5.子類
6.常量、變量、屬性、下標(biāo)
(1)Getter和Setter
7.初始化
(1)默認(rèn)初始化方法
(2)結(jié)構(gòu)體的默認(rèn)成員初始化方法
8.協(xié)議
(1)協(xié)議繼承
(2)協(xié)議一致性
9.擴展
(1)協(xié)議的擴展
10.泛型
11.類型別名
訪問控制可以限定你在源文件或模塊中訪問代碼的級別,也就是說可以控制哪些代碼你可以訪問,哪些代碼你不能訪問。這個特性可以讓我們隱藏功能實現(xiàn)的一些細(xì)節(jié),并且可以明確的指定我們提供給其他人的接口中哪些部分是他們可以使用的,哪些是他們看不到的。
你可以明確的給類、結(jié)構(gòu)體、枚舉、設(shè)置訪問級別,也可以給屬性、函數(shù)、初始化方法、基本類型、下標(biāo)索引等設(shè)置訪問級別。協(xié)議也可以被限定在一定的范圍內(nèi)使用,包括協(xié)議里的全局常量、變量和函數(shù)。
在提供了不同訪問級別的同時,Swift 并沒有規(guī)定我們要在任何時候都要在代碼中明確指定訪問級別。其實,如果我們作為獨立開發(fā)者在開發(fā)我們自己的 app,而不是在開發(fā)一些 Framework 的時候,我們完全可以不用明確的指定代碼的訪問級別。
注:為方便起見,在代碼中可以設(shè)置訪問級別的它們(屬性、基本類型、函數(shù)等)在下面的章節(jié)中我們稱之為“實體”。
模塊和源文件
Swift 中的訪問控制模型基于模塊和源文件這兩個概念。

模塊指的是 Framework 或 App bundle 。在 Swift 中,可以用 import 關(guān)鍵字引入自己的工程。

在 Swift 中,F(xiàn)ramework 或 App bundle 被作為模塊處理。如果你是為了實現(xiàn)某個通用的功能,或者是為了封裝一些常用方法而將代碼打包成 Framework,這個 Framework 在 Swift 中就被稱為模塊。不論它被引入到某個 App 工程或者其他的Framework,它里面的一切(屬性、函數(shù)等)都屬于這個模塊。

源文件指的是 Swift 中的Swift File,就是編寫 Swift 代碼的文件,它通常屬于一個模塊。通常一個源文件包含一個類,在類中又包含函數(shù)、屬性等類型。

訪問級別

Swift 提供了三種不同的訪問級別。這些訪問級別相對于源文件中定義的實體,同時也相對于這些源文件所屬的模塊。

1.Public:可以訪問自己模塊或應(yīng)用中源文件里的任何實體,別人也可以訪問引入該模塊中源文件里的所有實體。通常情況下,某個接口或 Framework 是可以被任何人使用時,你可以將其設(shè)置為 public 級別。

2.Internal:可以訪問自己模塊或應(yīng)用中源文件里的任何實體,但是別人不能訪問該模塊中源文件里的實體。通常情況下,某個接口或 Framework 作為內(nèi)部結(jié)構(gòu)使用時,你可以將其設(shè)置為 internal 級別。

3.Private:只能在當(dāng)前源文件中使用的實體,稱為私有實體。使用 private 級別,可以用作隱藏某些功能的實現(xiàn)細(xì)節(jié)。

Public 為***級訪問級別,Private 為***級訪問級別。

訪問級別的使用原則

在 Swift 中,訪問級別有如下使用原則:訪問級別統(tǒng)一性。 比如說:

1.一個 public 訪問級別的變量,不能將它的類型定義為 internal 和 private 的類型。因為變量可以被任何人訪問,但是定義它的類型不可以,所以這樣就會出現(xiàn)錯誤。

2.函數(shù)的訪問級別不能高于它的參數(shù)、返回類型的訪問級別。因為如果函數(shù)定義為 public 而參數(shù)或者返回類型定義為 internal 或 private,就會出現(xiàn)函數(shù)可以被任何人訪問,但是它的參數(shù)和返回類型不可以,同樣會出現(xiàn)錯誤。

默認(rèn)訪問級別

代碼中的所有實體,如果你不明確的定義其訪問級別,那么它們默認(rèn)為 internal 級別。在大多數(shù)情況下,我們不需要明確的設(shè)置實體的訪問級別,因為我們大多數(shù)時候都是在開發(fā)一個 App bundle。

單目標(biāo)應(yīng)用程序的訪問級別

當(dāng)你編寫一個單目標(biāo)應(yīng)用程序時,該應(yīng)用的所有功能都是為該應(yīng)用服務(wù),不需要提供給其他應(yīng)用或者模塊使用,所以我們不需要明確設(shè)置訪問級別,使用默認(rèn)的訪問級別 internal 即可。但是如果你愿意,你也可以使用 private 級別,用于隱藏一些功能的實現(xiàn)細(xì)節(jié)。

Framework的訪問級別

當(dāng)你開發(fā) Framework 時,就需要把一些實體定義為 public 級別,以便其他人導(dǎo)入該 Framework 后可以正常使用其功能。這些被你定義為 public 的實體,就是這個 Framework 的API。

注意:Framework 的內(nèi)部實現(xiàn)細(xì)節(jié)依然可以使用默認(rèn)的 internal 級別,或者也可以定義為 private 級別。只有你想將它作為 API 的實體,才將其定義為 public 級別。

 

訪問控制語法

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

  1. public class SomePublicClass {} 
  2. internal class SomeInternalClass {} 
  3. private class SomePrivateClass {} 
  4.  
  5. public var somePublicVariable = 0 
  6. internal let someInternalConstant = 0 
  7. private func somePrivateFunction() {} 

除非有特殊的說明,否則實體都使用默認(rèn)的訪問級別 internal,可以查閱 Default Access Levels 這一節(jié)。這意味著 SomeInternalClass someInternalConstant 不用明確的使用修飾符聲明訪問級別,但是他們?nèi)稳粨碛须[式的訪問級別 internal

  1. class SomeInternalClass {}              // 隱式訪問級別 internal 
  2. var someInternalConstant = 0            // 隱式訪問級別 internal

 

自定義類型

如果你想為一個自定義類型指定一個明確的訪問級別,那么你要明確一點。那就是你要確保新類型的訪問級別和它實際的作用域相匹配。比如說,如果某個類里的屬性、函數(shù)、返回值它們的作用域僅在當(dāng)前的源文件中,那么你就可以將這個類聲明為 private 類,而不需要聲明為 public 或者 internal 類。

類的訪問級別也可以影響到類成員(屬性、函數(shù)、初始化方法等)的默認(rèn)訪問級別。如果你將類聲明為 private 類,那么該類的所有成員的默認(rèn)訪問級別也會成為 private 。如果你將類聲明為 public 或者 internal 類(或者不明確的指定訪問級別,而使用默認(rèn)的 internal 訪問級別),那么該類的所有成員的訪問級別是 internal 。

注意:上面提到,一個 public 類的所有成員的訪問級別默認(rèn)為 internal 級別,而不是 public 級別。如果你想將某個成員聲明為 public 級別,那么你必須使用修飾符明確的聲明該成員。這樣做的好處是,在你定義公共接口API的時候,可以明確的選擇哪些屬性或方法是需要公開的,哪些是內(nèi)部使用的,可以避免將內(nèi)部使用的屬性方法公開成公共API的錯誤。

  1. public class SomePublicClass {          // 顯示的 public 類 
  2.     public var somePublicProperty = 0    // 顯示的 public 類成員 
  3.     var someInternalProperty = 0         // 隱式的 internal 類成員 
  4.     private func somePrivateMethod() {}  // 顯示的 private 類成員 
  5.  
  6. class SomeInternalClass {               // 隱式的 internal 類 
  7.     var someInternalProperty = 0         // 隱式的 internal 類成員 
  8.     private func somePrivateMethod() {}  // 顯示的 private 類成員 
  9.  
  10. private class SomePrivateClass {        // 顯示的 private 類 
  11.     var somePrivateProperty = 0          // 隱式的 private 類成員 
  12.     func somePrivateMethod() {}          // 隱式的 private 類成員 

元組類型

元組的訪問級別使用是所有類型的訪問級別使用中最為嚴(yán)謹(jǐn)?shù)摹1热缯f,如果你構(gòu)建一個包含兩種不同類型元素的元組,其中一個元素類型的訪問級別為 internal,另一個為 private 級別,那么這個元組的訪問級別為 private 。也就是說元組的訪問級別遵循它里面元組中***級的訪問級別。

注意:元組不同于類、結(jié)構(gòu)體、枚舉、函數(shù)那樣有單獨的定義。元組的訪問級別是在它被使用時自動推導(dǎo)出的,而不是明確的聲明。

函數(shù)類型

函數(shù)的訪問級別需要根據(jù)該函數(shù)的參數(shù)類型訪問級別、返回類型訪問級別得出。如果根據(jù)參數(shù)類型和返回類型得出的函數(shù)訪問級別不符合上下文,那么就需要明確的聲明該函數(shù)的訪問級別。

下面的例子中定義了一個全局函數(shù)名為 someFunction ,并且沒有明確的聲明其訪問級別。你也許會認(rèn)為該函數(shù)應(yīng)該擁有默認(rèn)的訪問級別 internal,但事實并非如此。事實上,如果按下面這種寫法,編譯器是無法編譯通過的:

  1. func someFunction() -> (SomeInternalClass, SomePrivateClass) { 
  2.     // function implementation goes here 

我們可以看到,這個函數(shù)的返回類型是一個元組,該元組中包含兩個自定義的類(可查閱Custom Types)。其中一個類的訪問級別是 internal,另一個的訪問級別是 private,所以根據(jù)元組訪問級別的原則,該元組的訪問級別是 private(元組的訪問級別遵循它里面元組中***級的訪問級別)。

因為該函數(shù)返回類型的訪問級別是private,所以你必須使用private修飾符,明確地申請該函數(shù):

  1. private func someFunction() -> (SomeInternalClass, SomePrivateClass) { 
  2.     // function implementation goes here 

將該函數(shù)聲明為public或internal,或者使用默認(rèn)的訪問級別internal都是錯誤的,因為如果把該函數(shù)當(dāng)做 public internal 級別來使用的話,是無法得到private級別的返回值的。

枚舉類型

枚舉中成員的訪問級別繼承自該枚舉,你不能為枚舉中的成員指定訪問級別。

比如下面的例子,枚舉 CompassPoint 被明確的聲明為 public 級別,那么它的成員 North,South,East,West 的訪問級別同樣也是 public

  1. public enum CompassPoint { 
  2.     case North 
  3.     case South 
  4.     case East 
  5.     case West 
  6. }

原始值和關(guān)聯(lián)值

用于枚舉定義中的任何原始值,或關(guān)聯(lián)的值類型必須有一個訪問級別,至少要高于枚舉的訪問級別。比如說,你不能在一個 internal 訪問級別的枚舉中定義 private 級別的原始值類型。

嵌套類型

如果在private級別的類型中定義嵌套類型,那么該嵌套類型就自動擁有 private 訪問級別。如果在 public 或者 internal 級別的類型中定義嵌套類型,那么該嵌套類型自動擁有 internal 訪問級別。如果想讓嵌套類型擁有 public 訪問級別,那么需要對該嵌套類型進(jìn)行明確的訪問級別聲明。

子類

子類的訪問級別不得高于父類的訪問級別。比如說,父類的訪問級別是 internal ,子類的訪問級別就不能聲明為 public 。

此外,在滿足子類不高于父類訪問級別以及遵循各訪問級別作用域(即模塊或源文件)的前提下,你可以重寫任意類成員(方法、屬性、初始化方法、下標(biāo)索引等)。

如果我們無法直接訪問某個類中的屬性或函數(shù)等,那么可以繼承該類,從而可以更容易的訪問到該類的類成員。下面的例子中,類A的訪問級別是 public ,它包含一個函數(shù) someMethod,訪問級別為private。類B繼承類A,并且訪問級別聲明為 internal ,但是在類B中重寫了類A中訪問級別為 private 的方法 someMethod,并重新聲明為 internal 級別。通過這種方式,我們就可以訪問到某類中 private 級別的類成員,并且可以重新聲明其訪問級別,以便其他人使用:

  1. public class A { 
  2.     private func someMethod() {} 
  3.  
  4. internal class B: A { 
  5.     override internal func someMethod() {} 

只要滿足子類不高于父類訪問級別以及遵循各訪問級別作用域的前提下(即 private 的作用域在同一個源文件中,internal 的作用域在同一個模塊下),我們甚至可以在子類中,用子類成員訪問父類成員,哪怕父類成員的訪問級別比子類成員的要低:

  1. public class A { 
  2.     private func someMethod() {} 
  3.  
  4. internal class B: A { 
  5.     override internal func someMethod() { 
  6.         super.someMethod() 
  7.     } 

因為父類A和子類B定義在同一個源文件中,所以在類B中可以在重寫的 someMethod 方法中調(diào)用 super.someMethod() 。

常量、變量、屬性、下標(biāo)

常量、變量、屬性不能擁有比它們的類型更高的訪問級別。比如說,你定義一個 public 級別的屬性,但是它的類型是 private 級別的,這是編譯器不允許的。同樣,下標(biāo)也不能擁有比索引類型或返回類型更高的訪問級別。

如果常量、變量、屬性、下標(biāo)索引的定義類型是 private 級別的,那么它們必須要明確的聲明訪問級別為 private:

  1. private var privateInstance = SomePrivateClass()

Getter和Setter

常量、變量、屬性、下標(biāo)索引的 Getters 和 Setters 的訪問級別繼承自它們所屬成員的訪問級別。

Setter 的訪問級別可以低于對應(yīng)的 Getter 的訪問級別,這樣就可以控制變量、屬性或下標(biāo)索引的讀寫權(quán)限。在var或subscript定義作用域之前,你可以通過private(set)或 internal(set)先為它門的寫權(quán)限聲明一個較低的訪問級別。

注意:這個規(guī)定適用于用作存儲的屬性或用作計算的屬性。即使你不明確的聲明存儲屬性的 Getter Setter,Swift 也會隱式的為其創(chuàng)建 Getter  Setter,用于對該屬性進(jìn)行讀取操作。使用 private(set) internal(set) 可以改變 Swift 隱式創(chuàng)建的 Setter 的訪問級別。在計算屬性中也是同樣的。

下面的例子中定義了一個結(jié)構(gòu)體名為 TrackedString,它記錄了value屬性被修改的次數(shù):

  1. struct TrackedString { 
  2.     private(set) var numberOfEdits = 0 
  3.     var value: String = "" { 
  4.     didSet { 
  5.         numberOfEdits++ 
  6.     } 
  7.     } 
  8. }

TrackedString 結(jié)構(gòu)體定義了一個用于存儲的屬性名為 value,類型為 String,并將初始化值設(shè)為""(即一個空字符串)。該結(jié)構(gòu)體同時也定義了另一個用于存儲的屬性名為 numberOfEdits ,類型為 Int,它用于記錄屬性 value 被修改的次數(shù)。這個功能的實現(xiàn)通過屬性 value 的 didSet 方法實現(xiàn),每當(dāng)給value賦新值時就會調(diào)用 didSet 方法,給 numberOfEdits 加一。

結(jié)構(gòu)體 TrackedString 和它的屬性 value 均沒有明確的聲明訪問級別,所以它們都擁有默認(rèn)的訪問級別 internal。但是該結(jié)構(gòu)體的 numberOfEdits 屬性使用 private(set) 修飾符進(jìn)行聲明,這意味著numberOfEdits 屬性只能在定義該結(jié)構(gòu)體的源文件中賦值。numberOfEdits 屬性的 Getter 依然是默認(rèn)的訪問級別 internal,但是 Setter 的訪問級別是 private ,這表示該屬性只有在當(dāng)前的源文件中是可讀可寫的,在當(dāng)前源文件所屬的模塊中它只是一個可讀的屬性。

如果你實例化 TrackedString 結(jié)構(gòu)體,并且多次對value屬性的值進(jìn)行修改,你就會看到 numberOfEdits 的值會隨著修改次數(shù)更改:

  1. var stringToEdit = TrackedString() 
  2. stringToEdit.value = "This string will be tracked." 
  3. stringToEdit.value += " This edit will increment numberOfEdits." 
  4. stringToEdit.value += " So will this one." 
  5. println("The number of edits is \(stringToEdit.numberOfEdits)"
  6. // prints "The number of edits is 3" 

雖然你可以在其他的源文件中實例化該結(jié)構(gòu)體并且獲取到numberOfEdits屬性的值,但是你不能對其進(jìn)行賦值。這樣就能很好的告訴使用者,你只管使用,而不需要知道其實現(xiàn)細(xì)節(jié)。

初始化

我們可以給自定義的初始化方法指定訪問級別,但是必須要低于或等于它所屬類的訪問級別。但如果該初始化方法是必須要使用的話,那它的訪問級別就必須和所屬類的訪問級別相同(參見Required Initializers)。

如同函數(shù)或方法參數(shù),初始化方法參數(shù)的訪問級別也不能低于初始化方法的訪問級別。

默認(rèn)初始化方法

Swift 為結(jié)構(gòu)體、類都提供了一個默認(rèn)的無參初始化方法,用于給它們的所有屬性提供賦值操作,但不會給出具體值。默認(rèn)初始化方法可以參閱 Default Initializers 。默認(rèn)初始化方法的訪問級別與所屬類型的訪問級別相同。

注意:如果一個類型被聲明為public級別,那么默認(rèn)的初始化方法的訪問級別為 internal 。如果你想讓無參的初始化方法在其他模塊中可以被使用,那么你必須提供一個具有 public 訪問級別的無參初始化方法。

結(jié)構(gòu)體的默認(rèn)成員初始化方法

如果結(jié)構(gòu)體中的任一存儲屬性的訪問級別為 private ,那么它的默認(rèn)成員初始化方法訪問級別就是 private 。盡管如此,結(jié)構(gòu)體的初始化方法的訪問級別依然是 internal 。

如果你想在其他模塊中使用該結(jié)構(gòu)體的默認(rèn)成員初始化方法,那么你需要提供一個訪問級別為 public 的默認(rèn)成員初始化方法。

 

 

 

協(xié)議

如果你想為一個協(xié)議明確的聲明訪問級別,那么有一點需要注意,就是你要確保該協(xié)議只在你聲明的訪問級別作用域中使用。

協(xié)議中的每一個必須要實現(xiàn)的函數(shù)都具有和該協(xié)議相同的訪問級別。這樣才能確保該協(xié)議的使用者可以實現(xiàn)它所提供的函數(shù)。

注意:如果你定義了一個 public 訪問級別的協(xié)議,那么實現(xiàn)該協(xié)議提供的必要函數(shù)也會是public的訪問級別。這一點不同于其他類型,比如 public 訪問級別的其他類型,他們成員的訪問級別為 internal 。

協(xié)議繼承

如果定義了一個新的協(xié)議,并且該協(xié)議繼承了一個已知的協(xié)議,那么新協(xié)議擁有的訪問級別***也只和被繼承協(xié)議的訪問級別相同。比如說,你不能定義一個public的協(xié)議而去繼承一個internal的協(xié)議。

協(xié)議一致性

類可以采用比自身訪問級別低的協(xié)議。比如說,你可以定義一個 public 級別的類,可以讓它在其他模塊中使用,同時它也可以采用一個 internal 級別的協(xié)議,并且只能在定義了該協(xié)議的模塊中使用。

采用了協(xié)議的類的訪問級別遵循它本身和采用協(xié)議中***的訪問級別。也就是說如果一個類是 public 級別,采用的協(xié)議是 internal 級別,那個采用了這個協(xié)議后,該類的訪問級別也是 internal 。

如果你采用了協(xié)議,那么實現(xiàn)了協(xié)議必須的方法后,該方法的訪問級別遵循協(xié)議的訪問級別。比如說,一個 public 級別的類,采用了 internal 級別的協(xié)議,那么該類實現(xiàn)協(xié)議的方法至少也得是 internal 。

注意:在 Swift 中和 Objective-C 中一樣,協(xié)議的一致性保證了一個類不可能在同一個程序中用不同的方法采用同一個協(xié)議。

擴展

你可以在條件允許的情況下對類、結(jié)構(gòu)體、枚舉進(jìn)行擴展。擴展成員應(yīng)該具有和原始類成員一致的訪問級別。比如你擴展了一個公共類型,那么你新加的成員應(yīng)該具有和原始成員一樣的默認(rèn)的 internal 訪問級別。

或者,你可以明確聲明擴展的訪問級別(比如使用 private extension)給該擴展內(nèi)所有成員指定一個新的默認(rèn)訪問級別。這個新的默認(rèn)訪問級別仍然可以被單獨成員所指定的訪問級別所覆蓋。

協(xié)議的擴展

如果一個擴展采用了某個協(xié)議,那么你就不能對該擴展使用訪問級別修飾符來聲明了。該擴展中實現(xiàn)協(xié)議的方法都會遵循該協(xié)議的訪問級別。

 

泛型

泛型類型或泛型函數(shù)的訪問級別遵循泛型類型、函數(shù)本身、泛型類型參數(shù)三者中訪問級別***的級別。

類型別名

任何被你定義的類型別名都會被視作為不同的類型,這些類型用于訪問控制。一個類型別名的訪問級別可以低于或等于這個類型的訪問級別。比如說,一 個private級別的類型別名可以設(shè)定給一個public、internal、private的類型,但是一個public級別的類型別名只能設(shè)定給一 個public級別的類型,不能設(shè)定給internal或private的類類型。

注意這條規(guī)則也適用于為滿足協(xié)議一致性而給相關(guān)類型命名別名。

 

 

責(zé)任編輯:chenqingxiang 來源: cocoachina
相關(guān)推薦

2022-08-31 14:54:21

PerlDevelopmen

2011-08-03 10:01:28

網(wǎng)絡(luò)智能手機

2011-08-03 10:20:27

網(wǎng)絡(luò)智能手機

2016-06-07 14:42:18

Swift設(shè)計

2015-08-14 11:37:37

Swift語言中文版

2009-02-05 10:12:00

訪問控制列表限制訪問

2020-12-23 09:40:17

物聯(lián)網(wǎng)安全訪問控制

2011-05-20 10:53:01

2023-12-06 21:50:40

2011-03-14 17:50:27

訪問控制列表

2011-03-10 15:22:08

訪問控制機制Java

2012-09-18 09:43:14

Squid代理服務(wù)器安全網(wǎng)關(guān)

2018-08-15 09:55:35

IaaS查詢ZStack

2023-11-13 18:18:28

2009-12-15 15:19:30

Ruby訪問控制

2009-02-12 11:59:11

2015-04-17 16:07:11

swiftOC

2018-08-14 17:05:11

查詢語言

2019-06-13 11:50:41

Python面向?qū)ο?/a>編程語言

2012-09-18 09:50:41

點贊
收藏

51CTO技術(shù)棧公眾號