```html
专注于Swift技术分享与面试指导 | 域名:www.kaoacca.cn

Swift面试题,看这些就够了

从入门到精通,深度解析Swift 5.x核心机制。这里汇集了互联网大厂最新Swift面试真题,涵盖语言特性、内存管理、并发模型及架构设计,助您构建完整的知识体系。

⚡ Swift基础核心考点解析

在面试的初始阶段,面试官通常会通过考察Swift基础来评估候选人的语言掌握程度。与Objective-C不同,Swift强调安全性与表达力,以下是几个高频考察点:

📌 Optional 机制

Swift面试题中必问Optional。它不是简单的指针,而是一个枚举类型。Optional` 等价于 enum Optional { case none, some(T) }。面试时需解释隐式解包(Implicitly Unwrapped Optional, 如 !)的风险,以及如何使用 if let, guard let 进行安全解包。

📌 值类型与引用类型

Struct是值类型,Class是引用类型。面试常问:为什么Swift默认使用Struct?因为值类型更安全,不存在数据竞争,且性能更优(栈分配 vs 堆分配)。但在需要多态或共享状态时,必须使用Class。

📌 闭包捕获列表

闭包默认强引用捕获变量,易导致循环引用。必须使用 [weak self] 或 [unowned self]。面试重点在于区分 weak (Optional) 和 unowned (非Optional) 的使用场景及崩溃风险。

⚙️ Swift进阶:内存管理与协议

进阶面试不再局限于语法,而是深入底层原理。以下通过选项卡展示三大核心模块:

ARC 自动引用计数详解

Swift使用ARC管理内存。面试常问:循环引用如何产生?如何解决?

  • 循环引用:两个对象互相持有强引用,导致引用计数永远不为0。
  • 解决方案:使用 weak (弱引用) 或 unowned (无主引用) 打破循环。
  • 闭包循环:在捕获列表中指定捕获语义,如 [weak self] in ...。
// 示例:避免循环引用
class ViewController {
    var viewModel: ViewModel?
    func setup() {
        viewModel?.loadData { [weak self] in
            self?.updateUI()
        }
    }
}

Protocol Oriented Programming (POP)

Swift推崇面向协议编程。与OOP相比,POP更灵活,支持默认实现和组合。

  • 协议扩展:可以为协议提供默认实现,代码复用性更高。
  • 协议组合:可以使用 & 组合多个协议,如 where Self: ProtocolA & ProtocolB。
  • 泛型约束:限制类型必须符合特定协议,增强类型安全。
protocol Networkable {
    func request(completion: @escaping (Result) -> Void)
}
extension Networkable {
    func printResponse() {
        print("Executing network request")
    }
}

Runtime 与 Method Dispatch

Swift中有三种方法分发方式:

分发方式 描述 性能 适用场景
Static Dispatch 编译期确定,直接调用 最快 final函数, struct方法
Virtual Dispatch 通过vtable查找 较快 class非final方法
Dynamic Dispatch 通过objc_msgSend查找 最慢 @objc, KVO, 运行时修改

🚀 Swift并发:Actor与Async/Await

Swift 5.5引入的并发模型是近年来的Swift面试题热点。传统的GCD和OperationQueue逐渐被结构化并发取代。

概念一:Task与TaskGroup

Task 代表一个并发的异步工作单元。使用 TaskGroup 可以管理多个子任务,实现“分而治之”的并发逻辑,例如并行下载多个图片。

概念二:Actor 隔离

Actor 是一种引用类型,用于保护共享状态。与Class不同,Actor内部的状态是串行访问的,天然线程安全。面试常问:Actor与GCD的 async/await 有何区别?Actor更侧重于状态安全,而GCD侧重于任务调度。

概念三:Cancellation

Swift并发支持任务取消。通过检查 Task.isCancelled 或使用 try Task.checkCancellation() 来优雅地处理取消逻辑,避免资源浪费。

// Actor 示例
actor DataStore {
    private var data: [String] = []
    func add(_ item: String) {
        data.append(item)
    }
    func fetch() -> [String] {
        return data
    }
}
// 使用
Task {
    await store.add("Item")
    let items = await store.fetch()
}

🎨 SwiftUI vs UIKit

现代iOS开发面试必然涉及UI框架的选择与对比。

📌 UIKit (命令式)

成熟、稳定、生态完善。使用代码或Storyboard构建UI,状态管理需手动处理。适合复杂交互和遗留项目维护。

📌 SwiftUI (声明式)

未来趋势。代码即UI,状态驱动视图刷新。语法简洁,支持多平台(iOS, macOS, watchOS, tvOS)。学习曲线陡峭,但开发效率高。

📌 混合开发策略

实际项目中常采用混合模式。UIKit中使用 UIHostingController 嵌入SwiftUI视图,或反之。面试需展示对两者共存的理解。

❓ Swift面试高频问答精选

以下整理了网友最关心的Swift面试题,并提供了深度解答,总字数涵盖核心知识点,助您全面准备。

Q1: Swift中的 @objc 和 dynamic 关键字有什么区别?

@objc 是一个属性标记,告诉编译器将标记的实体暴露给Objective-C运行时。它并不强制使用动态分发,编译器仍可能进行静态优化(如内联)。

dynamic 是一个方法修饰符,强制使用Objective-C风格的动态分发(Message Sending),即 objc_msgSend。这确保了KVO(Key-Value Observing)和Runtime方法交换(Swizzling)能正常工作。

总结:如果需要KVO或Swizzling,必须同时使用 @objc 和 dynamic。

Q2: 如何优化Swift启动速度?

启动速度优化是高级开发的必备技能:
1. 减少Main Bundle大小:移除未使用的资源,使用Asset Catalog。
2. 延迟加载:非核心库(如Analytics、CrashReporter)使用懒加载或动态库。
3. 优化AppDelegate:避免在 application:didFinishLaunchingWithOptions: 中执行耗时操作。
4. 使用Pre-main Time Profiler:分析启动阶段的方法调用,消除瓶颈。
5. 减少全局变量初始化:全局变量的初始化会在Main RunLoop之前执行,耗时且不可控。

Q3: Swift中的Error处理与Result类型有何优劣?

do-catch 适合需要立即处理错误并恢复流程的场景,但链式调用不便。
Result<Success, Failure> 是Swift 5.0引入的枚举类型,将成功和失败封装为一个值。优势在于:
1. 适合异步回调和函数式编程。
2. 可以轻易组合和转换。
3. 避免了嵌套的 do-catch 块。
建议:在API层和ViewModel层使用Result,在UI层使用do-catch。

Q4: 什么是Swift的Copy-on-Write (COW)?

COW是一种性能优化技术,主要用于String, Array, Dictionary等集合类型。当值类型被赋值时,最初共享底层数据,只有当一方尝试修改数据时,才进行深拷贝。这避免了不必要的内存分配和数据复制,提升了性能。

```