632 字
3 分钟
Swift 访问控制
概念
Swift的访问控制基于 模块(Module) 和 源文件(Source File) 两个维度,定义了五个访问级别(从高到低):
open
- 允许跨模块访问,且类可被继承、方法可被重写。
- 开源框架或库的公共API设计(如
UIKit
中的公开类)。
public
- 跨模块可见,但类不可被继承,方法不可被重写。
- 公共接口的内部实现(如库的底层逻辑)。
internal
(默认级别)- 仅限当前模块内访问。
- 应用或框架的内部组件交互。
fileprivate
- 同一源文件内可见。
- 同一文件内的多个类共享私有工具方法。
private
- 限定于声明的作用域(如类、结构体内部)及其扩展(若在同一文件)。
- 隐藏类内部状态或敏感数据(如银行账户的
balance
属性)。
示例对比:
// ModuleA.swift
open class OpenClass {}
public class PublicClass {}
internal class InternalClass {}
fileprivate class FilePrivateClass {}
private class PrivateClass {}
// ModuleB.swift(导入ModuleA后)
let obj1 = OpenClass() // ✅
let obj2 = PublicClass() // ✅
let obj3 = InternalClass()// ❌(不可见)
设计原则
- 级别降序原则
• 高访问级别实体不能包含更低级别的成员。例如,public
类中的属性不能是private
的。 - 函数与类型依赖
• 函数的访问级别不能高于其参数或返回值的最高级别。 - 子类与协议限制
• 子类访问级别不能高于父类,协议方法默认与协议同级别。 - 扩展的访问控制
• 扩展中的成员默认继承原类型的访问级别,但可通过显式声明调整。
示例
场景1:封装敏感数据
class BankAccount {
private var balance: Double = 0.0
public func deposit(amount: Double) {
guard amount > 0 else { return }
balance += amount
}
}
此处,balance
被标记为private
,外部无法直接修改,确保数据安全性。
场景2:跨模块框架设计
// 框架模块中声明公共API
open class NetworkManager {
open func fetchData() { /* ... */ }
public var timeout: TimeInterval = 30
}
// 应用模块继承并扩展
class CustomNetworkManager: NetworkManager {
override open func fetchData() { /* 自定义实现 */ }
}
open
允许其他模块继承和重写,而public
属性仅暴露接口。
最佳实践
- 优先使用最小可见权限
- 默认使用
internal
,仅在需要时提升级别。
- 默认使用
- 避免滥用
open
- 仅在需要跨模块继承时使用,否则用
public
减少API暴露风险。
- 仅在需要跨模块继承时使用,否则用
- 利用
fileprivate
共享工具代码- 在同一文件中复用私有逻辑,避免全局污染。