整理下 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 聲明的屬性和方法,都比較廣,而且用於進行開發模塊框架中。若是隻是在單獨的 target 中使用的話,那麼沒有必要用到 open 和 public,用默認的級別便可,也就是 internal。swift
場景 | ||
---|---|---|
文件內 | 都可以進行訪問等操做。 | |
模塊內 | 能夠在模塊內進行訪問等操做。 | |
模塊外 | 當文件 import 模塊後,能夠在文件中對模塊內進行訪問等操做。 |
兩者的不一樣之處主要在:app
open 聲明的類,能夠在模塊外,也就是import 後,對模塊內相應聲明的類進行繼承,並重載方法,而 public 聲明的類,則只是在模塊外對其進行繼承,但不容許重載。框架
internal 是 Swift 中的默認訪問級別。通常也不用特地去聲明 internal。只能用於模塊內。ide
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() { } }
另外,咱們能夠經過 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) 這種用法,而後去官方文檔查才發現本身漏了這個知識點。因而藉此機會整理了。
Allow distinguishing between public access and public overridability