访问控制
问题
Swift 有几种访问控制级别?open 和 public 有什么区别?模块(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。