iOS2025年面试汇总

5 阅读5分钟

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?

答案:

使用 weakunowned 打破循环引用


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 属性观察器?

**答案: **

监听属性值变化,使用 willSetdidSet


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 响应式编程

💡 面试建议

  1. 手写代码 是必须的,熟练掌握基本算法

  2. Swift 官方文档 是最重要的复习资料

  3. 实际项目经验 会重点问,特别是你简历上的项目

  4. 性能优化 问题增多 (启动速度、内存、流畅度)


📅 最后更新:2026年3月

 

来源:GitHub 热门面试题仓库 + 2025-2026 年面试趋势分析