一、iOS基础核心:从ObjC到Swift的思维转变

在当前的中,基础知识的考察依然占据重要地位。虽然Swift已成为主流,但Objective-C作为iOS开发的基石,其底层机制仍是面试官考察候选人技术深度的关键切入点。许多求职者往往忽视了消息机制与运行时的重要性,导致在面试中失分。

1.1 Objective-C 消息机制

Objective-C 是一门动态语言,它的所有调用最终都会转化为 objc_msgSend 函数调用。理解这一点是掌握OC动态性的核心。

核心考点:消息发送流程

当执行 [obj method] 时,编译器会将其转换为:
objc_msgSend(obj, @selector(method))
运行时系统会在 obj 的类方法缓存中查找 IMP,若未找到则向父类查找,最后进行消息转发。

1.2 Swift 与 OC 的本质区别

Swift 是一种静态类型语言,强调安全性和性能。在面试中,常考 Swift 的值类型与引用类型的区别。Struct 是值类型,存储在栈上(通常),Copy-on-Write 机制保证了其高效性;Class 是引用类型,存储在堆上,通过 ARC 管理内存。

// Swift 值类型示例
struct Point {
    var x = 0.0, y = 0.0
}
var p1 = Point(x: 1.0, y: 1.0)
var p2 = p1
p2.x = 2.0 // p1 不受影响,因为是值类型

二、内存管理:iOS开发的灵魂

内存管理是iOS面试中频率最高的话题之一。无论是 ARC 机制还是手动内存管理,理解其底层原理对于避免内存泄漏、循环引用至关重要。

2.1 ARC 与 引用计数

ARC (Automatic Reference Counting) 在编译期自动插入 retain/release/autorelease 调用。面试中常问:ARC 是如何工作的?

  • ⚡ Strong: 强引用,增加引用计数。
  • ⚡ Weak: 弱引用,不增加引用计数,对象释放后自动置为 nil。
  • ⚡ Unowned: 无主引用,类似 weak,但不会在对象释放后自动置为 nil,使用不当会导致崩溃。

2.2 循环引用及其解决

循环引用发生在两个对象互相持有对方的强引用时,导致引用计数永远不为0,内存泄漏。在 Swift 中,解决闭包循环引用的标准做法是使用捕获列表 (Capture List)。

关键字 行为描述 适用场景 潜在风险
weak 弱引用,指向 nil 时安全 Delegate, 闭包中避免循环引用 无(需处理 nil 情况)
unowned 无主引用,假设始终有值 闭包中确定会捕获 self 且生命周期短 对象释放后访问会崩溃
strong 强引用,保持对象存活 绝大多数属性声明 易导致循环引用

2.3 内存泄漏检测工具

除了静态代码分析,开发者应熟练掌握 Instruments 中的 Allocations 和 Zombies 工具。Allocations 用于观察内存分配趋势,Zombies 用于追踪野指针访问。

三、并发编程:GCD 与 Async/Await

随着 iOS 13 的发布,Swift Concurrency (Async/Await) 逐渐成为主流,但 GCD (Grand Central Dispatch) 依然是底层基石。理解两者的关系与区别,是高级 iOS 工程师的必备技能。

GCD 核心概念

Dispatch Queue 分为串行队列 (Serial) 和并发队列 (Concurrent)。Dispatch Source 用于处理底层事件。面试重点在于理解 Barrier (屏障) 的作用,它可以在并发队列中实现读写锁的效果,保证数据一致性。

let queue = DispatchQueue(label: "com.example.concurrent", attributes: .concurrent)
queue.async { / 读 / }
queue.async(flags: .barrier) { / 写 - 独占执行 / }
queue.async { / 读 / }

Swift Concurrency

Async/Await 语法糖极大地简化了异步代码的编写,避免了“回调地狱”。其核心在于 Actor 模型,通过数据隔离保证线程安全,无需手动加锁。

关键概念:Task, Actor, Sendable。Sendable 协议用于标记可以在线程间安全传递的数据。

线程同步机制

除了 GCD 和 Actor,传统的锁机制如 NSLock, pthread_mutex, dispatch_semaphore 仍需了解。信号量 (Semaphore) 常用于限制并发数量,如图片下载时的并发控制。

四、UI 布局与性能优化

UI 是用户直接接触的部分,其流畅度直接影响用户体验。在 iOS常见面试题 中,关于 渲染原理 和 卡顿优化 的问题层出不穷。

4.1 渲染流程

iOS 的 UI 渲染主要涉及 CPU 和 GPU 的协作。
1. CPU: 布局计算 (Layout), 生成 Layer Tree。
2. GPU: 光栅化 (Rasterization), 合成 (Compositing), 显示到屏幕。
优化核心在于减少 CPU 的计算量,并减少 Layer 的数量和层级深度。

4.2 常见卡顿原因与解决方案

原因一:主线程阻塞

在主线程执行耗时操作(如网络请求、大文件解析、复杂计算)。
解决:将耗时操作移至后台线程。

原因二:过度重绘

频繁调用 setNeedsDisplay 或布局计算过于复杂。
解决:使用 shouldRasterize 缓存图层,或优化布局算法。

原因三:图片过大

加载高分辨率图片导致内存抖动和光栅化耗时。
解决:使用 SDWebImage 等库进行异步加载和缓存,按需缩放。

4.3 AutoLayout 与 Frame

虽然 AutoLayout 灵活,但在高性能列表(如 UITableView/UICollectionView)中,过多的 AutoLayout 约束会导致布局计算耗时。建议:Cell 内部尽量使用 Frame 或简单的 AutoLayout,Cell 与 Cell 之间使用 AutoLayout。

五、架构设计与设计模式

现代 iOS 应用越来越复杂,良好的架构设计是项目可维护性的保障。MVC、MVVM、VIPER 等架构模式在面试中常被讨论。

5.1 MVC 的局限性

在传统的 MVC 中,Controller 往往变得过于庞大(Massive View Controller),承担了过多的业务逻辑。这违反了单一职责原则。

5.2 MVVM 的普及

MVVM (Model-View-ViewModel) 通过 数据绑定 机制(如 Combine, RxSwift, 或 Swift 5.5+ 的 Observation)实现 View 与 ViewModel 的同步,大大减少了 Controller 的代码量,并使逻辑更易测试。

5.3 响应式编程

RxSwift 和 Combine 是响应式编程的代表。它们将事件流作为一等公民,适合处理复杂的异步逻辑和用户交互。面试中常问:Combine 与 RxSwift 的区别?(主要在于 Apple 原生支持、学习曲线及社区生态)。

六、Swift 高级特性与底层原理

Swift 不仅是语法的变化,更是底层实现的革新。理解 Swift 的底层机制,能让你在编写高性能代码时游刃有余。

6.1 闭包捕获与内存

Swift 闭包默认捕获外部变量的值(对于值类型)或引用(对于引用类型)。若闭包在类方法中被使用,需注意 self 的捕获语义。

6.2 协议与泛型

Swift 的协议可以关联类型 (Associated Types),泛型则提供了类型安全。面试常考:协议扩展 (Protocol Extension) 的作用?(提供默认实现,代码复用)。

6.3 值类型 vs 引用类型

再次强调,Swift 鼓励使用 Struct。Struct 的 Copy-on-Write (COW) 机制保证了在修改时才会真正拷贝数据,兼顾了安全性与性能。在集合操作(如数组、字典)中,理解 COW 能避免不必要的性能损耗。