整理下 Swift 的 Access Control

整理下 Swift 的 Access Control~屬性訪問級別。html

衆所周知,Swift 並無像 Objective-C 那樣,有着涇渭分明的 .h 和 .m 文件能夠來決定哪些參數、方法須要暴露,哪些不須要暴露。Swift 提供了五種訪問級別(assess level),分別是 open、public、internal、fileprivate、private。git

level
open open 的級別,也是最高的
public public 的級別次之
internal internal 是默認的訪問控制級別
fileprivate 使用 fileprivate 定義的方法和屬性,只在該文件中都可以使用,包括該文件中的extension
private 使用 private 定義的方法和屬性,只包括該文件中該類或結構體等的extension。

<!-- Mark -->github

open & public

open 和 public 聲明的屬性和方法,都比較廣,而且用於進行開發模塊框架中。若是隻是在單獨的 target 中使用的話,那麼沒有必要用到 open 和 public,用默認的級別便可,也就是 internal。swift

場景
文件內 都可以進行訪問等操做。
模塊內 能夠在模塊內進行訪問等操做。
模塊外 當文件 import 模塊後,能夠在文件中對模塊內進行訪問等操做。

兩者的不一樣之處主要在:app

open 聲明的類,能夠在模塊外,也就是import 後,對模塊內相應聲明的類進行繼承,並重載方法,而 public 聲明的類,則只是在模塊外對其進行繼承,但不容許重載。框架

internal

internal 是 Swift 中的默認訪問級別。通常也不用特地去聲明 internal。只能用於模塊內。ide

fileprivate & private

fileprivate 和 private 聲明的屬性和方法,均是私有的。可是前者更可能是對文件內私有,後者則是對類型內私有。ui

fileprivate,顧名思義,只在文件內訪問。所以,任何標明瞭 fileprivate 的屬性和方法,都可以在該文件內進行訪問使用。spa

private,則更可能是類、結構體等內部使用。早在 Swift 3 的時候,當在同一個文件裏,用 extension 對類或結構體等進行擴展時,在 extension 裏是沒法訪問到 private 標記的屬性和方法,須要使用 fileprivate。可是後面 Swift 4 又對 private 進行改變,在同一文件內,extension 裏能夠訪問到 private 標記的屬性和方法裏。code

因此,fileprivate 的訪問級別是比 private 高的。fileprivate 是隻要在同一個文件裏都是能夠訪問的,可是 private 則多了限制。

struct Dog {
    fileprivate func run() { }
    private func eat() { }
}

extension Dog {
    func eatAgain() {
        eat()
    }
}

struct Human {
    fileprivate var month : String?
    private var eye : String?
    var dog = Dog()
    
    func walkTheDog() {
        dog.run()
    }
}

好比上述例子,在同一文件內,Human 能夠經過 dog 來調用到 fileprivate 聲明的 run(),可是沒法調用到 private 聲明的 eat()。而在 extension Dog 裏,則能夠調用到 private 聲明的 eat()

另外,fileprivate 還有一些其餘的用法。好比子類在和父類同一文件內能夠重寫 fileprivate 聲明的屬性和方法等。其中,若是是存儲性屬性的話,那麼是沒法進行重載的。

class Animal {
    fileprivate var mouth : String { return "mouth"}
    fileprivate var nose : String = ""
    private var eye : String?
    
    fileprivate func jump() { }
    private func eat() { }
}

class Cat : Animal {
    override var mouth: String { return "CatMouth" }
    
    override func jump() { }
}

get/set

另外,咱們能夠經過 fileprivate(set)private(set)internal(set) 來決定 set 方法的級別。

struct TrackedString {
    private(set) var numberOfEdits = 0
    var value: String = "" {
        didSet {
            numberOfEdits += 1
        }
    }
}
var tracked = TrackedString()
tracked.numberOfEdits = 0         ❌

好比官方文檔的這個?。當使用 private(set) 標明 numberOfEdits 後,當你
經過構造一個 TrackedString,想要從外部更改 numberOfEdits ,那麼就會報錯。這裏簡單的說明就是,numberOfEdits 的 get 外部能夠見,而 set 因爲代表了 private(set) ,那麼外部不能夠見,沒法在外部更改。

訪問權限大概就是這些。主要是在看源碼的時候,發現了 private(set) 這種用法,而後去官方文檔查才發現本身漏了這個知識點。因而藉此機會整理了。

p1

參考

官方文檔

Allow distinguishing between public access and public overridability

相關文章
相關標籤/搜索