整理下 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