一、iOS基础核心:从ObjC到Swift的思维转变
在当前的
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 能避免不必要的性能损耗。