Swift

访问控制

本文详细介绍了 Swift 中的访问控制机制,包括五种访问级别(open, public, internal, file-private, private)的区别、使用场景以及在自定义类型、子类化、扩展中的应用。

访问控制(Access Control)限制了其他源文件和模块对你的代码的访问。这对于隐藏代码的实现细节、指定明确的接口非常重要。

访问级别 (Access Levels)

Swift 提供了五种不同的访问级别,从高到低依次为:

  1. open:最高访问级别。允许在定义模块之外被访问和子类化(仅限类)。
  2. public:允许在定义模块之外被访问,但不能被子类化(对于类)或重写(对于成员)。
  3. internal:默认访问级别。允许在定义模块内的任何源文件中访问,但不能在模块外访问。
  4. fileprivate:限制在当前源文件中访问。
  5. private:最低访问级别。限制在当前定义的作用域(及其扩展,如果在同一文件中)内访问。

访问控制语法

通过在实体声明前添加修饰符来指定访问级别:

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() {}

自定义类型

如果定义了一个自定义类型,你可以为其指定一个显式的访问级别。

public class A {
    fileprivate func someMethod() {} // 在 A 的定义文件中可见
}

internal class B {
    var someProperty: Int = 0 // 默认为 internal
}

private class C {
    // 这里的成员默认为 private
    func someMethod() {}
}

类型的访问级别会影响其成员(属性、方法、初始化器等)的默认访问级别。

  • 如果类型是 publicinternal,成员默认为 internal
  • 如果类型是 fileprivate,成员默认为 fileprivate
  • 如果类型是 private,成员默认为 private

子类化 (Subclassing)

子类的访问级别不能高于父类的访问级别。例如,你不能编写一个 public 的子类继承自一个 internal 的父类。

public class A {}
internal class B: A {} // 正确
// public class C: B {} // 错误:C (public) 的访问级别高于 B (internal)

此外,子类可以重写父类的成员,并提供更高的访问级别(但不能更低)。

public class A {
    fileprivate func someMethod() {}
}

internal class B: A {
    override internal func someMethod() {
        super.someMethod()
    }
}

Getter 和 Setter

你可以为 setter 指定比 getter 更低的访问级别,以限制属性的读写权限。

struct TrackedString {
    // 外部只读 (internal),内部可读写 (private)
    private(set) var numberOfEdits = 0
    
    var value: String = "" {
        didSet {
            numberOfEdits += 1
        }
    }
}

总结

  • open/public:用于库的公共接口。
  • internal:用于应用内的模块级共享(默认)。
  • fileprivate:用于文件内的实现细节共享。
  • private:用于完全隐藏实现细节。
  • private(set):常用的模式,用于创建“外部只读,内部可写”的属性。
在 GitHub 上编辑

上次更新于