iOS 面试题汇总 (2025-2026)
整理来源:GitHub 热门面试题仓库 + 2025-2026 年趋势分析
目录
一、Swift 核心基础
1. let vs var 的区别?
答案:
-
let声明常量,不可修改 -
var声明变量,可以修改
let constant = "Cannot change" // 编译错误
var variable = "Can change"
variable = "Changed!" // OK
**追问: ** let 修饰的类实例,可以修改其属性吗?
-
可以,
let修饰的是引用不可变,不是对象内部属性不可变
2. struct vs class 的区别?
答案:
| 特性 | Struct | Class |
|------|--------|-------|
| 类型 | 值类型 | 引用类型 |
| 继承 | ❌ 不支持 | ✅ 支持 |
| 默认初始化器 | ✅ memberwise | ❌ 需要自定义 |
| ARC | ❌ 不需要 | ✅ 需要 |
| 修饰方法 | 需要 mutating | 不需要 |
使用场景:
-
Struct: 数据容器、优先不可变性、不需要继承、线程安全重要
-
Class: 需要标识性、需要继承、需要引用语义
3. Optional 是什么?如何解包?
答案:
Optional 表示可能有值也可能为 nil,使用 ? 定义
var name: String? = "John"
解包方法:
// 1. 强制解包 (危险,可能崩溃)
let unwrapped = name!
// 2. Optional Binding (安全)
if let safeName = name {
print(safeName)
}
// 3. Guard
guard let safeName = name else { return }
// 4. Nil Coalescing
let result = name ?? "Default"
// 5. Optional Chaining
let length = name?.count
4. Property Wrapper 是什么?
答案:
属性包装器,为属性添加可复用的行为逻辑
@propertyWrapper
struct Clamped<Value: Comparable> {
var wrappedValue: Value {
didSet {
wrappedValue = min(max(wrappedValue, range.lowerBound), range.upperBound)
}
}
let range: ClosedRange<Value>
}
struct Player {
@Clamped(range: 0...100) var health: Int = 100
}
常见包装器: @State, @Published, @AppStorage, @UserDefaults
5. Protocol-Oriented Programming (POP) 为什么 Swift 叫面向协议编程?
答案:
Swift 优先使用协议而不是继承,协议支持多重继承和扩展默认实现
protocol Drawable {
func draw()
}
// 扩展提供默认实现
extension Drawable {
func draw() { print("Default drawing") }
}
struct Circle: Drawable {
func draw() { print("Drawing circle") }
}
// 协议组合
typealias Displayable = Drawable & CustomStringConvertible
优点:
-
组合优于继承
-
支持值类型
-
默认实现
-
多重遵循
6. 什么是 Opaque Type?
答案:
使用 some 关键字隐藏具体返回类型
protocol Shape {
func draw()
}
struct Circle: Shape {
func draw() { print("Drawing Circle") }
}
func getShape() -> some Shape {
return Circle()
}
二、内存管理 (ARC)
7. 什么是 ARC?
答案:
ARC (Automatic Reference Counting) 自动管理内存,跟踪对象的引用计数
class Person {
let name: String
init(name: String) { self.name = name }
deinit { print("\(name) deinitialized") }
}
var person1: Person? = Person(name: "John") // RC = 1
var person2 = person1 // RC = 2
person1 = nil // RC = 1
person2 = nil // RC = 0 -> deinit called
8. Strong vs Weak vs Unowned 的区别?
答案:
| 类型 | 引用计数 | 可选性 | 使用场景 |
|------|----------|--------|----------|
| strong | +1 | N/A | 默认,持有对象 |
| weak | 0 | 必须可选 | 代理模式、父引用 |
| unowned | 0 | 非可选 | 已知生命周期内有效 |
class Parent {
var child: Child?
}
class Child {
weak var parent: Parent? // 避免循环引用
unowned let owner: Parent // 假设始终有效
}
9. 如何避免 Retain Cycle?
答案:
使用 weak 或 unowned 打破循环引用
class ViewModel {
var data: String = ""
func load() {
// ❌ 循环引用
networkCall { self.data = $0 }
// ✅ Weak self
networkCall { [weak self] result in
self?.data = result
}
// ✅ Unowned (如果确定有效)
networkCall { [unowned self] result in
self.data = result
}
}
}
10. 什么是循环引用 (Retain Cycle)?
答案:
两个对象相互持有强引用,导致 ARC 无法释放内存
class A {
var b: B?
}
class B {
var a: A?
}
// 如果 A 持有 B,B 持有 A,都无法释放
11. Struct 需要 ARC 吗?
**答案: **
不需要。Struct 是值类型,存储在栈上,赋值时复制,不使用 ARC
struct User {
var name: String
}
var user1 = User(name: "John")
var user2 = user1 // 复制一份
user2.name = "Jane" // user1 不受影响
三、Swift 进阶
12. Value Type vs Reference Type?
**答案: **
-
**值类型: ** 存储自己的数据副本,赋值时创建新副本
-
**引用类型: ** 共享同一内存位置
// 值类型 (Struct)
struct Car {
var name: String
}
var car1 = Car(name: "BMW")
var car2 = car1
car2.name = "Audi"
// car1.name 仍是 "BMW"
// 引用类型 (Class)
class Person {
var name: String
}
var p1 = Person(name: "John")
var p2 = p1
p2.name = "Jane"
// p1.name 变成 "Jane"
13. Stored Property vs Computed Property?
**答案: **
-
**存储属性: ** 实际存储值
-
**计算属性: ** 每次访问时计算,不存储
struct Rectangle {
var width: Double
var height: Double
// 计算属性
var area: Double {
return width * height
}
}
let rect = Rectangle(width: 5, height: 4)
print("Area:", rect.area) // 20.0
14. Lazy Initialization 懒加载?
**答案: **
lazy 修饰的属性只在首次访问时初始化
class DataManager {
lazy var data: String = {
print("Loading data...")
return "Loaded Data"
}()
}
let manager = DataManager()
print(manager.data) // 首次访问时打印 "Loading data..."
print(manager.data) // 直接返回 "Loaded Data"
15. Property Observer 属性观察器?
**答案: **
监听属性值变化,使用 willSet 和 didSet
var score: Int = 0 {
willSet {
print("Will change to \(newValue)")
}
didSet {
print("Changed from \(oldValue) to \(score)")
}
}
score = 10
// Will change to 10
// Changed from 0 to 10
16. Tuple 元组?
**答案: **
组合多个不同类型的值
let person = ("John", 28, true)
// 命名
let namedPerson = (name: "John", age: 28)
// 访问
print(person.0) // John
print(namedPerson.name) // John
17. defer 的用法?
**答案: **
在作用域结束前执行代码,常用于清理工作
func test() {
defer { print("Clean up 2") }
defer { print("Clean up 1") }
print("Start")
}
// 输出: Start -> Clean up 1 -> Clean up 2
18. inout 参数?
**答案: **
允许函数修改原始值,传入时加 &
func increase(value: inout Int) {
value += 1
}
var num = 5
print("Before:", num) // 5
increase(value: &num)
print("After:", num) // 6
19. Generics 泛型?
**答案: **
编写灵活可复用的代码,适用于任意类型
func swapValues<T>(_ a: inout T, _ b: inout T) {
let temp = a
a = b
b = temp
}
var first = 10
var second = 20
swapValues(&first, &second)
print(first, second) // 20 10
四、函数式编程
20. Closure 闭包?
**答案: **
自包含的代码块,可以捕获周围上下文的变量
// 完整写法
let greet = { (name: String) in
print("Hello \(name)")
}
greet("John")
// 简写
let numbers = [1, 2, 3, 4]
let doubled = numbers.map { $0 * 2 }
print(doubled) // [2, 4, 6, 8]
21. map vs flatMap vs compactMap?
**答案: **
| 函数 | 作用 | 示例 |
|------|------|------|
| map | 转换每个元素 | [1,2,3].map { $0 * 2 } → [2,4,6] |
| flatMap | 扁平化嵌套数组 | [[1,2],[3,4]].flatMap { $0 } → [1,2,3,4] |
| compactMap | 移除 nil 并解包 | ["1","2","a"].compactMap { Int($0) } → [1,2] |
// map
let numbers = [1, 2, 3]
let doubled = numbers.map { $0 * 2 }
// flatMap
let array = [[1, 2], [3, 4]]
let flat = array.flatMap { $0 }
// compactMap
let values = ["1", "2", "abc"]
let numbers = values.compactMap { Int($0) }
22. filter vs reduce?
**答案: **
-
**filter: ** 返回符合条件的元素
-
**reduce: ** 合并为单个值
// filter
let numbers = [1, 2, 3, 4, 5]
let even = numbers.filter { $0 % 2 == 0 } // [2, 4]
// reduce
let sum = numbers.reduce(0) { $0 + $1 } // 15
五、并发编程 (重点!)
23. Synchronous vs Asynchronous?
**答案: **
-
**同步 (Sync): ** 任务依次执行,等待上一个完成
-
**异步 (Async): ** 任务在后台运行,不等待继续执行
// GCD 示例
DispatchQueue.global().async {
print("Background task") // 后台执行
}
print("Main thread continues") // 立即执行
24. GCD 是什么?
**答案: **
Grand Central Dispatch,低级线程管理 API
// 主线程
DispatchQueue.main.async {
print("Update UI")
}
// 后台队列
DispatchQueue.global().async {
// 后台任务
}
// 自定义队列
let myQueue = DispatchQueue(label: "com.myapp.queue")
myQueue.async {
// 任务
}
25. async/await (现代 Swift 异步)?
**答案: **
Swift 并发的现代写法,让异步代码像同步一样简洁
// Async 函数
func fetchUser() async throws -> User {
let url = URL(string: "https://api.example.com/user")!
let (data, _) = try await URLSession.shared.data(from: url)
return try JSONDecoder().decode(User.self, from: data)
}
// 调用
Task {
do {
let user = try await fetchUser()
print(user)
} catch {
print(error)
}
}
26. Actor 是什么?
**答案: **
Actor 是引用类型,保护数据免于数据竞争,同时只有一个任务能访问
actor BankAccount {
private var balance: Double = 0
func deposit(_ amount: Double) {
balance += amount
}
func withdraw(_ amount: Double) -> Bool {
guard balance >= amount else { return false }
balance -= amount
return true
}
}
// 使用 (必须 await)
let account = BankAccount()
await account.deposit(100)
27. @MainActor 的作用?
**答案: **
确保代码在主线程运行,用于 UI 更新
@MainActor
class ViewModel: ObservableObject {
@Published var data: [Item] = []
func load() async {
// 自动在主线程运行
data = await fetchData()
}
}
// 或指定代码在主线程执行
await MainActor.run {
self.updateUI()
}
28. Task vs TaskGroup?
**答案: **
-
**Task: ** 创建单个异步任务
-
**TaskGroup: ** 管理多个子任务
// Task
Task {
await fetchData()
}
// TaskGroup
await withTaskGroup(of: Int.self) { group in
group.addTask { return 1 }
group.addTask { return 2 }
for await result in group {
print(result)
}
}
29. async let 的用法?
**答案: **
并行执行多个异步任务
func fetchTwoThings() async {
async let first = fetchData()
async let second = fetchOtherData()
let result = await (first, second)
print(result)
}
30. Continuation 是什么?
**答案: **
将回调风格代码转为 async/await
func fetch() async -> String {
await withCheckedContinuation { continuation in
someAsyncTask { result in
continuation.resume(returning: result)
}
}
}
六、架构设计
31. MVC vs MVVM?
**答案: **
| 架构 | 组件 | 说明 |
|------|------|------|
| MVC | Model-View-Controller | UIKit 默认架构 |
| MVVM | Model-View-ViewModel | SwiftUI 常用,分离业务逻辑 |
// MVVM 示例
class UserViewModel: ObservableObject {
@Published var name: String = "John"
@Published var isLoading: Bool = false
}
32. VIPER 架构?
**答案: **
高度解耦的架构:
-
View - 展示 UI
-
Interactor - 业务逻辑
-
Presenter - 准备展示数据
-
Entity - 数据模型
-
Router - 导航管理
适用于大型项目
33. Coordinator 模式?
**答案: **
将导航逻辑从 ViewController 中分离
protocol Coordinator {
func start()
}
class AppCoordinator: Coordinator {
var navigationController: UINavigationController
init(navigationController: UINavigationController) {
self.navigationController = navigationController
}
func start() {
let vc = UIViewController()
navigationController.pushViewController(vc, animated: true)
}
}
34. Singleton 单例?
**答案: **
确保类只有一个全局实例
class NetworkManager {
static let shared = NetworkManager()
private init() { }
}
// 使用
NetworkManager.shared.request(...)
35. Decorator 装饰器模式?
**答案: **
动态为对象添加新行为,不修改原类
protocol Coffee {
func cost() -> Double
}
class SimpleCoffee: Coffee {
func cost() -> Double { return 5 }
}
class MilkDecorator: Coffee {
var coffee: Coffee
init(coffee: Coffee) { self.coffee = coffee }
func cost() -> Double { return coffee.cost() + 2 }
}
七、UIKit & SwiftUI
36. iOS App 生命周期?
**答案: **
Not Running → Inactive → Active → Background → Suspended
| 状态 | 说明 |
|------|------|
| Not Running | 未启动 |
| Inactive | 前台但无事件响应 |
| Active | 前台正常运行 |
| Background | 后台运行 |
| Suspended | 暂停,无执行 |
37. UIViewController 生命周期?
**答案: **
viewDidLoad()
→ viewWillAppear()
→ viewDidAppear()
→ viewWillDisappear()
→ viewDidDisappear()
override func viewDidLoad() {
super.viewDidLoad()
print("View Loaded") // 只调用一次
}
override func viewWillAppear(_ animated: Bool) {
super.viewWillAppear(animated)
// 每次出现前调用
}
38. Delegate vs NotificationCenter?
**答案: **
| 模式 | 特点 | 使用场景 |
|------|------|----------|
| Delegate | 一对一通信 | UITableViewDelegate |
| NotificationCenter | 一对多广播 | 系统通知 |
// Delegate
protocol DataDelegate: AnyObject {
func didReceiveData(_ data: String)
}
// Notification
NotificationCenter.default.post(
name: Notification.Name("DataUpdated"),
object: nil
)
39. KVO 是什么?
**答案: **
Key-Value Observing,监听属性变化
class Person: NSObject {
@objc dynamic var name: String = ""
}
person.observe(\.name) { person, change in
print("Name changed to \(person.name)")
}
40. @State vs @Binding vs @StateObject vs @ObservedObject?
**答案: **
| 包装器 | 所有权 | 类型 | 用途 |
|--------|--------|------|------|
| @State | View 拥有 | 值类型 | 简单本地状态 |
| @Binding | 引用 | 值类型 | 向下传递状态 |
| @StateObject | View 创建 | 引用类型 | 创建并拥有 ObservableObject |
| @ObservedObject | 外部注入 | 引用类型 | 注入的 ObservableObject |
struct ParentView: View {
@State private var count = 0
@StateObject var viewModel = ViewModel()
var body: some View {
ChildView(count: $count) // 传递 binding
}
}
struct ChildView: View {
@Binding var count: Int
@ObservedObject var vm: ViewModel
}
八、Networking & Data
41. iOS 网络请求?
**答案: **
现代 Swift 使用 async/await
func fetchUsers() async throws -> [User] {
let url = URL(string: "https://api.example.com/users")!
let (data, response) = try await URLSession.shared.data(from: url)
guard let httpResponse = response as? HTTPURLResponse,
httpResponse.statusCode == 200 else {
throw NetworkError.invalidResponse
}
return try JSONDecoder().decode([User].self, from: data)
}
42. Core Data vs SQLite?
**答案: **
| 特性 | Core Data | SQLite |
|------|-----------|--------|
| 类型 | Apple 官方 | 轻量级 |
| 复杂度 | 高 | 低 |
| 性能 | 中 | 高 |
| 适用 | 对象图管理 | 简单数据 |
43. 图片缓存方案?
**答案: **
-
SDWebImage(Objective-C) -
Kingfisher(Swift)
// Kingfisher 示例
imageView.kf.setImage(
with: URL(string: "https://example.com/image.png"),
placeholder: UIImage(named: "placeholder")
)
九、算法 Coding 题
44. 反转链表
func reverseList(_ head: ListNode?) -> ListNode? {
var prev: ListNode? = nil
var current = head
while current != nil {
let next = current?.next
current?.next = prev
prev = current
current = next
}
return prev
}
45. 判断回文串
func isPalindrome(_ s: String) -> Bool {
let chars = s.lowercased().filter { $0.isLetter || $0.isNumber }
return chars == String(chars.reversed())
}
46. 两数之和
func twoSum(_ nums: [Int], _ target: Int) -> [Int] {
var map = [Int: Int]()
for (index, num) in nums.enumerated() {
if let complement = map[target - num] {
return [complement, index]
}
map[num] = index
}
return []
}
47. 二叉树前序遍历
func preorderTraversal(_ root: TreeNode?) -> [Int] {
var result = [Int]()
func traverse(_ node: TreeNode?) {
guard let node = node else { return }
result.append(node.val)
traverse(node.left)
traverse(node.right)
}
traverse(root)
return result
}
十、2025-2026 面试重点趋势
🔥 必考重点
| 排名 | 知识点 | 考频 |
|------|--------|------|
| 1 | Swift Concurrency (async/await, Actor) | ⭐⭐⭐⭐⭐ |
| 2 | SwiftUI (@StateObject, MVVM) | ⭐⭐⭐⭐⭐ |
| 3 | 内存管理 (weak/unowned 场景) | ⭐⭐⭐⭐ |
| 4 | 闭包 Retain Cycle | ⭐⭐⭐⭐ |
| 5 | 值类型 vs 引用类型 | ⭐⭐⭐⭐ |
📈 新增热点
-
** @MainActor** 在 SwiftUI 中的使用
-
TaskGroup 并发任务管理
-
Property Wrapper 原理
-
SwiftUI Performance 优化
-
Combine 响应式编程
💡 面试建议
-
手写代码 是必须的,熟练掌握基本算法
-
Swift 官方文档 是最重要的复习资料
-
实际项目经验 会重点问,特别是你简历上的项目
-
性能优化 问题增多 (启动速度、内存、流畅度)
📅 最后更新:2026年3月
来源:GitHub 热门面试题仓库 + 2025-2026 年面试趋势分析