访问控制模型是基于 Modules & Source Files
作用:隐藏代码的实现,指定接口能够被访问和使用
Module
- 是单一的代码分配单元 - 一个框架或应用程序会作为独立的单元构建和发布并且可以使用 Swift 的 import 关键字导入到另一个 module
- Swift 的 module 相当于每一个 Target (app bundle OR framework)
Source File
- 在一个 module 中的一个 Swift 源代码文件
- 通常每一个类型分配在单独源文件,一个源文件也可以包括定义多个类型、方法等等
五种访问等级
从高到低:open / public / internal / fileprivate / private
Open & Public
- 在被定义的 module 中使用
- 在其他 module 中使用,imports 被定义的 module
- 指定 Framework 公共接口,使用 open 和 public 修饰
Internal
- 在被定义的 module 中使用
- 在 app 或 Framework 内部结构时使用
File-private
- 在被定义的源文件中使用
Private
- 定义的范围内 + 同文件内的 extension 中使用
Open 只能用于类和类成员,以下几点不同于 Public
- < Public(类),只能在所在的 module 被子类化
- < Public(类成员),只能在所在的 module 被子类重写
- Open(类)能够在所在的 module 中被子类化,或者在任何已 import module 的 module 中被子类化
- Open(类成员)能够在所在的 module 中被子类化,或者在任何已 import module 的 module 中被子类重写
✨访问权限的原则
实体不能被另外一个低访问权限的实体定义
eg:
- 一个 public 变量不能被定义有一个 internal / file-private / private 类型定义,因为类型也许不能在 public 变量使用时有效
- 方法 level !> 参数 level & return level
默认访问等级 - internal
Unit Test Targets
除了标记 Open 和 Public,能够访问任何 internal 实体的方式:在 import module 前加 @testable
Frameworks
open / public 修饰 API
自定义类型
- 如果定义类型为 private / file-private,默认成员的访问等级也是 private / file-private
- 如果定义类型为 internal / public,默认成员的访问等级是 Internal(如果需要,用 public 修饰,提供选择性发布,避免将内部类型作为 API)
fileprivate class SomeFilePrivateClass {
func someFilePrivateMethod() {}
private func somePrivateMethod() {}
}
元祖类型
整个元祖类型的访问权限,决定于元祖中所有类型的最低访问权限,不能特指访问权限
方法类型
方法类型的访问权限,决定于方法参数类型和返回值类型的最低访问权限
func someFunction() -> (SomeInternalClass, SomePrivateClass) {
// function implementation goes here
}
// 也许会期望方法的默认访问权限为 internal,但是实际上取决于元祖类型
// 并且在这里不能用 public 和 internal 修饰改方法
枚举类型
- 不能为独立的枚举 case 指定不同的访问权限
- 独立的枚举 case 自动为枚举类型的相同访问权限
- 原生值 和 关联值 必须至少和枚举有相同的访问等级
嵌套类型
- 嵌套类型在一个 private 有一个自动 private 访问类型
- 嵌套类型在一个 file-private 类型中自动有 file-private 访问类型
- 嵌套类型在在一个 public OR internal 类型中自动有 internal 中
- 如果需要 public 类型就显式指定
子类化
- 一个子类不能有高于父类的访问权限
- 重写可以让继承的类成员比其父类更容易访问
public class A {
fileprivate func someMethod() {}
}
internal class B: A {
override internal func someMethod(){
super.someMethod()
}
}
常量、变量、属性和下标
- 不能比它的类型还高级
- 下标不能比它的索引类型和返回值更高级
private var privateInstance = SomePrivateClass()
Setter and Getter
- setter / getter 自动接收 常量、变量、属性、下标的访问等级
- fileprivate(set) / private(set) / internal(set) 修饰变量 OR 下标,这个规则应用于存储属性和计算属性
struct TrackedString {
// setter: private ; getter: internal
private(set) var numberOfEdits = 0
var value: String = "" {
didSet {
numberOfEdit += 1
}
}
}
public struct TrackedString {
// 默认是 getter internal;此时设置为 getter public
public private(set) var numberOfEdits = 0
public var value: String = "" {
didSet {
numberOfEdits += 1
}
}
public init() {}
}
初始化
- 自定义初始化器能够被定义低于或等于他们的类型
- 除了 Required 初始化器必须和类有相同的访问等级
- 初始化器的参数不能低于初始化器的本身访问等级
默认初始化器
- Swift 自动提供一个没有任何参数的默认初始化,为结构体和类的所有属性提供默认值,但没有提供初始化本身的方法
- 默认的初始化器有和类型相同的访问等级,除了public 的类型
结构体类型的默认 Memberwise 初始化器
- 如果结构体的所有存储属性是 private, 结构体类型也是 private
- 如果结构体的所有存储属性时 file-private,结构体类型也是 file-private
- 如果需要 public 结构体类型能够在另外的 module 中使用,必须提供一个 public memberwise 初始化器
协议
-requirement 自动设置与协议相同的访问等级,并且不能设置与其不同的等级,以确保所有 requirement 能够有效适用任何遵循该协议的类型
协议继承
最高访问权限为父协议的等级
协议遵循
- 一个类型能够遵循一个低于它访问等级的协议
- 一个类型遵循一个协议,访问等级为协议和类型的最低访问等级
- 一个类型遵循一个协议必须确保每一个 requirement 至少有和协议相同的访问等级
遵循协议是全局的:一个类型不能以两种不同的方式遵循一个协议
Extensions
class / structure / enumeration
-
新扩展的类成员和被扩展类型的访问等级一致
extension public / internal -> type member internal
extension private -> type member private
extension file-private -> type member file-private -
可以为所有在 extension 的成员定义一个新的等级,同样也可以针对单个成员重写
eg: private extension -
如果使用了 extension 添加协议遵循,不能提供一个显式的访问等级修饰一个扩展
在 Extension 中的私有成员
- 声明一个私有成员在初始声明中,能在同个文件的 extension 中访问
- 在 extension 中声明私有成员,其他来自同一文件的其他 extension 中访问
- 在 extension 中声明私有成员,能够被来自同个文件的初始声明中访问
泛型
泛型类型 / 泛型方法 level = minimum (泛型类型 / 泛型方法,类型参数上的类型约束)
类型别名
类型别名 level <= 类型 level
网友评论