about 6 years ago

Swift 中的 access control 主要區分兩種環境,分別是 module 跟 source file,
在 Xcode 中,一個 target 或是一個 library 可以識別成一個 module,
source file 指的就是單一的 swift 檔案。

Open && Public

代表權限可以在任何 module 的 source file 使用。

module A
open class MyClassA {
}
module B
class MyClassB {
    let c = MyClassA()
}

兩者的差別會出現在使用 classes 的時候,
是使用 public 的 class 無法在其他的 module 繼承,但 open 可以,
class 的 property 或是 function 等等也是相同的情況。

module A
open class MyClassA {
}
public class MyClassA2 {
}
module B
class MyClassB: MyClassA {
}

上述如果繼承 MyClassA2 會出現 error。

Internal

限制只能在所屬的 module 內的 source file 使用。

module A
internal class MyClassA {
}
class AnotherMyClassA {
    let c = MyClassA()
}
module B
class MyClassB {
    let c = MyClassA()
}

上述的 MyClassB 會有 error。

File-private

限制只能在此 source file 使用。

fileprivate class MyClass {
}
let c = MyClass()
class MyClass2 {
    let c = MyClass()
}

上述中的 MyClass2 無法建立 MyClass 型別,因為在不同的檔案內無法使用。

Private

限制在所屬的程式區塊。

class MyClass {
    private var num = 123
}
let c = MyClass()
c.num = 456

上述無法操作 num,因為 num 限制在 MyClass 的區塊內使用。

自定義限制權限

決大部分的型別,若不額外設定,在宣告時便會將 internal 當作預設權限,
自訂時,要注意其自定義的型別與其內部成員的關係。

例如,若將一個 class 設定為 fileprivate,那麽內部成員預設就會變成 fileprivate,
且針對內部成員不能設定超過 fileprivate 的權限,也就是只能設定 fileprivate 或 private。

fileprivate class MyClass {
    var num = 123
    private func myFunc() {
    }
}

Tuple

在 tuple 內,如果有兩個不同限制權限的型別,會以最低 level 的當成此 tuple 的限制。
比如說有 internal 與 private,那麼此 tuple 就會是 private。

Function

若 function 的參數或回傳值是有其他的權限,必須對 function 改變限制權限來符合其參數或是回傳值。

class MyClass {
    private class MyClass2 {
    }
  private func() -> MyClass {
    }
}

Enumeration

沒辦法對 enumeration 內的 case 單一設定不同的限制權限。
如果是設定初始值,初始值型別的限制權限不能超過 enumeration 本身的權限。

Subclass

Subclass 的權限不能比 sueprclass 還高,但是內部成員在某些情況下是允許的。

public class MyClass {
    fileprivate func myFunc() {
    }
}
internal class MyClass2: MyClass {
    override internal func myFunc() {
        super.myFunc()
    }
}

上述的例子,MyClass2 的權限並沒有比 MyClass 來的高,
但是 override 的 fuction 權限卻比 superclass 還高,
因為在 MyClass2 內呼叫 super myFunc, 而 MyClass 跟 MyClass2 因為在同一個 source file,
所以是可以正常被呼叫到的,如果 MyClass2 寫在跟 MyClass 不同的 source file 就無法正常執行。

變數,常數,property 與 subscript

這些的限制權限都不能高過於本身的型別。

Getter & Setter

與變數常數相同的規則,比較不同的是,可以額外針對 set 做較嚴格的限制權限。

class MyClass {
    private(set) var num = 0
    var numP: Int {
        didSet {
            num = numP
        }
    }
}

Initializer

Initializer 基本上會跟著所屬的 class 或是 structure 的限制權限而改變,
但如果有在 class 或是 structure 使用 public 或是 open 的話,
都必須對 initializer 宣告 public 才能使用。

Protocol

  1. Protocol 內宣告的限制權限必定與 protocol 本身相同,無法更改。
  2. Porotocol 內使用的型別限制權不能比 protocol 本身更低。
  3. 實作的限制權限會 follow 原本的 protocol。
  4. 可以修改實作的限制權限,但不能比原本的 protocol 更低。

Extension

建立的任何 extension 都會參照原本的型別限制權限,
也可以讓 extension 有新的限制權限,其內部成員都會跟隨新的限制權限。

使用 extension 實作 protocol 的情況下,不能修改 extension 的限制權限。

← iOS Swift : Generics iOS Objective-C 動態置換實作 →