如何通过Swift面试:高级别热门问题
iOS开发职位的面试不仅考察UIKit和SwiftUI的知识。在高级别,招聘人员和技术主管希望确认你理解内存工作原理、在引用计数上下文中class与struct的区别、如何通过协议正确构建架构以及如何管理异步操作。本文将分析Swift中高级和资深级别面试中常见的关键主题。
1. 内存管理与ARC(自动引用计数)
ARC是面试中最常见的主题之一。你不仅需要了解理论,还要能够解释如何避免内存泄漏。
1.1. ARC如何工作?强引用循环有哪些?
ARC自动计算类对象的强引用数量。当计数器变为零时,对象从内存中释放。当两个对象相互强引用时,就会产生循环(retain cycle)。
class Parent { var child: Child?}
class Child { var parent: Parent? // 反向强引用}
var parent: Parent? = Parent()var child: Child? = Child()parent?.child = childchild?.parent = parent// 两个对象永远不会被释放1.2. 如何打破循环?
使用weak或unowned。weak是一个可选引用,当对象被释放时会自动变为nil。unowned是非可选引用,但假定对象的生命周期至少与引用它的对象一样长。
class Child { weak var parent: Parent? // 弱引用}1.3. ARC如何处理闭包?
闭包会捕获外部变量。如果闭包作为类的属性存储,并且在内部使用了self,就会产生循环。解决方案是使用[weak self]或[unowned self]。
class NetworkManager { var completionHandler: (() -> Void)? func fetchData() { completionHandler = { [weak self] in guard let self = self else { return } self.processData() } } func processData() { }}2. 闭包:escaping vs non-escaping
理解escaping和non-escaping闭包的区别是任何高级职位的必备知识点。
2.1. 什么是escaping闭包?
如果闭包可以在函数返回后被调用,则称为escaping。默认情况下,所有闭包都是non-escaping——编译器知道它们将在函数体内执行。对于异步操作(例如网络请求),需要显式指定@escaping。
func performAsyncTask(completion: @escaping (String) -> Void) { DispatchQueue.global().async { // 模拟耗时任务 sleep(2) completion("完成") }}2.2. 为什么non-escaping闭包更快?
编译器会优化non-escaping闭包——它不必将它们复制到堆(heap)中,而是可以存储在栈上。它还可以避免引用计数,因为闭包的生命周期仅限于函数调用。
3. 泛型与关联类型协议(PAT)
泛型是Swift的基础。在面试中,你可能会被要求编写一个泛型结构或解释带有关联类型的协议如何工作。
3.1. 编写一个泛型队列(Queue)
struct Queue<T> { private var elements: [T] = [] mutating func enqueue(_ value: T) { elements.append(value) } mutating func dequeue() -> T? { guard !elements.isEmpty else { return nil }