14-12.【模块化与包管理】Swift 中 internal、fileprivate、private、public、open 的作用和适用场景?

5 阅读3分钟

在 Swift 中,访问控制(Access Control)遵循一个核心原则:实体只能在它被定义的上下文中访问,除非你显式提升了它的权限。

这五个关键字构成了 Swift 的权限金字塔,从最严格到最宽松排列如下:


1. private(最严格)

作用范围: 仅限在**当前定义的作用域({})**以及同文件内的扩展(extension)中访问。

  • 适用场景:

    • 隐藏类的内部实现细节(如私有属性、辅助方法)。
    • 防止外部直接修改状态,确保封装性。
    • 优化编译性能(编译器可以确定该属性不会被外部修改,从而进行内联优化)。

2. fileprivate

作用范围: 仅限在**当前源文件(.swift 文件)**内访问。

  • 适用场景:

    • 当一个文件内有多个类、结构体需要共享某些属性,但不希望文件外部看到时。
    • 在同一个文件中定义复杂的逻辑拆分,但仍保持逻辑闭环。

3. internal(默认级别)

作用范围: 在**整个模块(Module / Target)**内均可访问,但模块外部不可见。

  • 适用场景:

    • App 项目内部的大部分代码。
    • 在同一个 Swift Package 或 Framework 内,不同类之间的协作。
    • 注意: 如果不写任何关键字,Swift 默认就是 internal

4. public

作用范围: 可以在模块外部访问(即被其他 App 或 Library import 后使用)。

  • 适用场景:

    • 定义框架(Framework)对外的 API。
    • 允许外部调用,但禁止外部在其定义的模块外进行继承(Subclass)或重写(Override)。
  • 限制: 保证了库的稳定性,防止用户通过继承破坏库的内部逻辑。

5. open(最宽松)

作用范围:public 相同,但允许在模块外部进行继承和重写

  • 适用场景:

    • 设计需要被用户高度定制的框架类(如 UIKitUIViewController)。
    • 仅适用于类(Class)和类成员,不适用于结构体和枚举。

访问权限对比与关系

为了更直观地理解,可以参考以下表格:

级别跨文件访问 (同模块)跨模块访问 (import)跨模块继承/重写默认级别
private❌ (仅限作用域)
fileprivate✅ (仅限同文件)
internal
public
open

核心建议:如何选择?

  1. 坚持“最小特权原则” :默认先使用 private,当发现无法访问时再逐步放开。这不仅能保护数据安全,还能让编译器更好地优化代码。

  2. 区分“调用者”与“继承者”

    • 如果你希望别人只能用你的代码,用 public
    • 如果你希望别人能扩展你的功能,用 open
  3. 针对多模块项目

    • 即使是同一项目,拆分成不同 Package 后,只有标记为 publicopen 的部分才能跨模块通信。
  4. 属性 Setter 的特殊处理

    • 你可以使用 private(set) public var count: Int。这意味着外面的人能读取 count,但只有内部能修改它。这在状态管理中非常实用。