632 字
3 分钟
Swift 访问控制
2025-03-13

概念#

Swift的访问控制基于 模块(Module)源文件(Source File) 两个维度,定义了五个访问级别(从高到低):

  1. open
    • 允许跨模块访问,且类可被继承、方法可被重写。
    • 开源框架或库的公共API设计(如 UIKit 中的公开类)。
  2. public
    • 跨模块可见,但类不可被继承,方法不可被重写。
    • 公共接口的内部实现(如库的底层逻辑)。
  3. internal(默认级别)
    • 仅限当前模块内访问。
    • 应用或框架的内部组件交互。
  4. fileprivate
    • 同一源文件内可见。
    • 同一文件内的多个类共享私有工具方法。
  5. 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()// ❌(不可见)  

设计原则#

  1. 级别降序原则
    • 高访问级别实体不能包含更低级别的成员。例如,public类中的属性不能是private的。
  2. 函数与类型依赖
    • 函数的访问级别不能高于其参数或返回值的最高级别。
  3. 子类与协议限制
    • 子类访问级别不能高于父类,协议方法默认与协议同级别。
  4. 扩展的访问控制
    • 扩展中的成员默认继承原类型的访问级别,但可通过显式声明调整。

示例#

场景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属性仅暴露接口。


最佳实践#

  1. 优先使用最小可见权限
    • 默认使用internal,仅在需要时提升级别。
  2. 避免滥用open
    • 仅在需要跨模块继承时使用,否则用public减少API暴露风险。
  3. 利用fileprivate共享工具代码
    • 在同一文件中复用私有逻辑,避免全局污染。
Swift 访问控制
https://blog.lpkt.cn/posts/swift-access-ctrl/
作者
lollipopkit
发布于
2025-03-13
许可协议
CC BY-NC-SA 4.0