跳到主要内容

访问控制

问题

Swift 有几种访问控制级别?openpublic 有什么区别?模块(Module)和源文件的关系是什么?

答案

五种访问级别

从高到低排列:

级别访问范围典型用途
open任何模块可访问、继承、重写框架 API 设计(允许子类化)
public任何模块可访问,不可继承/重写框架 API 设计(限制子类化)
internal同一模块内(默认级别App 内部代码
fileprivate同一源文件内同文件中多个类型共享
private同一声明(及其扩展)内实现细节封装

open vs public

// Framework 中定义
open class BaseViewController: UIViewController {
open func setupUI() { } // 可被子类重写
public func configure() { } // 可调用,不可重写
}

// App 中使用
class MyVC: BaseViewController { // ✅ open 允许继承
override func setupUI() { } // ✅ open 允许重写
// override func configure() { } // ❌ public 不允许重写
}
设计原则
  • 库/框架 API:默认用 public,只对明确需要被继承/重写的类和方法用 open
  • App 内部:默认 internal(不写修饰符),对不需要暴露的实现用 private

private vs fileprivate

// 同一个文件 User.swift
class User {
private var password: String = "" // 仅 User 声明及其 extension 可访问
fileprivate var nickname: String = "" // 同文件内的任何类型可访问
}

extension User {
func checkPassword(_ input: String) -> Bool {
return input == password // ✅ private 在扩展中可访问(同一文件内)
}
}

// 同文件中的另一个类型
class UserHelper {
func display(_ user: User) {
print(user.nickname) // ✅ fileprivate
// print(user.password) // ❌ private
}
}
Swift 4+ 的 private 放宽

Swift 4 以后,private 声明在同一文件的扩展中也可以访问,不再限于声明所在的 {} 内。

模块(Module)概念

Module = 一个 import 单元
├── App Target(你的应用)
├── Framework Target(自定义框架)
├── Swift Package(SPM 包)
└── 系统框架(UIKit、Foundation 等)
  • 同一个 App Target 内的所有文件属于同一模块 → internal 互相可见
  • 不同 Target/Package → 需要 public / open

Getter/Setter 分别设置访问级别

struct TrackedProperty {
// 外部可读(internal),仅内部可写(private set)
private(set) var count: Int = 0

mutating func increment() {
count += 1 // ✅ 内部可以写
}
}

var prop = TrackedProperty()
print(prop.count) // ✅ 可以读
// prop.count = 10 // ❌ 外部不可以写
prop.increment() // ✅ 通过方法修改

访问控制的继承规则

public class Animal {
internal func eat() { } // internal
private func breathe() { } // private
}

// 子类的访问级别不能高于父类
internal class Dog: Animal { // ✅ internal ≤ public
// 重写时可以提升访问级别(不能降低)
public override func eat() { } // ✅ public ≥ internal
}

常见面试问题

Q1: Swift 默认的访问级别是什么?

答案internal。不写任何修饰符的声明,在同一模块内任何地方都可以访问。

Q2: 为什么需要 open,public 不够吗?

答案open vs public 体现了开放-封闭原则。框架设计者可以:

  • public 暴露 API 但禁止继承/重写(保护内部实现不被意外覆盖)
  • open 明确标记允许继承/重写的扩展点

这比 OC 的"所有方法都可以被子类重写"更安全。

Q3: private 和 fileprivate 在实际开发中如何使用?

答案

  • private默认首选,最小范围暴露,只有当前类型及其同文件扩展可用
  • fileprivate:同一文件中多个类型需要共享实现细节时使用(如 View + ViewModel 写在同一文件)

推荐优先用 private,只在编译器报错时考虑改为 fileprivate

相关链接