Swift 的访问控制
访问控制限制来自其它代码源文件或module对各种类型(类、结构体、枚举)以及属性、方法等的访问
权限等级
swift支持5种权限等级:
-
open:
- open修饰的实体可被同一个module里的其它源文件访问,也可被导入了此module的其它module里的源文件访问。
-
public:
- 同open
-
internal:
- internal修饰的实体只能被同一个module的其它源文件访问
- 如果没有显示的指定权限,那internal便作为默认的权限
-
file-private:
- file-private修饰的实体只能本源文件内被访问
-
private:
- file-private修饰的实体只能在声明的范围内被访问和同一文件内声明的类别被访问
open权限是最高权限等级(最少的限制),private权限是最低权限等级(最多的限制)
- file-private修饰的实体只能在声明的范围内被访问和同一文件内声明的类别被访问
- public权限和比它更低的权限等级修饰的类只能在同一个module里子类化
- public权限和比它更低的权限等级修饰的类成员只能在同一个module里的子类里重写
- open修饰的类可在同一个module和导入了此module的其它module里子类化
- open修饰的类成员可在同一个module和导入了此module的其它module里的子类里重写
权限等级原则
实体不能使用比它低权限的实体来定义
例如:
- public变量不能使用internal, file-private, or private的类型来定义
- 函数不能比它的参数和返回值高的访问权限
单元测试的访问控制
通常情况下,只有open和public修饰的实体才能被其它module使用。然而,如果在单元测试导入此module前加上@testable关键字并开启此module的测试,便可访问internal修饰的实体。
访问控制语法
public class SomePublicClass {}
internal class SomeInternalClass {}
fileprivate class SomeFilePrivateClass {}
private class SomePrivateClass {}
public var somePublicVariable = 0
internal let someInternalConstant = 0
fileprivate func someFilePrivateFunction() {}
private func somePrivateFunction() {}
class SomeInternalClass {} // implicitly internal
let someInternalConstant = 0 // implicitly internal
访问控制的使用
类型的权限会影响到类型的成员的权限
如果定义了一个类型是private 或 file private,那它的成员的默认权限便是private 或 file private,如果定义了一个类型是internal 或 public,那它的成员的默认权限便是internal
public class SomePublicClass { // explicitly public class
public var somePublicProperty = 0 // explicitly public class member
var someInternalProperty = 0 // implicitly internal class member
fileprivate func someFilePrivateMethod() {} // explicitly file-private class member
private func somePrivateMethod() {} // explicitly private class member
}
class SomeInternalClass { // implicitly internal class
var someInternalProperty = 0 // implicitly internal class member
fileprivate func someFilePrivateMethod() {} // explicitly file-private class member
private func somePrivateMethod() {} // explicitly private class member
}
fileprivate class SomeFilePrivateClass { // explicitly file-private class
func someFilePrivateMethod() {} // implicitly file-private class member
private func somePrivateMethod() {} // explicitly private class member
}
private class SomePrivateClass { // explicitly private class
func somePrivateMethod() {} // implicitly private class member
}
子类的访问控制
子类的权限不能超过父类的权限
继承的成员可以有比父类更高的权限
public class A {
fileprivate func someMethod() {}
}
internal class B: A {
override internal func someMethod() {}
}
getters 和 setters 的访问控制
getters和setters的访问权限与所属的constant, variable, property, or subscript的权限相同
可以设置setters的权限比getters更低
struct TrackedString {
private(set) var numberOfEdits = 0
var value: String = "" {
didSet {
numberOfEdits += 1
}
}
}
可以同时显示设置setters与getters的权限
public struct TrackedString {
public private(set) var numberOfEdits = 0
public var value: String = "" {
didSet {
numberOfEdits += 1
}
}
public init() {}
}
初始化方法的访问控制
初始化方法的权限一定要低于或等于所初始化的类,required修饰的初始化方法的权限一定要等于所属的类。和函数与方法相同,初始化方法的权限不能高于它的参数
默认的初始化方法的权限等于所初始化的类,例外:public类型的默认初始化方法的权限为internal
结构体的默认成员初始化方法:若任何的存储性属性的权限为private,那初始化便是private,若任何的存储性属性的权限为file private,那初始化便file private,其它情况便是internal
协议的访问控制
协议中定义的需求的权限自动设置为与协议相同,不能设置需求为不同的权限
协议的权限不能高于它所继承的协议
一个类型可遵守低于此类型权限的协议,但是此类型只能用于其遵守协议的权限的适用范围,此类的适用范围是此类权限与其遵守的协议的权限的最低权限的适用范围
协议的实现的权限不能低于协议的权限
类的扩展的访问控制
类的扩展的成员的默认权限与类的成员的默认权限相同
可以为扩展显示指定权限,例如:private extension
当扩展为实现协议时不能显示指定权限
泛型的访问控制
泛型的类和函数的权限是泛型本身的访问权限与它们参数的访问权限的最低权限