iOS 知识体系手册 面试复习 / 项目表达 / 线上排障
Knowledge First

把 iOS 知识整理成能复述、能追问、能落地的体系

这份手册按知识域组织,不按 UI 模块组织。每章先给可以在面试中直接说出的核心结论,再补底层模型、常见追问和项目落地方式。目标是帮你建立一张稳定的 iOS 知识地图。

00

复习路径

先建立主干,再补细节。iOS 面试不是把每个 API 背出来,而是能把问题放到“语言、系统、UI、并发、网络、性能、架构、线上治理”这些层级里分析。

第一层:会说清原理

Runtime、RunLoop、ARC、Block、GCD、UIKit 渲染、HTTP/TLS 是最容易被追问的底层主干。

第二层:能结合项目

每个知识点都准备一个项目场景:比如卡顿怎么定位、启动怎么拆、OOM 如何加上下文。

第三层:能讲取舍

高级面试更关心为什么这么做、风险是什么、怎么灰度、如何验证收益。

第四层:有线上闭环

发现、定位、止血、修复、验证、复盘,能讲闭环比单点知识更有说服力。

面经高频主题

知识域 高频问题 考察重点
语言底层 属性修饰符、Block、Runtime、KVO、分类、+load+initialize 是否理解对象模型、内存语义和动态派发。
系统机制 RunLoop、事件响应、主线程渲染、GCD、锁、进程线程 是否能解释 UI 卡顿、线程安全和死锁。
工程项目 启动优化、列表优化、网络缓存、组件化、CI/CD、灰度 是否能把技术方案放进真实业务环境。
线上治理 Crash、OOM、Watchdog、卡顿、MetricKit、日志、trace、告警 是否具备线上问题闭环能力。
01

Objective-C 与内存

这一章解决“对象怎么被持有、什么时候释放、Block 捕获了什么、属性语义该怎么选”。

核心结论

对象属性默认用 strong,反向引用和 delegate 用 weak,字符串、集合和 Block 属性优先 copy,基础类型用 assign。Block 里避免循环引用用 __weak,需要修改局部变量才用 __block

属性修饰符

修饰符 语义 使用场景 常见误区
strong / retain 强引用,持有对象。 模型、服务、普通对象属性。 ARC 下常用 strongretain 多见于历史代码。
weak 弱引用,不增加引用计数,释放后自动置空。 delegate、dataSource、父子对象的反向引用。 不要用 assign 修饰对象来模拟弱引用,会产生野指针。
copy 保存副本。 NSString、集合、Block。 集合 copy 是浅拷贝,元素不会递归复制。
atomic getter/setter 单次访问具备原子性。 iOS 项目中通常不用,默认写 nonatomic atomic 不等于业务线程安全。

Block 的知识框架

存储位置

全局 Block 不捕获自动变量;栈 Block 不能逃逸;copy 后变成堆 Block,能安全保存。

捕获规则

局部自动变量默认按值捕获;对象变量通常被强捕获;self.property 捕获的是 self

__block

__block 让变量被包装成可转移的结构体,通过 forwarding 指向有效存储位置。

常见追问:为什么 NSString 用 copy?

不是因为所有字符串都会变,而是为了隔离外部传入的 NSMutableString。属性声明为 copy 后,内部状态不会被外部可变对象后续修改影响,这体现的是 API 语义稳定。

02

Runtime 与类加载

Runtime 的核心问题是“对象如何找到方法”。围绕对象、类、元类、cache、方法列表、消息转发、类加载时机展开。

核心结论

实例方法存在类对象中,类方法存在元类中。消息发送先通过 isa 找到类,再查 cache、方法列表和父类;找不到时进入动态方法解析、快速转发、完整转发,最终才是 unrecognized selector 崩溃。

消息发送流程

  1. 接收者通过 isa 找到类对象。
  2. Runtime 先查方法缓存,命中后直接调用 IMP。
  3. 缓存未命中时查当前类方法列表,再沿父类向上找。
  4. 仍找不到,调用 resolveInstanceMethod:resolveClassMethod: 动态添加方法。
  5. 快速转发 forwardingTargetForSelector: 可以换接收者。
  6. 完整转发通过 methodSignatureForSelector:forwardInvocation: 处理。

类加载与首次使用

方法 触发时机 面试重点
+load 类或分类被 Runtime 加载进进程时调用,通常早于 main 不依赖是否使用这个类;分类的 +load 都会执行;启动期不要做重活。
静态初始化 C/C++ 静态对象、全局变量构造等发生在进入业务代码前。 也会影响 pre-main,复杂初始化应尽量延迟。
+initialize 类第一次收到消息前由 Runtime 懒触发。 父类通常先于子类;可能被多线程触发;现代代码更推荐显式初始化或 dispatch_once

关联对象、分类、Swizzling

  • 关联对象:给已有对象挂额外 key-value,常用于分类“加属性”。
  • 分类:方法会合并到类方法列表,同名方法存在覆盖风险,不能依赖加载顺序做业务逻辑。
  • Swizzling:交换 selector 和 IMP,适合埋点、修复、AOP,但必须控制时机、幂等和作用范围。
03

RunLoop 与 UIKit

RunLoop 是线程事件循环,UIKit 则把事件响应、布局、渲染和动画放在主线程周期里完成。

核心结论

RunLoop 和线程一一对应。主线程 RunLoop 默认开启,子线程要保活需要添加 Source/Timer 后运行。Mode 决定当前处理哪些事件;卡顿监控常通过观察主线程 RunLoop 状态和独立线程计时来判断。

RunLoop 模型

Source

输入源,处理端口、事件、手动唤醒等。

Timer

定时器,受 Mode 影响。滚动时 Default Mode 的 Timer 可能暂停。

Observer

观察 RunLoop 状态变化,卡顿监控常用它记录主线程是否长时间停留。

UIKit 高频点

主题 要点 项目表达
事件传递 Window 从上到下 hit-test 找目标 view,响应链从目标 view 向上传递。 区分“谁被命中”和“谁处理事件”。
UIView / CALayer UIView 管事件和层级,CALayer 管显示和动画。 渲染问题常从 layer 属性、离屏渲染、图片解码分析。
AutoLayout 复杂约束和频繁更新会增加求解成本。 列表中可缓存高度,减少嵌套和动态约束。
列表性能 复用、预取、异步解码、缓存尺寸、滚动时降级非关键任务。 能结合 Feed/评论/直播列表讲优化路径。
04

并发与线程安全

并发题要分清线程、队列、任务、锁、共享状态。队列不是线程,同步/异步也不是串行/并行。

核心结论

线程是系统调度单位,GCD 队列是任务调度抽象。串行队列一次执行一个任务,并发队列可同时执行多个任务;同步会等待任务完成,异步不会等待。死锁常见于当前串行队列同步派发到自己。

GCD 组合

组合 行为 面试提醒
串行 + 同步 当前线程等待任务执行完。 在当前串行队列里 sync 到自己会死锁。
串行 + 异步 任务按顺序执行,调用方不等待。 可能新开线程,也可能复用线程。
并发 + 同步 调用方等待,任务可由当前线程或其他线程执行。 同步限制的是调用方,不是队列的并发能力。
并发 + 异步 多个任务可并发执行。 并发数由系统调度,不是无限开线程。

线程安全怎么答

  • 先指出共享可变状态在哪里。
  • 再说明用什么同步手段保护:锁、串行队列、读写锁、信号量、actor。
  • 最后补充风险:死锁、优先级反转、锁粒度过大、主线程阻塞。
05

Swift 与 SwiftUI

Swift 面试重点在值语义、协议泛型、ARC、闭包捕获、并发模型和与 Objective-C 混编边界。

核心结论

Swift 用强类型、值语义、协议和泛型提升安全性;类仍由 ARC 管理,闭包仍可能循环引用。现代并发用 async/await 表达异步流程,用 actor 隔离可变状态,用 @MainActor 约束 UI 更新。

Swift 高频点

值类型和引用类型

struct / enum 默认值语义,适合不可共享状态;class 适合身份、继承和共享生命周期。

协议和泛型

协议描述能力,泛型保留静态类型。some Protocol 是不透明类型,any Protocol 是 existential 容器。

闭包捕获

[weak self] 用于打断循环引用,但不要所有异步闭包都无脑 weak,要结合业务生命周期。

SwiftUI 状态

@State@Binding@ObservedObject@StateObject 表达不同状态来源和所有权。

06

网络与数据

网络题要能讲清端到端链路,数据题要按数据类型选存储,并说明一致性、性能、安全和迁移。

核心结论

一次 HTTPS 请求通常经过 DNS、连接建立、TLS、请求响应、缓存处理。现代 TLS 用证书验证身份,用 ECDHE 协商密钥,后续数据用对称加密。持久化上,小配置用 UserDefaults,敏感凭证用 Keychain,结构化数据用 SQLite/Core Data,大文件走文件系统缓存。

网络链路

  1. DNS 解析域名,可能受到本地、运营商、公共 DNS 缓存影响。
  2. TCP 或 QUIC 建立传输通道。
  3. TLS 完成证书校验和密钥协商。
  4. 发送请求,服务端处理并返回响应。
  5. 客户端根据缓存策略、状态码和业务错误做处理。

缓存与持久化

主题 要点 风险
HTTP 缓存 Cache-Control 是强缓存,ETag / Last-Modified 是协商缓存。 缓存策略错误会导致数据陈旧或请求量过大。
断点续传 依赖 Range 和服务端支持。 文件变化、校验不一致、resumeData 失效都要处理。
Keychain 适合 token、账号凭证、敏感标识。 注意访问组、卸载残留、迁移和权限。
SQLite/Core Data 适合结构化数据、本地索引、对象图。 重点是事务、索引、分页、迁移和并发访问。
07

启动、性能与稳定性

性能优化不是“感觉快”,而是分阶段度量、定位瓶颈、做最小改动并验证收益。稳定性则要按崩溃类型和资源异常分类治理。

核心结论

启动分为 pre-main 和 main 后。pre-main 受 Mach-O 加载、动态库、符号绑定、+load、静态初始化影响;main 后关注首屏路径。优化方向是减少启动期工作、懒加载、任务拆分、二进制重排,并用 Instruments、MetricKit 和线上指标验证。

性能问题分类

问题 常见原因 定位手段
启动慢 动态库多、+load 重、首屏同步 IO、首屏网络阻塞。 启动耗时拆解、dyld 统计、Instruments、线上启动指标。
卡顿 主线程计算、图片解码、布局求解、锁等待、同步 IO。 主线程采样、RunLoop 监控、火焰图、卡顿堆栈。
OOM 图片/视频内存、缓存失控、泄漏、峰值过高。 内存水位、Memory Graph、Jetsam/OOM 上下文。
Crash 越界、野指针、KVC/KVO、线程、生命周期、数据异常。 符号化、聚类、日志、用户路径、版本/机型/系统分布。

稳定性治理动作

  • 输入数据做边界校验,处理 nilNSNull、数组越界和类型不匹配。
  • KVO 使用唯一 context 或 token 封装,避免重复添加/移除。
  • Crash/OOM/Watchdog 上报时补充页面、场景、版本、设备、内存、CPU、磁盘和最近操作。
  • 对高风险功能准备灰度、降级和配置止血能力。
08

架构与工程化

架构面试的重点不是背 MVC/MVVM 名词,而是解释复杂业务如何拆分、依赖如何收敛、变更如何可测可回滚。

核心结论

好的 iOS 架构要降低耦合、提高可测性和交付效率。页面层处理 UI,业务层沉淀用例,数据层封装网络和缓存,基础层提供日志、路由、配置、监控等能力。组件化时要控制依赖方向,避免模块互相 import。

架构表达模板

  1. 先讲业务背景:为什么现有结构不够用了。
  2. 再讲边界:按业务、能力、页面还是基础设施拆。
  3. 说明依赖方向:谁能依赖谁,跨模块怎么通信。
  4. 说明工程配套:CI、测试、路由、资源隔离、版本管理。
  5. 最后讲收益和风险:编译时间、协作效率、问题定位、灰度回滚。

常见模式

MVC

系统协作成本低,适合简单页面;风险是 Controller 膨胀。

MVVM

适合展示逻辑多、状态转换复杂的页面;要避免 ViewModel 变成另一个“大控制器”。

Clean / VIPER

适合多人协作和复杂业务规则;风险是文件和协议数量较多。

组件化

适合大型 App 和多团队并行;关键是模块边界、依赖治理和路由协议。

09

线上监控与排障

线上监控不是接一个 SDK,而是形成从指标到定位、止血、修复、验证的闭环。你本地的 `ios-client` 项目就体现了这种完整监控栈。

核心结论

线上监控要覆盖 Crash/OOM/Watchdog、启动和卡顿、CPU/内存/磁盘/电量、网络错误、页面黑白屏、业务漏斗和日志 trace。指标异常后要能定位版本、设备、系统、页面、实验、用户路径和最近操作。

监控指标

层级 核心指标 排障动作
稳定性 Crash 率、OOM/FOOM、Watchdog、CPU Block、异常类型。 符号化、聚类、回溯变更、灰度止血、补上下文。
性能 冷启动、热启动、TTI、首帧、FPS、卡顿率、长卡顿。 Instruments、MetricKit、火焰图、启动任务拆解。
资源 footprint、resident、CPU、线程数、wakeups、磁盘、电量。 按页面和场景采集水位,结合内存图、缓存、图片解码分析。
网络 成功率、状态码、错误码、耗时、DNS/TLS/TCP、重试、流量。 弱网复现、traceId 串联服务端、降级和重试策略检查。
体验和业务 黑白屏、内容错位、点击无响应、曝光、点击、转化、支付成功率。 截图/视图树/日志打包,按页面、版本、实验、人群归因。

线上问题闭环

  1. 发现:告警、看板、Crash 聚类、用户反馈。
  2. 定位:版本、系统、机型、页面、实验、网络环境、用户路径。
  3. 止血:配置降级、关闭实验、回滚灰度、熔断高风险功能。
  4. 修复:补代码、补校验、补监控、补测试。
  5. 验证:指标回落、灰度观察、复盘沉淀。
10

安全、发布与基础能力

这部分常作为综合能力追问:证书签名、隐私权限、发布灰度、算法、操作系统、网络和数据库基础。

核心结论

iOS 安全从代码签名和沙盒开始,网络侧依赖 ATS/TLS,敏感数据放 Keychain,权限访问要最小化并说明用途。发布上要管理证书、描述文件、符号表、灰度、崩溃监控和审核合规。

发布检查

  • 构建:版本号、环境、证书、Profile、编译参数、符号表上传。
  • 提审:权限描述、隐私清单、支付规则、后台能力、第三方 SDK 合规。
  • 灰度:按版本、人群、地区、设备、实验逐步放量。
  • 发布后:重点看 Crash、启动、核心转化、网络错误和用户反馈。

算法和基础

算法

数组、字符串、链表、栈队列、哈希表、树、二分、滑动窗口、动态规划入门。

操作系统

进程线程、锁、内存、调度、上下文切换、虚拟内存。

网络基础

TCP、HTTP、TLS、DNS、缓存、弱网、重试和幂等。

数据库

索引、事务、分页、迁移、并发读写、本地缓存一致性。