<?xml version="1.0" encoding="utf-8" standalone="yes"?><rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:content="http://purl.org/rss/1.0/modules/content/"><channel><title>IOS开发 on Last Stand</title><link>https://amatsuzero.github.io/LastStand/categories/ios%E5%BC%80%E5%8F%91/</link><description>Recent content in IOS开发 on Last Stand</description><generator>Hugo</generator><language>zh-cn</language><lastBuildDate>Sun, 21 Jun 2026 22:41:52 +0800</lastBuildDate><atom:link href="https://amatsuzero.github.io/LastStand/categories/ios%E5%BC%80%E5%8F%91/index.xml" rel="self" type="application/rss+xml"/><item><title>Swift 面试：ARC 与内存管理源码解析</title><link>https://amatsuzero.github.io/LastStand/posts/swiftinterviewsourcecode/arc-memory-management/</link><pubDate>Tue, 16 Jun 2026 09:06:27 +0800</pubDate><guid>https://amatsuzero.github.io/LastStand/posts/swiftinterviewsourcecode/arc-memory-management/</guid><description>&lt;h1 id="swift-面试arc-与内存管理源码解析"&gt;Swift 面试：ARC 与内存管理源码解析&lt;/h1&gt;
&lt;p&gt;Swift 面试里问 ARC，通常不是想听一句“自动引用计数”。真正要答清楚的是：&lt;strong&gt;对象头里有什么、strong / weak / unowned 到底差在哪里、编译器什么时候插入或消除 retain/release、为什么闭包会循环引用&lt;/strong&gt;。&lt;/p&gt;
&lt;p&gt;这篇文章按面试题展开。先给可以直接回答的版本，再把结论落到 Swift 源码里的对象布局、引用计数状态机和 SIL ARC 优化。&lt;/p&gt;
&lt;h2 id="面试高频问题"&gt;面试高频问题&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;Swift 的 ARC 和 Objective-C 的 ARC 有什么区别？&lt;/li&gt;
&lt;li&gt;Swift 对象的引用计数存在哪里？&lt;/li&gt;
&lt;li&gt;strong、weak、unowned 的底层差异是什么？&lt;/li&gt;
&lt;li&gt;为什么 weak 在对象释放后会自动变成 nil？&lt;/li&gt;
&lt;li&gt;为什么 unowned 访问已释放对象会崩溃？&lt;/li&gt;
&lt;li&gt;闭包为什么容易造成循环引用？&lt;/li&gt;
&lt;li&gt;编译器会如何优化 retain/release？&lt;/li&gt;
&lt;li&gt;值类型是否完全不参与 ARC？&lt;/li&gt;
&lt;li&gt;ARC 和 Copy-on-Write 有什么关系？&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="30-秒回答版"&gt;30 秒回答版&lt;/h2&gt;
&lt;p&gt;Swift ARC 是编译器和运行时共同完成的内存管理机制。&lt;/p&gt;
&lt;p&gt;编译器在 SIL 阶段根据所有权语义插入 &lt;code&gt;retain_value&lt;/code&gt;、&lt;code&gt;release_value&lt;/code&gt;、&lt;code&gt;strong_retain&lt;/code&gt;、&lt;code&gt;strong_release&lt;/code&gt; 等引用计数指令，并通过 ARC 优化尽量消除冗余 retain/release。运行时负责真正维护对象的引用计数。&lt;/p&gt;
&lt;p&gt;对原生 Swift 堆对象来说，对象头包含两部分：&lt;code&gt;metadata&lt;/code&gt; 和 &lt;code&gt;refCounts&lt;/code&gt;。源码里 &lt;code&gt;HeapObject&lt;/code&gt; 的注释明确说 &lt;code&gt;metadata&lt;/code&gt; 总是指向一个有效的 metadata 对象，&lt;code&gt;refCounts&lt;/code&gt; 是 Swift heap object header 的非 Objective-C 成员。&lt;/p&gt;</description></item><item><title>objc4 类加载、read_images 与类实现化</title><link>https://amatsuzero.github.io/LastStand/posts/ocsourcecodeanalysis/class-realization-explained/</link><pubDate>Mon, 01 Jun 2026 19:50:12 +0800</pubDate><guid>https://amatsuzero.github.io/LastStand/posts/ocsourcecodeanalysis/class-realization-explained/</guid><description>&lt;h1 id="objc4-类加载read_images-与类实现化"&gt;objc4 类加载、read_images 与类实现化&lt;/h1&gt;
&lt;p&gt;本文解释 Objective-C runtime 从 dyld 通知镜像映射，到读取类、处理 future class、realize class、methodize class、附着 category 的主干流程。 重点源码来自 &lt;code&gt;runtime/objc-runtime-new.mm&lt;/code&gt;、&lt;code&gt;objc-runtime-new.h&lt;/code&gt;、&lt;code&gt;objc-os.mm&lt;/code&gt;、&lt;code&gt;objc-class.mm&lt;/code&gt; 及相关测试。&lt;/p&gt;
&lt;p&gt;&lt;a href="#purpose"&gt;作用&lt;/a&gt; &lt;a href="#structures"&gt;核心结构&lt;/a&gt; &lt;a href="#flow"&gt;关键流程&lt;/a&gt; &lt;a href="#tests"&gt;测试视角&lt;/a&gt;&lt;/p&gt;
&lt;h2 id="一这条链路的作用"&gt;一、这条链路的作用&lt;/h2&gt;
&lt;h3 id="把-mach-o-中的静态元数据变成运行时可用的类"&gt;把 Mach-O 中的静态元数据变成运行时可用的类&lt;/h3&gt;
&lt;p&gt;编译器把类、元类、方法列表、协议列表、属性列表和 ivar 布局写入 Mach-O 的 Objective-C sections。 这些数据起初主要是只读的 &lt;code&gt;class_ro_t&lt;/code&gt;。runtime 加载镜像时要登记类名、修正 selector/protocol/class 引用，并在必要时分配可写的 &lt;code&gt;class_rw_t&lt;/code&gt;。&lt;/p&gt;
&lt;h3 id="延迟成本同时保证消息发送能看到正确结构"&gt;延迟成本，同时保证消息发送能看到正确结构&lt;/h3&gt;
&lt;p&gt;大量类可以保持未 realized 状态，直到非懒加载、&lt;code&gt;+load&lt;/code&gt;、消息发送、Swift 桥接或显式 API 需要它们。 realize 时才连接父类和元类、修正 ivar 偏移、初始化 cache、复制运行时标志，并把方法列表整理成可查找的形态。&lt;/p&gt;
&lt;p&gt;简化理解：&lt;code&gt;read_images&lt;/code&gt; 是“发现并登记”；&lt;code&gt;readClass&lt;/code&gt; 是“读一个类声明并处理 future/remap”；&lt;code&gt;realizeClassWithoutSwift&lt;/code&gt; 是“把类接入运行时继承图”；&lt;code&gt;methodizeClass&lt;/code&gt; 是“准备方法/协议/属性并合并 category”。&lt;/p&gt;
&lt;h2 id="二核心类结构和关键字段"&gt;二、核心类/结构和关键字段&lt;/h2&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;结构&lt;/th&gt;
&lt;th&gt;关键字段&lt;/th&gt;
&lt;th&gt;作用&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;objc_class&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;superclass&lt;/code&gt;、&lt;code&gt;cache&lt;/code&gt;、&lt;code&gt;bits&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;类对象本体。&lt;code&gt;bits&lt;/code&gt; 初始可指向 &lt;code&gt;class_ro_t&lt;/code&gt;，realize 后指向 &lt;code&gt;class_rw_t&lt;/code&gt; 并夹带 fast flags。&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;class_ro_t&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;flags&lt;/code&gt;、&lt;code&gt;instanceStart&lt;/code&gt;、&lt;code&gt;instanceSize&lt;/code&gt;、&lt;code&gt;name&lt;/code&gt;、&lt;code&gt;baseMethods&lt;/code&gt;、&lt;code&gt;ivars&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;编译期只读描述。包含类名、方法、协议、属性、ivar 布局和 root/meta/future/realized 等 ABI 标志。&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;class_rw_t&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;flags&lt;/code&gt;、&lt;code&gt;ro_or_rw_ext&lt;/code&gt;、&lt;code&gt;firstSubclass&lt;/code&gt;、&lt;code&gt;nextSiblingClass&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;运行时可写状态。保存 realized/initialized/constructing 等状态，并把类接入子类链。&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;class_rw_ext_t&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;ro&lt;/code&gt;、&lt;code&gt;methods&lt;/code&gt;、&lt;code&gt;properties&lt;/code&gt;、&lt;code&gt;protocols&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;当类需要扩展列表时分配。category 附着后，方法/属性/协议列表通常进入这里。&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;method_list_t&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;entsizeAndFlags&lt;/code&gt;、&lt;code&gt;count&lt;/code&gt;、方法条目&lt;/td&gt;
&lt;td&gt;方法列表。加载时会 uniquing selector，必要时排序并标记 fixed-up。&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;category_t&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;cls&lt;/code&gt;、&lt;code&gt;instanceMethods&lt;/code&gt;、&lt;code&gt;classMethods&lt;/code&gt;、&lt;code&gt;protocols&lt;/code&gt;、&lt;code&gt;instanceProperties&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;分类元数据。目标类已 realized 时立即附着，否则暂存到 unattached categories。&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;header_info&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;classlist&lt;/code&gt;、&lt;code&gt;nlclslist&lt;/code&gt;、&lt;code&gt;catlist&lt;/code&gt;、&lt;code&gt;selrefs&lt;/code&gt;、&lt;code&gt;protocolrefs&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;一个 Mach-O 镜像的 ObjC 元数据索引。&lt;code&gt;objc-os.mm&lt;/code&gt; 中 &lt;code&gt;addHeader&lt;/code&gt; 负责创建或取出它。&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;h3 id="类数据从-ro-切换到-rw"&gt;类数据从 ro 切换到 rw&lt;/h3&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-cpp" data-lang="cpp"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;struct&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;objc_class&lt;/span&gt; &lt;span style="color:#f92672"&gt;:&lt;/span&gt; objc_object {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; Class superclass;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; cache_t cache;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; class_data_bits_t bits; &lt;span style="color:#75715e"&gt;// 未实现时指向 class_ro_t，实现后指向 class_rw_t
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;};
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;struct&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;class_rw_t&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;uint32_t&lt;/span&gt; flags; &lt;span style="color:#75715e"&gt;// RW_REALIZED、RW_FUTURE、RW_INITIALIZED 等
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; explicit_atomic&lt;span style="color:#f92672"&gt;&amp;lt;&lt;/span&gt;uintptr_t&lt;span style="color:#f92672"&gt;&amp;gt;&lt;/span&gt; ro_or_rw_ext;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; Class firstSubclass;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; Class nextSiblingClass;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;};
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;&lt;code&gt;class_data_bits_t::safe_ro()&lt;/code&gt; 允许在并发 realize 场景下安全取出 ro。 &lt;code&gt;setData()&lt;/code&gt; 则在 realization 或构造阶段把 &lt;code&gt;objc_class::bits&lt;/code&gt; 改成 rw 指针，并设置 &lt;code&gt;FAST_IS_RW_POINTER&lt;/code&gt;。&lt;/p&gt;</description></item><item><title>APM-B端平台设计</title><link>https://amatsuzero.github.io/LastStand/posts/interview/ios-apm/b%E7%AB%AF%E5%B9%B3%E5%8F%B0%E8%AE%BE%E8%AE%A1/</link><pubDate>Thu, 07 May 2026 15:42:48 +0800</pubDate><guid>https://amatsuzero.github.io/LastStand/posts/interview/ios-apm/b%E7%AB%AF%E5%B9%B3%E5%8F%B0%E8%AE%BE%E8%AE%A1/</guid><description>&lt;p&gt;B 端 APM 平台的目标不是“展示所有数据”，而是让研发团队在最短路径内完成：&lt;strong&gt;发现问题、判断影响、定位原因、分配负责人、验证修复、防止再次劣化&lt;/strong&gt;。&lt;/p&gt;
&lt;hr&gt;
&lt;h2 id="一信息架构"&gt;一、信息架构&lt;/h2&gt;
&lt;pre class="mermaid"&gt;flowchart TB
Home["质量概览"] --&gt; Stability["稳定性"]
Home --&gt; Performance["性能体验"]
Home --&gt; Network["网络"]
Home --&gt; Session["用户会话"]
Home --&gt; Release["版本发布"]
Home --&gt; Alert["告警中心"]
Home --&gt; Config["SDK 配置"]
Stability --&gt; Crash["Crash"]
Stability --&gt; Watchdog["Watchdog"]
Stability --&gt; FOOM["FOOM"]
Performance --&gt; Launch["启动"]
Performance --&gt; View["页面"]
Performance --&gt; Freeze["卡顿/掉帧"]
Performance --&gt; Resource["资源"]
Release --&gt; Gray["灰度对比"]
Release --&gt; Gate["发布门禁"]
Alert --&gt; Rule["规则"]
Alert --&gt; Notify["通知"]
Alert --&gt; Silence["静默"]
&lt;/pre&gt;
&lt;p&gt;一级导航不要按技术实现命名，比如 Kafka、ClickHouse、符号化任务；应该按用户任务命名，比如稳定性、性能体验、网络、发布、告警。&lt;/p&gt;
&lt;hr&gt;
&lt;h2 id="二首页质量概览"&gt;二、首页质量概览&lt;/h2&gt;
&lt;p&gt;首页回答三个问题：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;当前版本稳不稳？&lt;/li&gt;
&lt;li&gt;过去一段时间有没有变差？&lt;/li&gt;
&lt;li&gt;最应该处理的 Top 问题是什么？&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;核心卡片：&lt;/p&gt;</description></item><item><title>死锁（Deadlock）原理、常见场景与治理</title><link>https://amatsuzero.github.io/LastStand/posts/interview/ios-performance/deadlock-%E6%AD%BB%E9%94%81/</link><pubDate>Mon, 04 May 2026 16:28:56 +0800</pubDate><guid>https://amatsuzero.github.io/LastStand/posts/interview/ios-performance/deadlock-%E6%AD%BB%E9%94%81/</guid><description>&lt;p&gt;死锁是 iOS 多线程开发中最隐蔽、也最致命的一类稳定性问题。它不像越界、空指针那样&amp;quot;立刻崩溃给你看&amp;quot;，而是表现为主线程&amp;quot;卡住&amp;quot;——用户能感受到界面无响应、无法交互，最终被 iOS watchdog 强杀（&lt;code&gt;0x8BADF00D&lt;/code&gt;），落在 Apple 崩溃日志里归为 &lt;code&gt;EXC_CRASH (SIGKILL)&lt;/code&gt; 或卡死（Hang）。&lt;/p&gt;
&lt;p&gt;本文系统梳理死锁的&lt;strong&gt;四个必要条件&lt;/strong&gt;、iOS 生产环境中&lt;strong&gt;常见的发生场景&lt;/strong&gt;，并结合 Apple 官方工具（TSan、Main Thread Checker、MetricKit）与业界最新实践（Sentry App Hangs、字节 Heimdallr、Swift Concurrency 的反思）讨论&lt;strong&gt;如何检测与治理&lt;/strong&gt;。&lt;/p&gt;
&lt;hr&gt;
&lt;h2 id="一死锁是什么"&gt;一、死锁是什么&lt;/h2&gt;
&lt;p&gt;死锁（Deadlock）指两个或多个线程因争夺资源（锁、队列、信号量等）而互相等待，导致所有相关线程永久阻塞、无法推进的状态。&lt;/p&gt;
&lt;p&gt;与死锁容易混淆的几个概念：&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;名称&lt;/th&gt;
&lt;th&gt;核心特征&lt;/th&gt;
&lt;th&gt;典型例子&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;死锁 Deadlock&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;多个线程循环等待对方持有的资源，永久阻塞&lt;/td&gt;
&lt;td&gt;线程 A 持 lockA 等 lockB；线程 B 持 lockB 等 lockA&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;活锁 Livelock&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;线程不阻塞但也不推进，不停重试互相让步&lt;/td&gt;
&lt;td&gt;两个线程都检测到冲突就回退重试，永远撞在一起&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;饥饿 Starvation&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;低优先级线程长期分不到资源&lt;/td&gt;
&lt;td&gt;高优先级线程持续抢占 CPU，导致低优先级线程持锁永远运行不完&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;优先级反转 Priority Inversion&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;低优先级持锁 + 高优先级自旋等锁 + 中优先级抢 CPU，高优先级被间接阻塞&lt;/td&gt;
&lt;td&gt;&lt;code&gt;OSSpinLock&lt;/code&gt; 被废弃的根本原因&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;死循环 Busy Loop&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;单线程进入无限循环，CPU 占用 100%&lt;/td&gt;
&lt;td&gt;&lt;code&gt;while(true)&lt;/code&gt; 忘记 break&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;卡顿 Hang&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;主线程执行时间超过阈值（几百 ms～几秒）&lt;/td&gt;
&lt;td&gt;主线程做网络、解压大图、Core Data 大量 fetch&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;卡死 Watchdog&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;主线程卡住数秒（启动约 20s、前后台切换约 10s），触发系统强杀&lt;/td&gt;
&lt;td&gt;死锁导致的卡死是最严重的一种&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;关键区别&lt;/strong&gt;：死循环线程 CPU 占用高、处于 &lt;code&gt;RUNNING&lt;/code&gt; 态；死锁线程 CPU 占用为 0、处于 &lt;code&gt;WAITING/BLOCKED&lt;/code&gt; 态并被换出。这一点正是线上死锁自动判定的核心依据（见&amp;quot;检测&amp;quot;章节）。&lt;/p&gt;</description></item><item><title>AFNetworking 源码导读</title><link>https://amatsuzero.github.io/LastStand/posts/interview/ios-source-analysis/afnetworking%E6%BA%90%E7%A0%81%E5%AF%BC%E8%AF%BB/</link><pubDate>Sat, 02 May 2026 22:32:27 +0800</pubDate><guid>https://amatsuzero.github.io/LastStand/posts/interview/ios-source-analysis/afnetworking%E6%BA%90%E7%A0%81%E5%AF%BC%E8%AF%BB/</guid><description>&lt;blockquote&gt;
&lt;p&gt;本文基于 &lt;strong&gt;AFNetworking 4.0.1&lt;/strong&gt;（2020 年发布，仓库最后一次迭代）源码进行分析。AFNetworking 虽然已进入&amp;quot;稳定休眠&amp;quot;状态，但它作为 iOS 网络层的教科书级实现，其 &lt;code&gt;NSURLSession&lt;/code&gt; 封装、HTTPS 校验、Multipart 流式上传、Method Swizzling 等设计思路至今仍值得每一位 iOS 工程师学习。源码仓库：&lt;a href="https://github.com/AFNetworking/AFNetworking"&gt;AFNetworking/AFNetworking&lt;/a&gt;。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;hr&gt;
&lt;h2 id="一整体架构"&gt;一、整体架构&lt;/h2&gt;
&lt;p&gt;AFNetworking 的整个库只有 &lt;strong&gt;7 个核心类&lt;/strong&gt;，按职责划分为&amp;quot;核心会话&amp;quot;、&amp;ldquo;序列化&amp;rdquo;、&amp;ldquo;安全&amp;rdquo;、&amp;ldquo;可达性&amp;rdquo;、&amp;ldquo;UIKit 扩展&amp;quot;五个子模块（对应 CocoaPods Subspec 拆分）：&lt;/p&gt;
&lt;pre class="mermaid"&gt;graph TB
subgraph "核心会话层 (NSURLSession 封装)"
A["AFURLSessionManager&lt;br/&gt;NSURLSession 代理总线"]
B["AFHTTPSessionManager&lt;br/&gt;HTTP 便利方法 GET/POST/..."]
C["AFURLSessionManagerTaskDelegate&lt;br/&gt;每个 Task 的代理持有者"]
end
subgraph "序列化层 (Serialization)"
D["AFHTTPRequestSerializer&lt;br/&gt;URL 编码 / 头部 / User-Agent"]
E["AFJSONRequestSerializer&lt;br/&gt;AFPropertyListRequestSerializer"]
F["AFStreamingMultipartFormData&lt;br/&gt;AFMultipartBodyStream (流式上传)"]
G["AFHTTPResponseSerializer&lt;br/&gt;+ JSON/XML/Image/PropertyList"]
end
subgraph "安全层 (Security)"
H["AFSecurityPolicy&lt;br/&gt;SSL Pinning (None/Certificate/PublicKey)"]
end
subgraph "可达性层 (Reachability)"
I["AFNetworkReachabilityManager&lt;br/&gt;基于 SCNetworkReachability"]
end
subgraph "UI 扩展 (UIKit+AFNetworking)"
J["UIImageView+AFNetworking&lt;br/&gt;UIButton+AFNetworking&lt;br/&gt;UIActivityIndicatorView+AFNetworking ..."]
end
B --&gt; A
A --&gt; C
A --&gt; D
A --&gt; G
A --&gt; H
A --&gt; I
D --&gt; E
D --&gt; F
J --&gt; B
&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;源码目录一览&lt;/strong&gt;（&lt;code&gt;AFNetworking 4.0.1&lt;/code&gt;）：&lt;/p&gt;</description></item><item><title>App启动流程</title><link>https://amatsuzero.github.io/LastStand/posts/interview/ios-basics/app%E5%90%AF%E5%8A%A8%E6%B5%81%E7%A8%8B/</link><pubDate>Sat, 02 May 2026 22:32:27 +0800</pubDate><guid>https://amatsuzero.github.io/LastStand/posts/interview/ios-basics/app%E5%90%AF%E5%8A%A8%E6%B5%81%E7%A8%8B/</guid><description>&lt;h2 id="启动类型概览"&gt;启动类型概览&lt;/h2&gt;
&lt;p&gt;iOS应用启动分为三种类型：&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;启动类型&lt;/th&gt;
&lt;th&gt;描述&lt;/th&gt;
&lt;th&gt;特点&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;冷启动（Cold Launch）&lt;/td&gt;
&lt;td&gt;App完全不在内存中，需要从头开始加载&lt;/td&gt;
&lt;td&gt;耗时最长，需要完整执行所有启动流程&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;热启动（Warm Launch）&lt;/td&gt;
&lt;td&gt;App在后台被挂起（Suspended），重新进入前台&lt;/td&gt;
&lt;td&gt;最快，只需恢复App状态，不需要重新创建进程&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;预热启动（Pre-warm Launch）&lt;/td&gt;
&lt;td&gt;系统预测用户可能启动App，提前在后台执行部分启动流程&lt;/td&gt;
&lt;td&gt;iOS 15+引入，介于冷启动和热启动之间&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;pre class="mermaid"&gt;graph LR
subgraph "冷启动（耗时最长）"
A1[创建进程] --&gt; A2[加载dylib]
A2 --&gt; A3[Rebase/Bind]
A3 --&gt; A4[+load]
A4 --&gt; A5[main]
A5 --&gt; A6[首帧渲染]
end
subgraph "预热启动（iOS 15+）"
B1[系统提前完成（后台）:&lt;br/&gt;创建进程 → 加载dylib → Rebase/Bind] --&gt; B2[用户点击后执行:&lt;br/&gt;+load → main → 首帧渲染]
end
subgraph "热启动（最快）"
C1[唤醒进程] --&gt; C2[WillEnterForeground]
C2 --&gt; C3[DidBecomeActive]
C3 --&gt; C4[恢复UI]
end
&lt;/pre&gt;
&lt;hr&gt;
&lt;h1 id="一冷启动cold-launch"&gt;一、冷启动（Cold Launch）&lt;/h1&gt;
&lt;p&gt;冷启动是最完整的启动流程，也是启动优化的主要关注点。&lt;/p&gt;
&lt;h2 id="冷启动流程概览"&gt;冷启动流程概览&lt;/h2&gt;
&lt;pre class="mermaid"&gt;flowchart TD
Start([App 冷启动流程]) --&gt; PreMain
subgraph PreMain["Pre-main 阶段"]
direction TB
A[加载可执行文件] --&gt; B[加载动态库&lt;br/&gt;（包括 Swift Runtime）]
B --&gt; C[Rebase &amp; Bind]
C --&gt; D[ObjC Runtime 初始化&lt;br/&gt;（类注册、Category 附加）]
D --&gt; D2[Swift Runtime 元数据注册&lt;br/&gt;（类型元数据、协议遵循表）]
D2 --&gt; D3[调用 +load 方法]
D3 --&gt; E[执行 Initializers&lt;br/&gt;（C++静态构造函数、__attribute__）]
end
PreMain --&gt; MainPhase
subgraph MainPhase["main 阶段"]
direction TB
F[main函数] --&gt; G[UIApplicationMain]
G --&gt; H[AppDelegate回调]
H --&gt; I[首帧渲染&lt;br/&gt;（创建Window、RootViewController、首屏UI）]
end
MainPhase --&gt; End([启动完成])
&lt;/pre&gt;
&lt;hr&gt;
&lt;h2 id="pre-main-阶段"&gt;Pre-main 阶段&lt;/h2&gt;
&lt;p&gt;Pre-main阶段是指从用户点击App图标到main函数执行之前的过程，这个阶段主要由dyld（动态链接器）负责。&lt;/p&gt;</description></item><item><title>Instruments详解</title><link>https://amatsuzero.github.io/LastStand/posts/interview/ios-advanced/instruments%E8%AF%A6%E8%A7%A3/</link><pubDate>Sat, 02 May 2026 22:32:27 +0800</pubDate><guid>https://amatsuzero.github.io/LastStand/posts/interview/ios-advanced/instruments%E8%AF%A6%E8%A7%A3/</guid><description>&lt;p&gt;Instruments 是 Xcode 内置的性能分析套件，基于 DTrace/Apple Trace 基础设施构建，可以对 iOS、iPadOS、macOS、watchOS、tvOS、visionOS 的应用与系统进行 CPU、内存、图形、能耗、网络、I/O 等各个维度的观测。&lt;/p&gt;
&lt;p&gt;Xcode 26（WWDC25）对 Instruments 做了近年来最大规模的升级，重点包括：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Power Profiler&lt;/strong&gt;：全新的能耗分析工具，支持 Tethered 与 Passive 两种录制模式。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;下一代 SwiftUI instrument&lt;/strong&gt;：基于 Cause &amp;amp; Effect Graph 可视化状态变更到视图更新的因果链。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Processor Trace&lt;/strong&gt;：基于 Apple Silicon 硬件特性的&amp;quot;全量指令级&amp;quot;采集（Xcode 16.3 引入，26 完善）。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;CPU Counters 重做&lt;/strong&gt;：引入 Bottleneck Analysis 方法论与 CPU Bottlenecks 模板。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Foundation Models instrument&lt;/strong&gt;：为 FoundationModels 框架提供 Prompt / Asset Loading / Inference 分阶段观测。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Animation Hitches 重做&lt;/strong&gt;：修正多显示器场景下的统计，数据量显著减少，处理更快。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;UI 重设计&lt;/strong&gt;：主菜单精简、Settings 页面重写、Track 次级菜单、Launch/Attach 环境变量配置。&lt;/li&gt;
&lt;/ul&gt;
&lt;hr&gt;
&lt;h2 id="一instruments-基础"&gt;一、Instruments 基础&lt;/h2&gt;
&lt;h3 id="11-启动-instruments-的几种方式"&gt;1.1 启动 Instruments 的几种方式&lt;/h3&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;方式&lt;/th&gt;
&lt;th&gt;使用场景&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Xcode &lt;code&gt;Product → Profile&lt;/code&gt;（⌘I）&lt;/td&gt;
&lt;td&gt;日常开发，自动以 Release 模式编译并附加符号&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Xcode &lt;code&gt;Debug Navigator&lt;/code&gt; 中的图表&lt;/td&gt;
&lt;td&gt;粗略观测 CPU / Memory / Disk / Network / Energy&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;直接打开 &lt;code&gt;Instruments.app&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;对已安装的 App、系统进程或已录制的 &lt;code&gt;.trace&lt;/code&gt; 文件进行分析&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;命令行 &lt;code&gt;xcrun xctrace record&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;CI / 自动化性能回归&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;设备端 Developer Settings 的 Power Profiler&lt;/td&gt;
&lt;td&gt;离线、无 Mac 场景采集能耗数据&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;blockquote&gt;
&lt;p&gt;Xcode 26 中，&lt;code&gt;Product → Profile&lt;/code&gt; 会按默认 scheme 的 Profile 构建配置（通常是 Release + &lt;code&gt;-O&lt;/code&gt;），这与 Debug 模式的数据差异很大，做性能评估时必须用 Profile 构建。&lt;/p&gt;</description></item><item><title>MVC架构详解</title><link>https://amatsuzero.github.io/LastStand/posts/interview/ios-architecture/mvc/</link><pubDate>Sat, 02 May 2026 22:32:27 +0800</pubDate><guid>https://amatsuzero.github.io/LastStand/posts/interview/ios-architecture/mvc/</guid><description>&lt;h2 id="什么是mvc"&gt;什么是MVC&lt;/h2&gt;
&lt;p&gt;MVC（Model-View-Controller）是Apple官方推荐的iOS应用架构模式，也是最基础、最常见的架构。它将应用分为三个核心组件：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Model（模型）&lt;/strong&gt;：负责数据和业务逻辑&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;View（视图）&lt;/strong&gt;：负责界面展示&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Controller（控制器）&lt;/strong&gt;：负责协调Model和View&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="mvc的结构apple-mvc"&gt;MVC的结构（Apple MVC）&lt;/h2&gt;
&lt;pre class="mermaid"&gt;graph TD
V[View&lt;br/&gt;UIView] --&gt;|用户事件| C[Controller&lt;br/&gt;UIViewController]
C --&gt;|更新UI| V
C &lt;--&gt;|读写数据| M[Model&lt;br/&gt;数据层]
&lt;/pre&gt;
&lt;blockquote&gt;
&lt;p&gt;在Apple的MVC中，View和Model之间不能直接通信，所有交互都必须通过Controller中转。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h3 id="model模型层"&gt;Model（模型层）&lt;/h3&gt;
&lt;p&gt;Model负责：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;数据的存储和管理&lt;/li&gt;
&lt;li&gt;业务逻辑处理&lt;/li&gt;
&lt;li&gt;网络请求和数据持久化&lt;/li&gt;
&lt;li&gt;数据验证&lt;/li&gt;
&lt;/ul&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-swift" data-lang="swift"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;// Model示例&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;struct&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;User&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;let&lt;/span&gt; id: Int
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;let&lt;/span&gt; name: String
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;let&lt;/span&gt; email: String
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;var&lt;/span&gt; isValidEmail: Bool {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;let&lt;/span&gt; emailRegex = &lt;span style="color:#e6db74"&gt;&amp;#34;[A-Z0-9a-z._%+-]+@[A-Za-z0-9.-]+&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;\\&lt;/span&gt;&lt;span style="color:#e6db74"&gt;.[A-Za-z]{2,64}&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;let&lt;/span&gt; emailPredicate = NSPredicate(format: &lt;span style="color:#e6db74"&gt;&amp;#34;SELF MATCHES %@&amp;#34;&lt;/span&gt;, emailRegex)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;return&lt;/span&gt; emailPredicate.evaluate(with: email)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; }
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;class&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;UserService&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;func&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;fetchUser&lt;/span&gt;(id: Int, completion: @escaping (Result&amp;lt;User, Error&amp;gt;) -&amp;gt; Void) {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#75715e"&gt;// 网络请求逻辑&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; }
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h3 id="view视图层"&gt;View（视图层）&lt;/h3&gt;
&lt;p&gt;View负责：&lt;/p&gt;</description></item><item><title>编译优化-Bazel方案</title><link>https://amatsuzero.github.io/LastStand/posts/interview/ios-build/bazel%E6%96%B9%E6%A1%88/</link><pubDate>Sat, 02 May 2026 22:32:27 +0800</pubDate><guid>https://amatsuzero.github.io/LastStand/posts/interview/ios-build/bazel%E6%96%B9%E6%A1%88/</guid><description>&lt;p&gt;当 iOS 工程的规模突破 CocoaPods / Xcode 原生构建体系的舒适区，Bazel 就成为下一代构建系统的首选。字节跳动的头条、抖音、Airbnb、Uber、Lyft、Pinterest、Square、Bilibili 等都已把 iOS 工程迁到 Bazel。本文介绍 Bazel 的核心原理、在 iOS 上的生态（rules_apple / rules_swift / rules_xcodeproj）以及大厂落地实践。&lt;/p&gt;
&lt;hr&gt;
&lt;h2 id="为什么是-bazel"&gt;为什么是 Bazel&lt;/h2&gt;
&lt;p&gt;CocoaPods + Xcode 在超大工程上的固有瓶颈：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;粗粒度依赖&lt;/strong&gt;：以 Pod / Target 为单位，增量编译颗粒粗&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;隐式依赖&lt;/strong&gt;：Build Phases 隐含顺序，难以沙箱化&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;难以远程缓存&lt;/strong&gt;：编译环境非 hermetic，hash 易变&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;难以远程执行&lt;/strong&gt;：Xcode Build System 绑定本地 macOS&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Bazel 针对这些问题从设计之初就提供了：&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;能力&lt;/th&gt;
&lt;th&gt;Bazel&lt;/th&gt;
&lt;th&gt;Xcode/CocoaPods&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;依赖粒度&lt;/td&gt;
&lt;td&gt;文件级&lt;/td&gt;
&lt;td&gt;Target 级&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;依赖显式化&lt;/td&gt;
&lt;td&gt;必须声明&lt;/td&gt;
&lt;td&gt;部分隐式&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Sandbox&lt;/td&gt;
&lt;td&gt;默认开启&lt;/td&gt;
&lt;td&gt;无&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;远程缓存&lt;/td&gt;
&lt;td&gt;原生&lt;/td&gt;
&lt;td&gt;需第三方（ccache/Rugby）&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;远程执行&lt;/td&gt;
&lt;td&gt;原生&lt;/td&gt;
&lt;td&gt;不支持&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;跨语言&lt;/td&gt;
&lt;td&gt;一流（Swift/OC/C++/Go/Rust/JS）&lt;/td&gt;
&lt;td&gt;主要 Apple 平台&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;多平台&lt;/td&gt;
&lt;td&gt;天生&lt;/td&gt;
&lt;td&gt;iOS/macOS 为主&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;hr&gt;
&lt;h2 id="bazel-核心概念"&gt;Bazel 核心概念&lt;/h2&gt;
&lt;h3 id="workspace-与-package"&gt;Workspace 与 Package&lt;/h3&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-text" data-lang="text"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;WORKSPACE # 仓库根，声明外部依赖
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;foo/
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;├── BUILD.bazel # package，本目录的构建声明
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;├── main.swift
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;└── util/
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; └── BUILD.bazel # 子 package
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Workspace&lt;/strong&gt;：整个 Bazel 仓库，一个 WORKSPACE 文件一个仓&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Package&lt;/strong&gt;：任何包含 &lt;code&gt;BUILD.bazel&lt;/code&gt; 的目录&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Target&lt;/strong&gt;：BUILD 文件里的一个 rule 调用，比如 &lt;code&gt;swift_library(name = &amp;quot;foo&amp;quot;)&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Label&lt;/strong&gt;：Target 的全局 ID，形如 &lt;code&gt;//foo/util:util&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id="rule"&gt;Rule&lt;/h3&gt;
&lt;p&gt;Rule 是构建函数，输入 sources + deps，输出 artifacts：&lt;/p&gt;</description></item><item><title>Swift 面试：泛型、协议与派发源码解析</title><link>https://amatsuzero.github.io/LastStand/posts/swiftinterviewsourcecode/generics-protocol-dispatch/</link><pubDate>Tue, 16 Jun 2026 09:06:27 +0800</pubDate><guid>https://amatsuzero.github.io/LastStand/posts/swiftinterviewsourcecode/generics-protocol-dispatch/</guid><description>&lt;h1 id="swift-面试泛型协议与派发源码解析"&gt;Swift 面试：泛型、协议与派发源码解析&lt;/h1&gt;
&lt;p&gt;Swift 面试里，泛型和协议经常不是单独问语法，而是连着问：&lt;strong&gt;Swift 中函数派发机制有哪几种？泛型是编译期还是运行期机制？协议调用为什么可能慢？&lt;code&gt;some&lt;/code&gt; 和 &lt;code&gt;any&lt;/code&gt; 为什么性能不同？Protocol Witness Table 到底是什么？&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;这篇文章按面试题展开，把答案落到 Swift 编译器里的 Generic Signature、Generic Specializer、SIL 调用指令、Protocol Witness Table、class vtable 和 Devirtualize 优化。&lt;/p&gt;
&lt;h2 id="面试高频问题"&gt;面试高频问题&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;Swift 中函数派发机制有哪几种？&lt;/li&gt;
&lt;li&gt;直接派发、class vtable 派发、witness table 派发、Objective-C 消息派发分别适用于什么场景？&lt;/li&gt;
&lt;li&gt;&lt;code&gt;function_ref&lt;/code&gt;、&lt;code&gt;class_method&lt;/code&gt;、&lt;code&gt;witness_method&lt;/code&gt;、&lt;code&gt;objc_method&lt;/code&gt; 在 SIL 里分别代表什么？&lt;/li&gt;
&lt;li&gt;如何用 &lt;code&gt;swiftc -emit-silgen&lt;/code&gt; / &lt;code&gt;swiftc -emit-sil -O&lt;/code&gt; 观察派发指令？&lt;/li&gt;
&lt;li&gt;&lt;code&gt;dynamic&lt;/code&gt; / &lt;code&gt;@objc dynamic&lt;/code&gt; 会怎样影响派发？&lt;/li&gt;
&lt;li&gt;如何用代码对比泛型、&lt;code&gt;some&lt;/code&gt;、&lt;code&gt;any&lt;/code&gt; 的派发和性能差异？&lt;/li&gt;
&lt;li&gt;Swift 泛型是运行时泛型还是编译期泛型？&lt;/li&gt;
&lt;li&gt;Generic Signature 是什么？它保存哪些信息？&lt;/li&gt;
&lt;li&gt;泛型特化为什么能提升性能？&lt;/li&gt;
&lt;li&gt;Protocol Witness Table 是什么？&lt;/li&gt;
&lt;li&gt;协议方法调用什么时候是静态派发，什么时候是动态派发？&lt;/li&gt;
&lt;li&gt;&lt;code&gt;some Protocol&lt;/code&gt; 和 &lt;code&gt;any Protocol&lt;/code&gt; 的本质区别是什么？&lt;/li&gt;
&lt;li&gt;&lt;code&gt;final&lt;/code&gt;、&lt;code&gt;private&lt;/code&gt;、具体类型为什么有利于优化？&lt;/li&gt;
&lt;li&gt;协议扩展里的方法一定是动态派发吗？&lt;/li&gt;
&lt;li&gt;&lt;code&gt;class_method&lt;/code&gt; 和 &lt;code&gt;witness_method&lt;/code&gt; 有什么区别？&lt;/li&gt;
&lt;li&gt;面试里如何解释“Swift 既强调协议，又强调性能”？&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="30-秒回答版"&gt;30 秒回答版&lt;/h2&gt;
&lt;p&gt;Swift 函数派发面试不要只答“静态派发和动态派发”。更完整的分类是：&lt;strong&gt;直接派发&lt;/strong&gt;、&lt;strong&gt;class vtable 派发&lt;/strong&gt;、&lt;strong&gt;protocol witness table 派发&lt;/strong&gt;、&lt;strong&gt;Objective-C 消息派发&lt;/strong&gt;，再补充优化器可能把动态调用去虚拟化成直接调用。&lt;/p&gt;</description></item><item><title>Objective-C 消息发送 objc_msgSend 与慢速查找入口</title><link>https://amatsuzero.github.io/LastStand/posts/ocsourcecodeanalysis/message-send-explained/</link><pubDate>Mon, 01 Jun 2026 19:50:12 +0800</pubDate><guid>https://amatsuzero.github.io/LastStand/posts/ocsourcecodeanalysis/message-send-explained/</guid><description>&lt;p&gt;objc4 runtime dispatch&lt;/p&gt;
&lt;h1 id="objective-c-消息发送objc_msgsend-与慢速查找入口"&gt;Objective-C 消息发送：objc_msgSend 与慢速查找入口&lt;/h1&gt;
&lt;p&gt;Objective-C 的方法调用本质上是一次以 &lt;code&gt;receiver&lt;/code&gt; 和 &lt;code&gt;SEL&lt;/code&gt; 为键的动态派发。 在 arm64 上，&lt;code&gt;objc_msgSend&lt;/code&gt; 先用少量汇编完成 nil/tagged pointer 判断和方法缓存查找； 只有缓存未命中时，才进入 C++ 慢路径 &lt;code&gt;lookUpImpOrForward&lt;/code&gt;，沿类层级查找、触发动态解析、填充缓存或进入消息转发。&lt;/p&gt;
&lt;p&gt;入口：runtime/Messengers.subproj/objc-msg-arm64.s 慢路径：runtime/objc-runtime-new.mm 缓存：runtime/objc-cache.mm 测试：test/msgSend.m&lt;/p&gt;
&lt;h2 id="目录"&gt;目录&lt;/h2&gt;
&lt;ol&gt;
&lt;li&gt;&lt;a href="#purpose"&gt;作用&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="#principle"&gt;实现原理总览&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="#structures"&gt;核心结构与约定&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="#fast-path"&gt;快速路径&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="#slow-path"&gt;慢速查找入口&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="#forwarding"&gt;消息转发&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="#tests"&gt;测试观察点&lt;/a&gt;&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;&lt;a id="purpose"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;h2 id="作用"&gt;作用&lt;/h2&gt;
&lt;p&gt;&lt;code&gt;objc_msgSend(id self, SEL _cmd, ...)&lt;/code&gt; 是 Objective-C 实例方法和类方法调用的公共派发入口。 编译器把 &lt;code&gt;[obj method:arg]&lt;/code&gt; 形式的调用降低为对 &lt;code&gt;objc_msgSend&lt;/code&gt; 的调用；真正执行哪个 &lt;code&gt;IMP&lt;/code&gt; 由运行时根据接收者的实际类、选择子和当前方法缓存决定。&lt;/p&gt;
&lt;h3 id="动态派发"&gt;动态派发&lt;/h3&gt;
&lt;p&gt;同一个 &lt;code&gt;SEL&lt;/code&gt; 可以在不同类上命中不同 &lt;code&gt;IMP&lt;/code&gt;，体现多态。&lt;/p&gt;
&lt;h3 id="缓存加速"&gt;缓存加速&lt;/h3&gt;
&lt;p&gt;大多数热路径只扫描类的 &lt;code&gt;cache_t&lt;/code&gt;，命中后直接尾调用 &lt;code&gt;IMP&lt;/code&gt;。&lt;/p&gt;
&lt;h3 id="语义兼容"&gt;语义兼容&lt;/h3&gt;
&lt;p&gt;&lt;code&gt;nil&lt;/code&gt; 接收者返回零值；tagged pointer 通过标签映射到伪类继续派发。&lt;/p&gt;
&lt;h3 id="扩展入口"&gt;扩展入口&lt;/h3&gt;
&lt;p&gt;未找到实现时支持 &lt;code&gt;+resolve...&lt;/code&gt; 和完整的 forwarding 机制。&lt;/p&gt;</description></item><item><title>APM-C端SDK架构</title><link>https://amatsuzero.github.io/LastStand/posts/interview/ios-apm/c%E7%AB%AFsdk%E6%9E%B6%E6%9E%84/</link><pubDate>Thu, 07 May 2026 15:42:48 +0800</pubDate><guid>https://amatsuzero.github.io/LastStand/posts/interview/ios-apm/c%E7%AB%AFsdk%E6%9E%B6%E6%9E%84/</guid><description>&lt;p&gt;iOS APM SDK 是整个系统的数据入口。它运行在真实用户设备上，和业务 App 共进程、共资源、共生命周期，所以设计目标不是“能力越多越好”，而是 &lt;strong&gt;低开销、可控制、可降级、可追责、可合规&lt;/strong&gt;。&lt;/p&gt;
&lt;hr&gt;
&lt;h2 id="一sdk-职责边界"&gt;一、SDK 职责边界&lt;/h2&gt;
&lt;p&gt;SDK 应该做：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;采集 Crash、Watchdog、FOOM、卡顿、启动、网络、页面、MetricKit、业务 Trace 等现场。&lt;/li&gt;
&lt;li&gt;生成并维护 &lt;code&gt;session_id&lt;/code&gt;、&lt;code&gt;view_id&lt;/code&gt;、&lt;code&gt;action_id&lt;/code&gt;、&lt;code&gt;resource_id&lt;/code&gt;、&lt;code&gt;trace_id&lt;/code&gt; 等关联 ID。&lt;/li&gt;
&lt;li&gt;做轻量预处理：去重、聚合、脱敏、采样、压缩、加密。&lt;/li&gt;
&lt;li&gt;按数据价值分级落盘和上报。&lt;/li&gt;
&lt;li&gt;接收远程配置，动态控制模块开关、采样率、阈值和熔断。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;SDK 不应该做：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;复杂 OLAP 查询。&lt;/li&gt;
&lt;li&gt;大规模归因计算。&lt;/li&gt;
&lt;li&gt;服务端符号化。&lt;/li&gt;
&lt;li&gt;跨用户聚合。&lt;/li&gt;
&lt;li&gt;长时间 CPU 采样或高频全量堆栈采样。&lt;/li&gt;
&lt;li&gt;未经允许采集请求 body、用户输入、定位、通讯录等敏感数据。&lt;/li&gt;
&lt;/ul&gt;
&lt;hr&gt;
&lt;h2 id="二分层架构"&gt;二、分层架构&lt;/h2&gt;
&lt;pre class="mermaid"&gt;flowchart TB
API["Public API&lt;br/&gt;start / identify / track / trace / breadcrumb"]
Core["SDK Core&lt;br/&gt;生命周期 / 插件管理 / 远程配置 / 采样 / 隐私"]
Context["Context Manager&lt;br/&gt;App / Device / User / Session / View / Trace"]
Plugins["Plugin Layer&lt;br/&gt;Crash / Watchdog / FOOM / FPS / Launch / Network / MetricKit / Business"]
Processor["Event Processor&lt;br/&gt;标准化 / 脱敏 / 聚合 / 去重 / 优先级"]
Store["Local Store&lt;br/&gt;mmap / WAL / SQLite / 文件队列"]
Uploader["Uploader&lt;br/&gt;批量 / 压缩 / 加密 / 重试 / 熔断"]
API --&gt; Core
Core --&gt; Context
Core --&gt; Plugins
Plugins --&gt; Processor
Context --&gt; Processor
Processor --&gt; Store
Store --&gt; Uploader
Uploader --&gt; Core
&lt;/pre&gt;
&lt;p&gt;推荐模块：&lt;/p&gt;</description></item><item><title>Alamofire源码导读</title><link>https://amatsuzero.github.io/LastStand/posts/interview/ios-source-analysis/alamofire%E6%BA%90%E7%A0%81%E5%AF%BC%E8%AF%BB/</link><pubDate>Sat, 02 May 2026 22:32:27 +0800</pubDate><guid>https://amatsuzero.github.io/LastStand/posts/interview/ios-source-analysis/alamofire%E6%BA%90%E7%A0%81%E5%AF%BC%E8%AF%BB/</guid><description>&lt;p&gt;Alamofire 是 Swift 社区最广泛使用的 HTTP 网络库，由 Alamofire Software Foundation 维护，在 GitHub 已收获 42k+ star。它在 &lt;code&gt;URLSession&lt;/code&gt; 之上构建了一整套链式 API、拦截器、认证、证书校验、重试与响应序列化等能力。本文基于最新版本 &lt;strong&gt;v5.11.2&lt;/strong&gt;（2026 年 4 月发布）源码进行分析，覆盖 Swift 6 严格并发、async/await、WebSocket、OfflineRetrier 等最新特性。&lt;/p&gt;
&lt;hr&gt;
&lt;h2 id="一整体架构"&gt;一、整体架构&lt;/h2&gt;
&lt;p&gt;Alamofire 采用&lt;strong&gt;中央调度 + 状态机 + 协议导向&lt;/strong&gt;的设计，核心角色分工清晰：&lt;/p&gt;
&lt;pre class="mermaid"&gt;graph TB
subgraph "入口层"
AF["AF&lt;br/&gt;(Session.default)"]
end
subgraph "调度层"
S["Session&lt;br/&gt;统一调度器"]
SD["SessionDelegate&lt;br/&gt;URLSession 桥接"]
end
subgraph "请求层"
R["Request (基类)&lt;br/&gt;状态机 + 生命周期"]
DR["DataRequest"]
DLR["DownloadRequest"]
UR["UploadRequest"]
DSR["DataStreamRequest"]
WSR["WebSocketRequest"]
end
subgraph "拦截层"
RA["RequestAdapter&lt;br/&gt;请求改写"]
RR["RequestRetrier&lt;br/&gt;失败重试"]
RI["RequestInterceptor&lt;br/&gt;= Adapter + Retrier"]
end
subgraph "服务层"
RS["ResponseSerializer&lt;br/&gt;响应序列化"]
STE["ServerTrustEvaluating&lt;br/&gt;证书/公钥校验"]
EM["EventMonitor&lt;br/&gt;事件监控"]
MP["MultipartFormData&lt;br/&gt;表单编码"]
end
subgraph "系统层"
US["URLSession / URLSessionTask"]
end
AF --&gt; S
S --&gt; SD
S --&gt;|创建| R
R --&gt; DR &amp; DLR &amp; UR &amp; DSR &amp; WSR
S -.使用.-&gt; RI
RI -.= .-&gt; RA &amp; RR
R -.序列化.-&gt; RS
SD -.校验.-&gt; STE
S -.通知.-&gt; EM
UR -.构建.-&gt; MP
SD &lt;--&gt;|delegate| US
R --&gt;|执行| US
&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;源码目录（&lt;code&gt;Source/&lt;/code&gt;，总计约 17000 行纯 Swift 代码）：&lt;/strong&gt;&lt;/p&gt;</description></item><item><title>Block底层原理</title><link>https://amatsuzero.github.io/LastStand/posts/interview/ios-basics/block%E5%BA%95%E5%B1%82%E5%8E%9F%E7%90%86/</link><pubDate>Sat, 02 May 2026 22:32:27 +0800</pubDate><guid>https://amatsuzero.github.io/LastStand/posts/interview/ios-basics/block%E5%BA%95%E5%B1%82%E5%8E%9F%E7%90%86/</guid><description>&lt;h2 id="基础概念"&gt;基础概念&lt;/h2&gt;
&lt;p&gt;Block 是 Apple 在 C 语言基础上扩展的语法特性（也称为 Closure / 闭包），它允许将一段代码和其执行时需要的上下文环境封装为一个可传递的对象。Block 在 Objective-C 和 C/C++ 中均可使用，是 GCD、动画 API、回调等场景的核心机制。&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-objc" data-lang="objc"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;// Block 的声明与调用
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;void&lt;/span&gt; (&lt;span style="color:#f92672"&gt;^&lt;/span&gt;myBlock)(NSString &lt;span style="color:#f92672"&gt;*&lt;/span&gt;) &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#f92672"&gt;^&lt;/span&gt;(NSString &lt;span style="color:#f92672"&gt;*&lt;/span&gt;name) {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; NSLog(&lt;span style="color:#e6db74"&gt;@&amp;#34;Hello, %@&amp;#34;&lt;/span&gt;, name);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;};
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;myBlock(&lt;span style="color:#e6db74"&gt;@&amp;#34;World&amp;#34;&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;一个核心问题是：&lt;strong&gt;Block 是函数指针还是对象？&lt;/strong&gt; 答案是——Block 本质上是一个 &lt;strong&gt;OC 对象&lt;/strong&gt;。它的底层是一个包含 &lt;code&gt;isa&lt;/code&gt; 指针的 C 结构体，满足 OC 对象的基本条件；同时它也包含一个函数指针（&lt;code&gt;FuncPtr&lt;/code&gt;），指向 Block 实际执行的代码。因此可以说，Block 是一个用对象形式包装了函数指针和捕获变量的特殊 OC 对象。&lt;/p&gt;
&lt;h2 id="底层数据结构"&gt;底层数据结构&lt;/h2&gt;
&lt;p&gt;通过 &lt;code&gt;clang -rewrite-objc&lt;/code&gt; 可以将 Block 语法转换为 C++ 代码，观察其底层结构。这个转换虽然不完全等同于最终编译产物，但准确反映了 Block 的数据布局和调用机制。&lt;/p&gt;
&lt;h3 id="编译器转换示例"&gt;编译器转换示例&lt;/h3&gt;
&lt;p&gt;对以下源码：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-objc" data-lang="objc"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;int&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;main&lt;/span&gt;() {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;int&lt;/span&gt; a &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;10&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;void&lt;/span&gt; (&lt;span style="color:#f92672"&gt;^&lt;/span&gt;block)(&lt;span style="color:#66d9ef"&gt;void&lt;/span&gt;) &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#f92672"&gt;^&lt;/span&gt;{
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; NSLog(&lt;span style="color:#e6db74"&gt;@&amp;#34;%d&amp;#34;&lt;/span&gt;, a);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; };
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; block();
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;return&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;0&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Clang 会将其转换为如下结构：&lt;/p&gt;</description></item><item><title>MVI架构详解</title><link>https://amatsuzero.github.io/LastStand/posts/interview/ios-architecture/mvi/</link><pubDate>Sat, 02 May 2026 22:32:27 +0800</pubDate><guid>https://amatsuzero.github.io/LastStand/posts/interview/ios-architecture/mvi/</guid><description>&lt;h2 id="什么是mvi"&gt;什么是MVI&lt;/h2&gt;
&lt;p&gt;MVI（Model-View-Intent）是一种单向数据流架构模式。&amp;ldquo;Model-View-Intent&amp;quot;这一命名最早出现在Andre Medeiros（Staltz）创建的JavaScript框架Cycle.js中。2016年，Hannes Dorfmann在其博客系列中将MVI系统化引入Android开发，他在文中明确提到同时受到了Cycle.js和Redux（以及更早的Elm架构）的启发——MVI的命名和响应式理念来自Cycle.js，而Reducer纯函数和单一状态源的机制则与Redux一脉相承。随着Swift社区对函数式编程和响应式编程的接受度提高，MVI也逐渐被引入iOS开发。&lt;/p&gt;
&lt;p&gt;MVI的核心思想：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;单向数据流&lt;/strong&gt;：数据沿固定方向流动（View -&amp;gt; Intent -&amp;gt; Reducer -&amp;gt; State -&amp;gt; View），没有捷径或后门&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;不可变状态&lt;/strong&gt;：整个界面由单一不可变的State描述，每次更新都产生全新的State对象&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;可预测性&lt;/strong&gt;：给定相同的当前State和Intent，Reducer总是产生相同的新State&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="mvi的核心概念"&gt;MVI的核心概念&lt;/h2&gt;
&lt;h3 id="model状态"&gt;Model（状态）&lt;/h3&gt;
&lt;p&gt;在MVI中，Model不是传统意义上的领域数据模型，而是&lt;strong&gt;界面状态模型（State）&lt;/strong&gt;。它用一个不可变的值类型来描述UI在某一时刻的完整快照，包括数据内容、加载状态、错误信息等。&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-swift" data-lang="swift"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;struct&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;UserListState&lt;/span&gt;: Equatable {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;var&lt;/span&gt; users: [User]
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;var&lt;/span&gt; isLoading: Bool
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;var&lt;/span&gt; error: String?
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;var&lt;/span&gt; searchQuery: String
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;static&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;let&lt;/span&gt; initial = UserListState(
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; users: [],
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; isLoading: &lt;span style="color:#66d9ef"&gt;false&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; error: &lt;span style="color:#66d9ef"&gt;nil&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; searchQuery: &lt;span style="color:#e6db74"&gt;&amp;#34;&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; )
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;这里使用&lt;code&gt;var&lt;/code&gt;属性配合&lt;code&gt;struct&lt;/code&gt;值类型，利用Swift的值语义在Reducer中通过拷贝实现不可变效果，这是Swift中最常用的做法（详见后文&amp;quot;状态的不可变性&amp;quot;一节）。&lt;/p&gt;
&lt;h3 id="intent意图"&gt;Intent（意图）&lt;/h3&gt;
&lt;p&gt;Intent代表所有触发状态变化的事件。它不仅包括用户的UI操作，还包括副作用的结果回调（如网络请求完成、数据库查询结果）、系统事件（如生命周期回调、推送通知）等。所有这些事件统一通过Intent进入Reducer驱动状态变化。&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-swift" data-lang="swift"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;enum&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;UserListAction&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#75715e"&gt;// 用户意图&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;case&lt;/span&gt; loadUsers
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;case&lt;/span&gt; refreshUsers
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;case&lt;/span&gt; deleteUser(id: Int)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;case&lt;/span&gt; searchQueryChanged(String)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#75715e"&gt;// 副作用结果（也是Intent的一种）&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;case&lt;/span&gt; usersLoaded([User])
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;case&lt;/span&gt; loadFailed(String)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;将用户操作和副作用结果统一为同一类型，是MVI的关键设计。这样Reducer就成为状态变化的唯一入口，所有状态转换都在一处完成。&lt;/p&gt;</description></item><item><title>OOP、POP与AOP</title><link>https://amatsuzero.github.io/LastStand/posts/interview/ios-advanced/oop-pop-aop/</link><pubDate>Sat, 02 May 2026 22:32:27 +0800</pubDate><guid>https://amatsuzero.github.io/LastStand/posts/interview/ios-advanced/oop-pop-aop/</guid><description>&lt;p&gt;在iOS开发中，经常会接触到三种重要的编程范式：面向对象编程（OOP）、面向协议编程（POP）和面向切面编程（AOP）。&lt;/p&gt;
&lt;hr&gt;
&lt;h2 id="oop---面向对象编程"&gt;OOP - 面向对象编程&lt;/h2&gt;
&lt;h3 id="基本概念"&gt;基本概念&lt;/h3&gt;
&lt;p&gt;面向对象编程（Object-Oriented Programming）是一种以对象为核心的编程范式。它将数据和操作数据的方法封装在一起，形成对象。&lt;/p&gt;
&lt;p&gt;OOP的四大核心特性：&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;特性&lt;/th&gt;
&lt;th&gt;说明&lt;/th&gt;
&lt;th&gt;iOS中的体现&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;封装&lt;/td&gt;
&lt;td&gt;隐藏内部实现细节，只暴露必要的接口&lt;/td&gt;
&lt;td&gt;&lt;code&gt;@interface&lt;/code&gt;/&lt;code&gt;@implementation&lt;/code&gt;分离，&lt;code&gt;private&lt;/code&gt;属性&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;继承&lt;/td&gt;
&lt;td&gt;子类继承父类的属性和方法&lt;/td&gt;
&lt;td&gt;&lt;code&gt;UIViewController&lt;/code&gt;继承自&lt;code&gt;UIResponder&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;多态&lt;/td&gt;
&lt;td&gt;同一接口可以有不同的实现&lt;/td&gt;
&lt;td&gt;子类重写父类方法&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;抽象&lt;/td&gt;
&lt;td&gt;提取共同特征形成抽象类型&lt;/td&gt;
&lt;td&gt;抽象基类、协议&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;h3 id="objective-c中的oop"&gt;Objective-C中的OOP&lt;/h3&gt;
&lt;p&gt;Objective-C是一门典型的面向对象语言，它在C语言的基础上添加了面向对象的特性。&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-objective-c" data-lang="objective-c"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;// 基类定义
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;@interface&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;Animal&lt;/span&gt; : &lt;span style="color:#a6e22e"&gt;NSObject&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;@property&lt;/span&gt; (&lt;span style="color:#66d9ef"&gt;nonatomic&lt;/span&gt;, &lt;span style="color:#66d9ef"&gt;copy&lt;/span&gt;) NSString &lt;span style="color:#f92672"&gt;*&lt;/span&gt;name;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;- (&lt;span style="color:#66d9ef"&gt;void&lt;/span&gt;)&lt;span style="color:#a6e22e"&gt;speak&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;- (&lt;span style="color:#66d9ef"&gt;void&lt;/span&gt;)&lt;span style="color:#a6e22e"&gt;eat:&lt;/span&gt;(NSString &lt;span style="color:#f92672"&gt;*&lt;/span&gt;)food;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;@end&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;@implementation&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;Animal&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;- (&lt;span style="color:#66d9ef"&gt;void&lt;/span&gt;)&lt;span style="color:#a6e22e"&gt;speak&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; NSLog(&lt;span style="color:#e6db74"&gt;@&amp;#34;Animal speaks&amp;#34;&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;- (&lt;span style="color:#66d9ef"&gt;void&lt;/span&gt;)&lt;span style="color:#a6e22e"&gt;eat:&lt;/span&gt;(NSString &lt;span style="color:#f92672"&gt;*&lt;/span&gt;)food {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; NSLog(&lt;span style="color:#e6db74"&gt;@&amp;#34;%@ is eating %@&amp;#34;&lt;/span&gt;, self.name, food);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;@end&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;// 子类继承
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;@interface&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;Dog&lt;/span&gt; : &lt;span style="color:#a6e22e"&gt;Animal&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;@property&lt;/span&gt; (&lt;span style="color:#66d9ef"&gt;nonatomic&lt;/span&gt;, &lt;span style="color:#66d9ef"&gt;copy&lt;/span&gt;) NSString &lt;span style="color:#f92672"&gt;*&lt;/span&gt;breed;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;@end&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;@implementation&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;Dog&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;// 重写父类方法 - 多态
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;- (&lt;span style="color:#66d9ef"&gt;void&lt;/span&gt;)&lt;span style="color:#a6e22e"&gt;speak&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; NSLog(&lt;span style="color:#e6db74"&gt;@&amp;#34;%@ barks: Woof!&amp;#34;&lt;/span&gt;, self.name);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;// 子类特有方法
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;- (&lt;span style="color:#66d9ef"&gt;void&lt;/span&gt;)&lt;span style="color:#a6e22e"&gt;fetch&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; NSLog(&lt;span style="color:#e6db74"&gt;@&amp;#34;%@ is fetching&amp;#34;&lt;/span&gt;, self.name);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;@end&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h3 id="swift中的oop"&gt;Swift中的OOP&lt;/h3&gt;
&lt;p&gt;Swift同样支持面向对象编程，但提供了更现代的语法和更强的类型安全。&lt;/p&gt;</description></item><item><title>启动优化-Initializers</title><link>https://amatsuzero.github.io/LastStand/posts/interview/ios-performance/launch-initializers/</link><pubDate>Sat, 02 May 2026 22:32:27 +0800</pubDate><guid>https://amatsuzero.github.io/LastStand/posts/interview/ios-performance/launch-initializers/</guid><description>&lt;p&gt;Initializers是指在main函数之前执行的初始化代码，包括C++静态构造函数和&lt;code&gt;__attribute__((constructor))&lt;/code&gt;标记的函数。这些代码会在Pre-main阶段同步执行，阻塞启动。&lt;/p&gt;
&lt;hr&gt;
&lt;h2 id="问题分析"&gt;问题分析&lt;/h2&gt;
&lt;p&gt;以下代码会在main之前执行：&lt;/p&gt;
&lt;h3 id="1-c静态构造函数"&gt;1. C++静态构造函数&lt;/h3&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-cpp" data-lang="cpp"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;__attribute__((constructor))
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;static&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;void&lt;/span&gt; MyInitializer() {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#75715e"&gt;// 耗时初始化
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; initializeHeavyResource();
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h3 id="2-全局静态变量的构造函数"&gt;2. 全局静态变量的构造函数&lt;/h3&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-cpp" data-lang="cpp"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;// 全局静态变量
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;static&lt;/span&gt; std&lt;span style="color:#f92672"&gt;::&lt;/span&gt;vector&lt;span style="color:#f92672"&gt;&amp;lt;&lt;/span&gt;std&lt;span style="color:#f92672"&gt;::&lt;/span&gt;string&lt;span style="color:#f92672"&gt;&amp;gt;&lt;/span&gt; globalCache &lt;span style="color:#f92672"&gt;=&lt;/span&gt; loadFromDisk(); &lt;span style="color:#75715e"&gt;// 构造函数在main前调用
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h3 id="3-非基本类型的全局变量"&gt;3. 非基本类型的全局变量&lt;/h3&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-cpp" data-lang="cpp"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;// 非POD类型的全局变量会触发构造函数
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;static&lt;/span&gt; std&lt;span style="color:#f92672"&gt;::&lt;/span&gt;string globalString &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#e6db74"&gt;&amp;#34;Hello&amp;#34;&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;static&lt;/span&gt; MyClass globalObject;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;hr&gt;
&lt;h2 id="优化方案"&gt;优化方案&lt;/h2&gt;
&lt;h3 id="方案1延迟初始化"&gt;方案1：延迟初始化&lt;/h3&gt;
&lt;p&gt;将全局变量改为懒加载模式：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-cpp" data-lang="cpp"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;// 优化前：全局变量在main前初始化
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;static&lt;/span&gt; std&lt;span style="color:#f92672"&gt;::&lt;/span&gt;vector&lt;span style="color:#f92672"&gt;&amp;lt;&lt;/span&gt;std&lt;span style="color:#f92672"&gt;::&lt;/span&gt;string&lt;span style="color:#f92672"&gt;&amp;gt;&lt;/span&gt; globalCache &lt;span style="color:#f92672"&gt;=&lt;/span&gt; loadFromDisk();
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;// 优化后（纯C++方案，适用于 .cpp 文件）：
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;#include&lt;/span&gt; &lt;span style="color:#75715e"&gt;&amp;lt;mutex&amp;gt;&lt;/span&gt;&lt;span style="color:#75715e"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;static&lt;/span&gt; std&lt;span style="color:#f92672"&gt;::&lt;/span&gt;vector&lt;span style="color:#f92672"&gt;&amp;lt;&lt;/span&gt;std&lt;span style="color:#f92672"&gt;::&lt;/span&gt;string&lt;span style="color:#f92672"&gt;&amp;gt;*&lt;/span&gt; getGlobalCache() {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;static&lt;/span&gt; std&lt;span style="color:#f92672"&gt;::&lt;/span&gt;vector&lt;span style="color:#f92672"&gt;&amp;lt;&lt;/span&gt;std&lt;span style="color:#f92672"&gt;::&lt;/span&gt;string&lt;span style="color:#f92672"&gt;&amp;gt;*&lt;/span&gt; cache &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;nullptr&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;static&lt;/span&gt; std&lt;span style="color:#f92672"&gt;::&lt;/span&gt;once_flag onceFlag;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; std&lt;span style="color:#f92672"&gt;::&lt;/span&gt;call_once(onceFlag, [&lt;span style="color:#f92672"&gt;&amp;amp;&lt;/span&gt;] {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; cache &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;new&lt;/span&gt; std&lt;span style="color:#f92672"&gt;::&lt;/span&gt;vector&lt;span style="color:#f92672"&gt;&amp;lt;&lt;/span&gt;std&lt;span style="color:#f92672"&gt;::&lt;/span&gt;string&lt;span style="color:#f92672"&gt;&amp;gt;&lt;/span&gt;();
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;*&lt;/span&gt;cache &lt;span style="color:#f92672"&gt;=&lt;/span&gt; loadFromDisk();
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; });
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;return&lt;/span&gt; cache;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;// 优化后（ObjC++方案，适用于 .mm 文件）：
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;static&lt;/span&gt; std&lt;span style="color:#f92672"&gt;::&lt;/span&gt;vector&lt;span style="color:#f92672"&gt;&amp;lt;&lt;/span&gt;std&lt;span style="color:#f92672"&gt;::&lt;/span&gt;string&lt;span style="color:#f92672"&gt;&amp;gt;*&lt;/span&gt; getGlobalCache() {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;static&lt;/span&gt; std&lt;span style="color:#f92672"&gt;::&lt;/span&gt;vector&lt;span style="color:#f92672"&gt;&amp;lt;&lt;/span&gt;std&lt;span style="color:#f92672"&gt;::&lt;/span&gt;string&lt;span style="color:#f92672"&gt;&amp;gt;*&lt;/span&gt; cache &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;nullptr&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;static&lt;/span&gt; dispatch_once_t onceToken;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; dispatch_once(&lt;span style="color:#f92672"&gt;&amp;amp;&lt;/span&gt;onceToken, &lt;span style="color:#f92672"&gt;^&lt;/span&gt;{
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; cache &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;new&lt;/span&gt; std&lt;span style="color:#f92672"&gt;::&lt;/span&gt;vector&lt;span style="color:#f92672"&gt;&amp;lt;&lt;/span&gt;std&lt;span style="color:#f92672"&gt;::&lt;/span&gt;string&lt;span style="color:#f92672"&gt;&amp;gt;&lt;/span&gt;();
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;*&lt;/span&gt;cache &lt;span style="color:#f92672"&gt;=&lt;/span&gt; loadFromDisk();
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; });
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;return&lt;/span&gt; cache;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h3 id="方案2使用swift懒加载"&gt;方案2：使用Swift懒加载&lt;/h3&gt;
&lt;p&gt;Swift的懒加载特性可以避免在启动时初始化：&lt;/p&gt;</description></item><item><title>编译优化-CocoaPods优化</title><link>https://amatsuzero.github.io/LastStand/posts/interview/ios-build/cocoapods%E4%BC%98%E5%8C%96/</link><pubDate>Sat, 02 May 2026 22:32:27 +0800</pubDate><guid>https://amatsuzero.github.io/LastStand/posts/interview/ios-build/cocoapods%E4%BC%98%E5%8C%96/</guid><description>&lt;p&gt;在 iOS 生态中，CocoaPods 依然是大多数中大型工程的依赖管理工具。当 Pod 数量达到几百个子组件上千个时，&lt;code&gt;pod install&lt;/code&gt; 的耗时会变成研发流程里的硬性卡点。抖音在其 &lt;code&gt;seer-optimize&lt;/code&gt; 项目中系统化地优化了 CocoaPods 的整个生命周期，全量 Pod Install 耗时减少 50%、增量减少 65%。本文系统介绍这些优化背后的原理。&lt;/p&gt;
&lt;p&gt;关于 CocoaPods 整体架构的深度介绍可以参考 &lt;a href="https://amatsuzero.github.io/LastStand/posts/interview/ios-source-analysis/cocoapods-%E6%9E%B6%E6%9E%84%E6%80%BB%E8%A7%88/"&gt;CocoaPods源码导读-架构总览&lt;/a&gt;。&lt;/p&gt;
&lt;hr&gt;
&lt;h2 id="pod-install-耗时构成"&gt;Pod Install 耗时构成&lt;/h2&gt;
&lt;p&gt;&lt;code&gt;Installer#install!&lt;/code&gt; 的六个阶段：&lt;/p&gt;
&lt;pre class="mermaid"&gt;flowchart LR
A[prepare] --&gt; B[resolve_dependencies]
B --&gt; C[download_dependencies]
C --&gt; D[validate_targets]
D --&gt; E[generate_pods_project]
E --&gt; F[integrate_user_project]
&lt;/pre&gt;
&lt;p&gt;抖音公开的典型耗时分布：&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;阶段&lt;/th&gt;
&lt;th&gt;典型耗时&lt;/th&gt;
&lt;th&gt;说明&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;prepare&lt;/td&gt;
&lt;td&gt;&amp;lt; 0.01s&lt;/td&gt;
&lt;td&gt;初始化&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;resolve_dependencies&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;数秒到数分钟&lt;/td&gt;
&lt;td&gt;依赖决议，瓶颈&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;download_dependencies&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;数秒到数分钟&lt;/td&gt;
&lt;td&gt;依赖下载，IO 密集&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;validate_targets&lt;/td&gt;
&lt;td&gt;0.1s&lt;/td&gt;
&lt;td&gt;校验&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;generate_pods_project&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;数秒到数十秒&lt;/td&gt;
&lt;td&gt;生成 xcodeproj&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;integrate_user_project&lt;/td&gt;
&lt;td&gt;0.01s&lt;/td&gt;
&lt;td&gt;集成主工程&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;hr&gt;
&lt;h2 id="resolve_dependencies-优化"&gt;resolve_dependencies 优化&lt;/h2&gt;
&lt;h3 id="source-仓库更新"&gt;Source 仓库更新&lt;/h3&gt;
&lt;p&gt;默认 CocoaPods 在 &lt;code&gt;pod install --repo-update&lt;/code&gt; 时会更新&lt;strong&gt;所有&lt;/strong&gt; source 仓库。抖音改造为：&lt;/p&gt;</description></item><item><title>Swift 面试：值语义、COW 与集合源码解析</title><link>https://amatsuzero.github.io/LastStand/posts/swiftinterviewsourcecode/value-semantics-cow-collections/</link><pubDate>Tue, 16 Jun 2026 09:06:27 +0800</pubDate><guid>https://amatsuzero.github.io/LastStand/posts/swiftinterviewsourcecode/value-semantics-cow-collections/</guid><description>&lt;h1 id="swift-面试值语义cow-与集合源码解析"&gt;Swift 面试：值语义、COW 与集合源码解析&lt;/h1&gt;
&lt;p&gt;Swift 的 &lt;code&gt;Array&lt;/code&gt;、&lt;code&gt;String&lt;/code&gt;、&lt;code&gt;Dictionary&lt;/code&gt; 都表现为值类型，但它们不可能每次赋值都完整复制底层存储。面试官问值语义和 COW，真正想看的是你能不能说清楚：&lt;strong&gt;值语义是语言语义，COW 是性能实现；集合表面是 struct，底层经常共享引用存储；写入前靠唯一性检查决定是否复制。&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;这篇文章从面试题出发，把结论落到 Swift 标准库源码里的 Array buffer、String guts、Dictionary storage 和 &lt;code&gt;isKnownUniquelyReferenced&lt;/code&gt;。&lt;/p&gt;
&lt;h2 id="面试高频问题"&gt;面试高频问题&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;Swift 的 struct 为什么常说是值语义？&lt;/li&gt;
&lt;li&gt;Array 赋值时一定会复制底层元素吗？&lt;/li&gt;
&lt;li&gt;Copy-on-Write 的触发条件是什么？&lt;/li&gt;
&lt;li&gt;&lt;code&gt;isKnownUniquelyReferenced&lt;/code&gt; 检查的到底是什么？&lt;/li&gt;
&lt;li&gt;Array、ContiguousArray、ArrayBuffer、Storage 是什么关系？&lt;/li&gt;
&lt;li&gt;String 为什么不能用整数下标随机访问？&lt;/li&gt;
&lt;li&gt;String.Index 为什么不是一个简单的 Int？&lt;/li&gt;
&lt;li&gt;Dictionary 也是 COW 吗？&lt;/li&gt;
&lt;li&gt;ArraySlice 为什么可能持有原数组存储？&lt;/li&gt;
&lt;li&gt;值类型里包含 class 引用，还算值语义吗？&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="30-秒回答版"&gt;30 秒回答版&lt;/h2&gt;
&lt;p&gt;Swift 的值语义是说：从语言使用者角度看，赋值、传参、修改不会意外影响另一个值。但这不等于底层每次都立即复制。&lt;/p&gt;
&lt;p&gt;标准库集合通常用 Copy-on-Write 实现：多个值可以共享同一份堆上 buffer；只有当某个值要写入时，才检查底层 buffer 是否唯一引用。如果唯一，就原地修改；如果不唯一，就复制一份新 buffer 再修改。&lt;/p&gt;
&lt;p&gt;所以：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-text" data-lang="text"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;值语义：用户看到的是独立值
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;COW：实现上先共享，写入前再判断是否复制
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;ARC：维护底层 buffer 的引用计数
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;isUnique：让 COW 判断能否原地修改
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;面试可以这样回答：&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Swift 的 Array 是 struct，但它内部持有引用语义的 storage。赋值时通常只复制结构体里的引用；真正写入时通过唯一性检查决定是否复制底层 storage。这让 Array 同时具备值语义和接近引用共享的性能。&lt;/p&gt;</description></item><item><title>Codable底层原理</title><link>https://amatsuzero.github.io/LastStand/posts/interview/ios-basics/codable%E5%BA%95%E5%B1%82%E5%8E%9F%E7%90%86/</link><pubDate>Mon, 08 Jun 2026 23:06:52 +0800</pubDate><guid>https://amatsuzero.github.io/LastStand/posts/interview/ios-basics/codable%E5%BA%95%E5%B1%82%E5%8E%9F%E7%90%86/</guid><description>&lt;p&gt;&lt;code&gt;Codable&lt;/code&gt; 是 Swift 4 引入的序列化方案，官方定位是替代 Objective-C 时代的 &lt;code&gt;NSCoding&lt;/code&gt;、以及各种第三方字典转模型框架（MJExtension、YYModel、JSONModel 等）。与运行时反射方案不同，&lt;code&gt;Codable&lt;/code&gt; 通过&amp;quot;编译器自动合成 + 标准库协议抽象 + 具体格式实现&amp;quot;三层解耦，在编译期就把类型与序列化逻辑绑定好，兼具类型安全、性能和扩展性。&lt;/p&gt;
&lt;p&gt;本文基于以下 Swift 源码展开分析：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;协议定义：&lt;a href="https://github.com/apple/swift/blob/main/stdlib/public/core/Codable.swift"&gt;&lt;code&gt;swift/stdlib/public/core/Codable.swift&lt;/code&gt;&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;编译器合成：&lt;a href="https://github.com/apple/swift/blob/main/lib/Sema/DerivedConformanceCodable.cpp"&gt;&lt;code&gt;swift/lib/Sema/DerivedConformanceCodable.cpp&lt;/code&gt;&lt;/a&gt;、&lt;code&gt;DerivedConformanceCodingKey.cpp&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;Foundation 实现：&lt;a href="https://github.com/apple/swift-corelibs-foundation/blob/main/Sources/Foundation/JSONEncoder.swift"&gt;&lt;code&gt;swift-corelibs-foundation/Sources/Foundation/JSONEncoder.swift&lt;/code&gt;&lt;/a&gt;、&lt;code&gt;JSONDecoder.swift&lt;/code&gt;、&lt;code&gt;PropertyListEncoder.swift&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="整体架构"&gt;整体架构&lt;/h2&gt;
&lt;p&gt;在开始深入之前，先建立整体印象。&lt;code&gt;Codable&lt;/code&gt; 可以拆成三层角色：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;用户类型层&lt;/strong&gt;：业务中的 &lt;code&gt;struct&lt;/code&gt; / &lt;code&gt;class&lt;/code&gt; / &lt;code&gt;enum&lt;/code&gt;，声明遵循 &lt;code&gt;Codable&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;标准库与编译器层&lt;/strong&gt;：标准库定义 &lt;code&gt;Encodable&lt;/code&gt; / &lt;code&gt;Decodable&lt;/code&gt; / &lt;code&gt;Encoder&lt;/code&gt; / &lt;code&gt;Decoder&lt;/code&gt; 等协议，编译器为符合条件的类型合成 &lt;code&gt;encode(to:)&lt;/code&gt; 和 &lt;code&gt;init(from:)&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;格式实现层&lt;/strong&gt;：Foundation 或第三方提供具体 &lt;code&gt;Encoder&lt;/code&gt; / &lt;code&gt;Decoder&lt;/code&gt;，负责把容器操作落到 JSON、Plist、BSON 等格式上&lt;/li&gt;
&lt;/ul&gt;
&lt;pre class="mermaid"&gt;flowchart LR
subgraph L1[用户类型层]
A[struct / class / enum&lt;br/&gt;声明遵循 Codable]
end
subgraph L2[标准库与编译器层]
B[Encodable / Decodable&lt;br/&gt;协议要求]
C["编译器合成&lt;br/&gt;encode(to:) / init(from:)"]
D[Encoder / Decoder&lt;br/&gt;容器协议]
B --&gt; C
C --&gt; D
end
subgraph L3[格式实现层]
E[JSONEncoder / JSONDecoder&lt;br/&gt;PropertyListEncoder / 第三方实现]
F[Data / 字符串 / 其他格式]
E --&gt; F
end
A --&gt;|conforms to| B
D --&gt;|由具体类型实现| E
&lt;/pre&gt;
&lt;p&gt;核心思想是：&lt;strong&gt;标准库只定义&amp;quot;如何描述一个可编码类型&amp;quot;和&amp;quot;编码器需要提供什么能力&amp;quot;，具体的格式（JSON、Plist、BSON…）由 Foundation 或第三方实现&lt;/strong&gt;。用户类型只需要遵循协议，剩下的由编译器在 SIL 层自动生成。&lt;/p&gt;</description></item><item><title>objc4 方法缓存 cache_t / bucket_t 技术讲解</title><link>https://amatsuzero.github.io/LastStand/posts/ocsourcecodeanalysis/method-cache-explained/</link><pubDate>Mon, 01 Jun 2026 19:50:12 +0800</pubDate><guid>https://amatsuzero.github.io/LastStand/posts/ocsourcecodeanalysis/method-cache-explained/</guid><description>&lt;h1 id="objc4-方法缓存-cache_t--bucket_t-技术讲解"&gt;objc4 方法缓存 cache_t / bucket_t 技术讲解&lt;/h1&gt;
&lt;p&gt;本文基于当前仓库中的 &lt;code&gt;runtime/objc-cache.mm&lt;/code&gt;、 &lt;code&gt;runtime/objc-runtime-new.h&lt;/code&gt;、&lt;code&gt;runtime/objc-runtime-new.mm&lt;/code&gt; 以及 cache flush 相关测试，说明 Objective-C runtime 如何把一次慢速方法查找变成后续的快速 &lt;code&gt;objc_msgSend&lt;/code&gt; cache hit。&lt;/p&gt;
&lt;h2 id="一方法缓存的作用"&gt;一、方法缓存的作用&lt;/h2&gt;
&lt;p&gt;Objective-C 消息发送以 &lt;code&gt;(Class, SEL)&lt;/code&gt; 为核心输入。完整方法查找需要处理类实现、父类链、 动态方法解析、转发和分类变更等逻辑，代价高于一次普通函数调用。&lt;code&gt;cache_t&lt;/code&gt; 是挂在每个 &lt;code&gt;objc_class&lt;/code&gt; 上的 IMP cache，用 &lt;code&gt;SEL&lt;/code&gt; 作为 key，缓存最终应该调用的 &lt;code&gt;IMP&lt;/code&gt;。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;加速热路径&lt;/strong&gt;命中时 &lt;code&gt;objc_msgSend&lt;/code&gt; 不进入 runtime 慢路径，直接由 bucket 中的 IMP 跳转。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;缓存继承结果&lt;/strong&gt;子类未实现某 selector 时，也可以把父类找到的 IMP 缓存在子类 cache 中。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;支持动态变更&lt;/strong&gt;分类加载、添加方法、交换实现等操作会触发 cache flush，避免继续调用旧 IMP。&lt;/p&gt;
&lt;p&gt;cache 不是方法列表本身，也不是权威数据源。它是一个可丢弃、可重建的性能结构；扩容时甚至不会搬迁旧条目， 而是让后续消息重新填充热点 selector。&lt;/p&gt;
&lt;h2 id="二核心结构"&gt;二、核心结构&lt;/h2&gt;
&lt;h3 id="bucket_t一个-selector-到-imp-的槽位"&gt;&lt;code&gt;bucket_t&lt;/code&gt;：一个 selector 到 IMP 的槽位&lt;/h3&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;&lt;/th&gt;
&lt;th&gt;&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;字段&lt;/td&gt;
&lt;td&gt;&lt;code&gt;_sel&lt;/code&gt; 保存 selector，&lt;code&gt;_imp&lt;/code&gt; 保存编码后的 IMP。arm64 上 IMP 在前，其他架构通常 SEL 在前，以贴合汇编 fast path 和指针认证需求。&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;sel()&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;以 relaxed atomic 读取 selector。空槽的 selector 为 0。&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;imp(base, cls)&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;读取并解码 IMP。arm64e 可使用 ptrauth，部分配置使用 class 指针 XOR，未编码配置则直接返回。&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;set&amp;lt;Atomic, Encoded&amp;gt;()&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;写入一个 bucket。写入顺序被精心安排，保证无锁读取者不会看到“新 SEL + 旧 IMP”的错误组合。&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;h3 id="cache_t每个类上的哈希表"&gt;&lt;code&gt;cache_t&lt;/code&gt;：每个类上的哈希表&lt;/h3&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;&lt;/th&gt;
&lt;th&gt;&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;_bucketsAndMaybeMask&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;保存 buckets 指针，有些 64 位配置还把 mask 打包进高位；preoptimized cache 也用低位 marker 复用这个字段。&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;_mask&lt;/code&gt; / 内联 mask&lt;/td&gt;
&lt;td&gt;bucket 数量始终为 2 的幂，&lt;code&gt;mask = capacity - 1&lt;/code&gt;，哈希后用按位与得到起始槽。&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;_occupied&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;已占用动态 bucket 数。插入成功后递增；换表时清零。&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;_flags&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;保存若干快速路径标记，例如 metaclass、C++ ctor/dtor、默认 alloc 或 RR 等，具体位定义在 &lt;code&gt;objc-runtime-new.h&lt;/code&gt;。&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;关键方法&lt;/td&gt;
&lt;td&gt;&lt;code&gt;insert&lt;/code&gt;、&lt;code&gt;eraseNolock&lt;/code&gt;、&lt;code&gt;destroy&lt;/code&gt;、&lt;code&gt;copyCacheNolock&lt;/code&gt;、&lt;code&gt;maybeConvertToPreoptimized&lt;/code&gt;、&lt;code&gt;preoptFallbackClass&lt;/code&gt;。&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;h3 id="preopt_cache_tdyld-shared-cache-预构建的常量-cache"&gt;&lt;code&gt;preopt_cache_t&lt;/code&gt;：dyld shared cache 预构建的常量 cache&lt;/h3&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;&lt;/th&gt;
&lt;th&gt;&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;fallback_class_offset&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;预优化查找未覆盖时继续查找的类，相对当前 class 地址保存。&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;shift&lt;/code&gt; / &lt;code&gt;mask&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;用于计算预优化 entries 下标。&lt;code&gt;capacity()&lt;/code&gt; 返回 &lt;code&gt;mask + 1&lt;/code&gt;。&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;occupied&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;预优化 cache 中的有效条目数量。&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;has_inlines&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;标记是否存在内联 selector；方法列表变更时需要更谨慎地禁用这类 cache。&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;entries[]&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;每项保存 selector offset 和 IMP offset，而不是直接保存完整指针。&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;h2 id="三实现原理"&gt;三、实现原理&lt;/h2&gt;
&lt;p&gt;动态 cache 是一个开放寻址哈希表。&lt;code&gt;cache_hash(sel, mask)&lt;/code&gt; 用 selector 地址和 mask 得到起始槽； 冲突时调用 &lt;code&gt;cache_next&lt;/code&gt; 继续探测。不同架构的探测方向不同：部分架构递增并使用 end marker， arm64 递减并通过 mask 回绕。&lt;/p&gt;</description></item><item><title>APM-业界方案</title><link>https://amatsuzero.github.io/LastStand/posts/interview/ios-apm/%E4%B8%9A%E7%95%8C%E6%96%B9%E6%A1%88/</link><pubDate>Thu, 07 May 2026 15:42:48 +0800</pubDate><guid>https://amatsuzero.github.io/LastStand/posts/interview/ios-apm/%E4%B8%9A%E7%95%8C%E6%96%B9%E6%A1%88/</guid><description>&lt;p&gt;本文对比目前 iOS APM 领域主流的七大方案，从接入形态、原理、能力深度、适用场景四个维度深入剖析。每个方案都包含核心技术原理与关键源码解读，帮助读者做&amp;quot;自研还是三方、自研该参考哪个&amp;quot;的选型决策。&lt;/p&gt;
&lt;hr&gt;
&lt;h2 id="一全景对比"&gt;一、全景对比&lt;/h2&gt;
&lt;pre class="mermaid"&gt;quadrantChart
title "iOS APM 方案对比"
x-axis "低侵入" --&gt; "高侵入"
y-axis "浅能力" --&gt; "深能力"
quadrant-1 "专业级"
quadrant-2 "旗舰级"
quadrant-3 "入门级"
quadrant-4 "高性价比"
MetricKit: [0.05, 0.45]
Firebase: [0.15, 0.4]
"Xcode Organizer": [0.02, 0.35]
Sentry: [0.3, 0.65]
Bugly: [0.25, 0.5]
"Matrix (微信)": [0.6, 0.88]
"Slardar (字节)": [0.65, 0.95]
"Hertz (美团)": [0.5, 0.8]
"Alita (阿里 mPaaS)": [0.55, 0.85]
&lt;/pre&gt;
&lt;hr&gt;
&lt;h2 id="二metrickit--xcode-organizerapple-官方"&gt;二、MetricKit + Xcode Organizer（Apple 官方）&lt;/h2&gt;
&lt;h3 id="21-定位"&gt;2.1 定位&lt;/h3&gt;
&lt;p&gt;Apple 自 iOS 13 推出的官方性能监控框架，&lt;strong&gt;完全系统侧实现&lt;/strong&gt;，SDK 零开销，是所有方案的基线。&lt;/p&gt;</description></item><item><title>编译优化-Explicit Modules</title><link>https://amatsuzero.github.io/LastStand/posts/interview/ios-build/explicit-modules/</link><pubDate>Tue, 05 May 2026 00:41:41 +0800</pubDate><guid>https://amatsuzero.github.io/LastStand/posts/interview/ios-build/explicit-modules/</guid><description>&lt;p&gt;Apple 从 Xcode 15 开始在 Swift 上引入 Explicit Modules，Xcode 16 在 C/C++/Objective-C 上全面铺开，Xcode 17 进一步默认启用并与细粒度依赖追踪结合。这是近五年 Apple 构建系统最重要的一次变革，直接影响到大部分项目的编译模型。&lt;/p&gt;
&lt;hr&gt;
&lt;h2 id="模块module基础"&gt;模块（Module）基础&lt;/h2&gt;
&lt;h3 id="为什么需要模块"&gt;为什么需要模块&lt;/h3&gt;
&lt;p&gt;C 家族语言的 &lt;code&gt;#include&lt;/code&gt; 机制有两个致命问题：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;文本替换&lt;/strong&gt;：头文件是纯文本替换，每个源文件都要重新解析一遍所有包含的头文件&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;宏污染&lt;/strong&gt;：先引入的头文件宏会影响后续头文件的行为，没有隔离&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;Clang 在 2012 年引入 &lt;strong&gt;Clang Modules&lt;/strong&gt;，用一个预编译的二进制模块（&lt;code&gt;.pcm&lt;/code&gt;）替代文本包含，同一 module 在一次构建里只解析一次。Swift 的 &lt;code&gt;.swiftmodule&lt;/code&gt; 从设计之初就是模块化的。&lt;/p&gt;
&lt;pre class="mermaid"&gt;flowchart LR
A["源文件"] --&gt;|"include 头文件"| B["Foundation.h 文本"];
B --&gt; C["每次都重新解析"];
D["源文件"] --&gt;|"@import Foundation"| E["Foundation.pcm 预编译"];
E --&gt; F["一次解析，多次复用"];
&lt;/pre&gt;
&lt;h3 id="模块的组成"&gt;模块的组成&lt;/h3&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;类型&lt;/th&gt;
&lt;th&gt;载体&lt;/th&gt;
&lt;th&gt;描述&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Clang Module&lt;/td&gt;
&lt;td&gt;&lt;code&gt;.pcm&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;C/OC 模块的序列化 AST&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Swift Module&lt;/td&gt;
&lt;td&gt;&lt;code&gt;.swiftmodule&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Swift 模块的接口 + SIL&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Swift Interface&lt;/td&gt;
&lt;td&gt;&lt;code&gt;.swiftinterface&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;可被不同 Swift 版本解析的文本接口&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Module Map&lt;/td&gt;
&lt;td&gt;&lt;code&gt;module.modulemap&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;描述哪些头文件构成某个 module&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;hr&gt;
&lt;h2 id="implicit-modules-的问题"&gt;Implicit Modules 的问题&lt;/h2&gt;
&lt;h3 id="原理"&gt;原理&lt;/h3&gt;
&lt;p&gt;在 Xcode 16 之前，Clang Modules 以 &lt;strong&gt;隐式&lt;/strong&gt; 方式工作：&lt;/p&gt;</description></item><item><title>IGListKit源码导读</title><link>https://amatsuzero.github.io/LastStand/posts/interview/ios-source-analysis/iglistkit%E6%BA%90%E7%A0%81%E5%AF%BC%E8%AF%BB/</link><pubDate>Sat, 02 May 2026 22:32:27 +0800</pubDate><guid>https://amatsuzero.github.io/LastStand/posts/interview/ios-source-analysis/iglistkit%E6%BA%90%E7%A0%81%E5%AF%BC%E8%AF%BB/</guid><description>&lt;p&gt;IGListKit 是 Instagram（Meta）开源的一款数据驱动的 UICollectionView 框架，旨在构建快速、灵活的列表。它的核心思想是将每个数据对象映射为独立的 Section Controller，通过高效的 O(n) Diff 算法自动计算数据变化并应用最小化更新，避免手动调用 &lt;code&gt;performBatchUpdates&lt;/code&gt; 或 &lt;code&gt;reloadData&lt;/code&gt;。本文基于 v5.2.0 源码（2026年2月发布）进行分析。&lt;/p&gt;
&lt;hr&gt;
&lt;h2 id="一整体架构"&gt;一、整体架构&lt;/h2&gt;
&lt;p&gt;IGListKit 采用分层架构，核心由三大模块构成：&lt;/p&gt;
&lt;pre class="mermaid"&gt;graph TB
subgraph "使用层"
A["UIViewController"]
end
subgraph "适配层"
B["IGListAdapter"]
C["IGListAdapterDataSource"]
end
subgraph "控制层"
D["IGListSectionController"]
E["IGListBindingSectionController"]
end
subgraph "更新层"
F["IGListAdapterUpdater"]
G["IGListUpdateCoalescer"]
H["IGListUpdateTransaction"]
end
subgraph "Diff层 (IGListDiffKit)"
I["IGListDiff&lt;br/&gt;Paul Heckel算法"]
J["IGListDiffable协议"]
end
subgraph "视图层"
K["UICollectionView"]
end
A --&gt; B
B --&gt; C
B --&gt; D
D --&gt; E
B --&gt; F
F --&gt; G
F --&gt; H
H --&gt; I
I --&gt; J
B --&gt; K
&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;源码目录结构：&lt;/strong&gt;&lt;/p&gt;</description></item><item><title>MVP架构详解</title><link>https://amatsuzero.github.io/LastStand/posts/interview/ios-architecture/mvp/</link><pubDate>Sat, 02 May 2026 22:32:27 +0800</pubDate><guid>https://amatsuzero.github.io/LastStand/posts/interview/ios-architecture/mvp/</guid><description>&lt;h2 id="什么是mvp"&gt;什么是MVP&lt;/h2&gt;
&lt;p&gt;MVP（Model-View-Presenter）是一种&lt;strong&gt;将展示逻辑与视图分离&lt;/strong&gt;的架构模式，起源于上世纪90年代。MVP通过引入Presenter层来解决MVC中Controller职责过重（Massive ViewController）的问题。MVP的核心思想是让View变得&amp;quot;被动&amp;quot;（Passive View），所有的展示逻辑都由Presenter处理，View只负责UI的展示和事件的转发。&lt;/p&gt;
&lt;h2 id="mvp的结构"&gt;MVP的结构&lt;/h2&gt;
&lt;pre class="mermaid"&gt;graph LR
subgraph View["View (ViewController)"]
V1["- 只负责UI展示&lt;br/&gt;- 将事件转发给Presenter&lt;br/&gt;- 持有Presenter强引用"]
end
subgraph Presenter["Presenter"]
P1["- 持有View的弱引用（通过协议）&lt;br/&gt;- 持有Model的引用&lt;br/&gt;- 处理所有业务逻辑&lt;br/&gt;- 决定何时更新View"]
end
subgraph Model["Model"]
M1["数据和业务逻辑"]
end
View --&gt;|"用户事件"| Presenter
Presenter -.-&gt;|"weak引用&lt;br/&gt;调用协议方法更新UI"| View
Presenter &lt;--&gt;|"获取/更新数据"| Model
&lt;/pre&gt;
&lt;h2 id="mvp的三个组件"&gt;MVP的三个组件&lt;/h2&gt;
&lt;h3 id="model模型层"&gt;Model（模型层）&lt;/h3&gt;
&lt;p&gt;与MVC中的Model相同，负责数据和业务逻辑。&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-swift" data-lang="swift"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;// Model&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;struct&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;User&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;let&lt;/span&gt; id: Int
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;let&lt;/span&gt; name: String
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;let&lt;/span&gt; email: String
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;let&lt;/span&gt; avatarURL: URL?
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;// Service&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;protocol&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;UserServiceProtocol&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;func&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;fetchUser&lt;/span&gt;(id: Int, completion: @escaping (Result&amp;lt;User, Error&amp;gt;) -&amp;gt; Void)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;func&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;updateUser&lt;/span&gt;(&lt;span style="color:#66d9ef"&gt;_&lt;/span&gt; user: User, completion: @escaping (Result&amp;lt;Void, Error&amp;gt;) -&amp;gt; Void)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;class&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;UserService&lt;/span&gt;: UserServiceProtocol {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;func&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;fetchUser&lt;/span&gt;(id: Int, completion: @escaping (Result&amp;lt;User, Error&amp;gt;) -&amp;gt; Void) {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#75715e"&gt;// 网络请求实现&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; }
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;func&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;updateUser&lt;/span&gt;(&lt;span style="color:#66d9ef"&gt;_&lt;/span&gt; user: User, completion: @escaping (Result&amp;lt;Void, Error&amp;gt;) -&amp;gt; Void) {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#75715e"&gt;// 更新用户实现&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; }
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h3 id="view视图层"&gt;View（视图层）&lt;/h3&gt;
&lt;p&gt;在MVP中，View是&amp;quot;被动的&amp;quot;（Passive View），它：&lt;/p&gt;</description></item><item><title>WebView底层原理</title><link>https://amatsuzero.github.io/LastStand/posts/interview/ios-advanced/webview%E5%BA%95%E5%B1%82%E5%8E%9F%E7%90%86/</link><pubDate>Sat, 02 May 2026 22:32:27 +0800</pubDate><guid>https://amatsuzero.github.io/LastStand/posts/interview/ios-advanced/webview%E5%BA%95%E5%B1%82%E5%8E%9F%E7%90%86/</guid><description>&lt;h2 id="前言"&gt;前言&lt;/h2&gt;
&lt;p&gt;iOS 上的 WebView 目前以 &lt;code&gt;WKWebView&lt;/code&gt; 为事实标准。它对外表现得像一个 &lt;code&gt;UIView&lt;/code&gt; 子类，但内部其实对接着整个 WebKit 引擎——一个由多个独立进程协作的庞大系统。日常开发中遇到的那些困扰：为什么 Web 页白屏不会把 App 带崩？为什么 Cookie 和 App 自身的 &lt;code&gt;NSHTTPCookieStorage&lt;/code&gt; 总是对不上？为什么 JS 调用 Native 永远是异步？为什么 &lt;code&gt;NSURLProtocol&lt;/code&gt; 拦不到 &lt;code&gt;WKWebView&lt;/code&gt; 的请求？这些问题单看 API 都得不到答案，必须下潜到 WebKit 源码里才能看清楚。&lt;/p&gt;
&lt;p&gt;好在 WebKit 是 Apple 官方开源的项目，仓库在 &lt;a href="https://github.com/WebKit/WebKit"&gt;github.com/WebKit/WebKit&lt;/a&gt;。本文基于其 &lt;code&gt;Source/&lt;/code&gt; 目录下的公开源码，按&amp;quot;源码地图 → 多进程架构 → 各进程职责 → 全链路串联 → 工程启示&amp;quot;的顺序，把 &lt;code&gt;WKWebView&lt;/code&gt; 从创建到渲染一帧的底层机制梳理清楚。&lt;/p&gt;
&lt;h2 id="一先看源码地图"&gt;一、先看源码地图&lt;/h2&gt;
&lt;p&gt;阅读源码前，先在脑子里建立目录结构。以 &lt;code&gt;WebKit/WebKit&lt;/code&gt; 仓库的 &lt;code&gt;Source/&lt;/code&gt; 目录为例：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-fallback" data-lang="fallback"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;Source/
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;├── JavaScriptCore/ # JS 引擎（解释器、JIT 编译器、GC）
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;├── WebCore/ # 渲染引擎核心（DOM、CSSOM、Layout、Paint）
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;├── WebKit/ # 多进程框架 + Cocoa 层 API
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;│ ├── UIProcess/ # 主进程侧（App 进程）
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;│ │ ├── API/Cocoa/ # WKWebView.mm、WKProcessPool.mm 等
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;│ │ ├── API/ios/ # WKWebViewIOS.mm
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;│ │ ├── ios/ # WKContentView.mm、WebPageProxyIOS.mm
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;│ │ └── ...
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;│ ├── WebProcess/ # 渲染进程侧（WebContent）
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;│ ├── NetworkProcess/ # 独立网络进程
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;│ ├── GPUProcess/ # 独立 GPU 进程
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;│ └── Shared/ # 跨进程共享的数据结构、IPC 消息定义
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;└── WTF/ # 基础容器、线程、字符串工具库
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;日常 iOS 开发能看到的 &lt;code&gt;WKWebView&lt;/code&gt;，对应的实现就在 &lt;code&gt;Source/WebKit/UIProcess/API/Cocoa/WKWebView.mm&lt;/code&gt;。它是一个 Objective-C++ 文件，内部只是持有一个 C++ 的 &lt;code&gt;WebPageProxy&lt;/code&gt; 对象，几乎所有实际工作都转发给它。为什么要这样设计？原因就藏在下一节要讲的多进程架构里。&lt;/p&gt;</description></item><item><title>启动优化-Rebase与Bind</title><link>https://amatsuzero.github.io/LastStand/posts/interview/ios-performance/launch-rebase%E4%B8%8Ebind/</link><pubDate>Sat, 02 May 2026 22:32:27 +0800</pubDate><guid>https://amatsuzero.github.io/LastStand/posts/interview/ios-performance/launch-rebase%E4%B8%8Ebind/</guid><description>&lt;p&gt;Rebase和Bind是Pre-main阶段的重要步骤，用于修正程序中的指针地址。ObjC类、方法、协议等元数据越多，需要修复的指针越多，启动时间越长。&lt;/p&gt;
&lt;hr&gt;
&lt;h2 id="基本概念"&gt;基本概念&lt;/h2&gt;
&lt;p&gt;由于ASLR（Address Space Layout Randomization）技术，App每次启动时加载到内存的地址都是随机的，因此需要进行地址修正。关于Rebase和Bind的底层原理，可以参考&lt;a href="https://amatsuzero.github.io/LastStand/posts/interview/ios-basics/mach-o%E7%9A%84%E9%93%BE%E6%8E%A5-%E8%A3%85%E8%BD%BD%E4%B8%8E%E5%BA%93/"&gt;Mach-O的链接、装载与库&lt;/a&gt;。&lt;/p&gt;
&lt;h3 id="rebase重定位"&gt;Rebase（重定位）&lt;/h3&gt;
&lt;p&gt;修正指向Mach-O内部的指针，将编译时的地址加上ASLR偏移量。&lt;/p&gt;
&lt;h3 id="bind绑定"&gt;Bind（绑定）&lt;/h3&gt;
&lt;p&gt;修正指向Mach-O外部的指针，查找符号表，绑定到正确的外部符号地址。&lt;/p&gt;
&lt;pre class="mermaid"&gt;flowchart LR
subgraph compile["编译时 (Mach-O文件)"]
A1["内部指针: 0x1000&lt;br/&gt;(指向内部数据)"]
A2["外部符号: _objc_msgSend&lt;br/&gt;(待绑定)"]
end
subgraph runtime["运行时 (内存中)"]
B1["内部指针: 0x1000 + slide&lt;br/&gt;(Rebase修正)"]
B2["外部符号: 实际地址&lt;br/&gt;(Bind绑定)"]
end
A1 --&gt;|"Rebase"| B1
A2 --&gt;|"Bind"| B2
&lt;/pre&gt;
&lt;hr&gt;
&lt;h2 id="问题分析"&gt;问题分析&lt;/h2&gt;
&lt;p&gt;以下因素会增加Rebase/Bind的工作量：&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;因素&lt;/th&gt;
&lt;th&gt;影响&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;ObjC类数量&lt;/td&gt;
&lt;td&gt;每个类都有元数据需要修正&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Swift类数量&lt;/td&gt;
&lt;td&gt;Swift类在Apple平台也会生成ObjC兼容的元数据，同样需要修正&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;ObjC方法数量&lt;/td&gt;
&lt;td&gt;方法列表中的指针需要修正&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Category数量&lt;/td&gt;
&lt;td&gt;Category的方法列表需要绑定&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;C++虚函数&lt;/td&gt;
&lt;td&gt;虚函数表中的指针需要绑定&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;全局变量&lt;/td&gt;
&lt;td&gt;指向其他符号的全局变量需要绑定&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;关于缓存机制&lt;/strong&gt;：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;系统动态库&lt;/strong&gt;：Rebase/Bind 操作已在 dyld shared cache 中预先完成，不会在 App 启动时执行&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;App 动态库&lt;/strong&gt;：dyld 3 的 Launch Closure 会缓存 Rebase/Bind 的&lt;strong&gt;元数据信息&lt;/strong&gt;（哪些指针需要修正、修正方式等），但 &lt;strong&gt;Rebase/Bind 操作本身仍需每次启动时执行&lt;/strong&gt;，因为 ASLR slide 每次启动都不同&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;因此，减少 ObjC 类、Category、C++ 虚函数等仍然是有效的优化手段。&lt;/p&gt;</description></item><item><title>Swift 面试：并发、async/await 与 Actor 源码解析</title><link>https://amatsuzero.github.io/LastStand/posts/swiftinterviewsourcecode/concurrency-actor-async/</link><pubDate>Tue, 16 Jun 2026 09:06:27 +0800</pubDate><guid>https://amatsuzero.github.io/LastStand/posts/swiftinterviewsourcecode/concurrency-actor-async/</guid><description>&lt;h1 id="swift-面试并发asyncawait-与-actor-源码解析"&gt;Swift 面试：并发、async/await 与 Actor 源码解析&lt;/h1&gt;
&lt;p&gt;Swift Concurrency 面试经常从 &lt;code&gt;async/await&lt;/code&gt; 问起，但真正的重点是：&lt;strong&gt;Task 是结构化并发的执行单元，await 是显式暂停点，Actor 通过隔离和串行执行器保护状态，Sendable 则约束跨并发边界传递的数据。&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;这篇文章按面试题展开，把结论落到 Swift 标准库和编译器源码里的 Actor、GlobalActor、MainActor、AsyncLet、TaskGroup、Sendable 和 ActorIsolation。&lt;/p&gt;
&lt;h2 id="面试高频问题"&gt;面试高频问题&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;async/await 和 GCD 的关系是什么？&lt;/li&gt;
&lt;li&gt;&lt;code&gt;await&lt;/code&gt; 到底表示线程阻塞还是任务暂停？&lt;/li&gt;
&lt;li&gt;Task、async let、TaskGroup 有什么区别？&lt;/li&gt;
&lt;li&gt;Actor 如何保证数据隔离？&lt;/li&gt;
&lt;li&gt;MainActor 是什么，为什么 UI 更新要回到 MainActor？&lt;/li&gt;
&lt;li&gt;GlobalActor 和普通 Actor 有什么区别？&lt;/li&gt;
&lt;li&gt;Sendable 解决什么问题？&lt;/li&gt;
&lt;li&gt;&lt;code&gt;Task.detached&lt;/code&gt; 为什么要慎用？&lt;/li&gt;
&lt;li&gt;Actor 之间调用为什么需要 &lt;code&gt;await&lt;/code&gt;？&lt;/li&gt;
&lt;li&gt;Swift Concurrency 是编译器机制还是运行时机制？&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="30-秒回答版"&gt;30 秒回答版&lt;/h2&gt;
&lt;p&gt;Swift Concurrency 是编译器、标准库和运行时共同完成的并发模型。&lt;/p&gt;
&lt;p&gt;&lt;code&gt;async/await&lt;/code&gt; 不是对 GCD 的简单语法糖。&lt;code&gt;await&lt;/code&gt; 表示当前异步任务可能在这里暂停，把执行权交还给调度器；等异步结果可用时，再从 continuation 恢复。它不应该理解成“阻塞当前线程等待”。&lt;/p&gt;
&lt;p&gt;Actor 是一种受隔离保护的引用类型。Actor 内部可变状态只能在 actor 隔离域内访问；跨 actor 访问必须异步，编译器会插入隔离检查。运行时通过 executor 保证同一 actor 的隔离状态不会被多个任务同时进入。&lt;/p&gt;</description></item><item><title>Objective-C Category 装载与附加机制</title><link>https://amatsuzero.github.io/LastStand/posts/ocsourcecodeanalysis/category-loading-explained/</link><pubDate>Mon, 01 Jun 2026 19:50:12 +0800</pubDate><guid>https://amatsuzero.github.io/LastStand/posts/ocsourcecodeanalysis/category-loading-explained/</guid><description>&lt;p&gt;objc4 runtime&lt;/p&gt;
&lt;h1 id="category-装载与方法协议属性附加"&gt;Category 装载与方法、协议、属性附加&lt;/h1&gt;
&lt;p&gt;Category 的本质不是“修改类结构体”，而是在镜像加载和类实现化时，把分类携带的方法列表、协议列表、属性列表合并到目标类或元类的可变列表视图中。objc4 同时要处理未实现类、stub class、dyld 预附加列表、方法缓存失效和 &lt;code&gt;+load&lt;/code&gt; 顺序。&lt;/p&gt;
&lt;p&gt;runtime/objc-runtime-new.mm runtime/objc-runtime-new.h runtime/objc-loadmethod.mm test/category.m 等测试&lt;/p&gt;
&lt;h2 id="目录"&gt;目录&lt;/h2&gt;
&lt;ol&gt;
&lt;li&gt;&lt;a href="#purpose"&gt;作用&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="#model"&gt;实现原理总览&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="#structures"&gt;核心结构和字段&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="#flow"&gt;关键流程&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="#snippets"&gt;带注释核心代码&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="#tests"&gt;测试揭示的行为&lt;/a&gt;&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;&lt;a id="purpose"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;h2 id="作用"&gt;作用&lt;/h2&gt;
&lt;h3 id="扩展类行为"&gt;扩展类行为&lt;/h3&gt;
&lt;p&gt;分类把实例方法挂到类，把类方法挂到元类，让现有类获得新 selector 或覆盖既有 selector。&lt;/p&gt;
&lt;h3 id="扩展反射信息"&gt;扩展反射信息&lt;/h3&gt;
&lt;p&gt;分类的协议和属性参与 &lt;code&gt;class_copyProtocolList&lt;/code&gt;、&lt;code&gt;class_getProperty&lt;/code&gt; 等运行时查询。&lt;/p&gt;
&lt;h3 id="保持加载顺序"&gt;保持加载顺序&lt;/h3&gt;
&lt;p&gt;后加载的分类应优先被方法查找看到，所以列表附加采用“前插”。&lt;/p&gt;
&lt;h3 id="支持动态镜像"&gt;支持动态镜像&lt;/h3&gt;
&lt;p&gt;bundle、共享缓存、stub class 和未实现类都能在不同时间点接收分类。&lt;/p&gt;
&lt;p&gt;关键结论：分类附加不是把方法逐个复制进类定义，而是把 &lt;code&gt;method_list_t&lt;/code&gt;、&lt;code&gt;protocol_list_t&lt;/code&gt;、&lt;code&gt;property_list_t&lt;/code&gt; 这类“列表”挂到 &lt;code&gt;class_rw_ext_t&lt;/code&gt; 的数组视图前端。&lt;/p&gt;
&lt;p&gt;&lt;a id="model"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;h2 id="实现原理总览"&gt;实现原理总览&lt;/h2&gt;
&lt;h3 id="mach-o-镜像"&gt;Mach-O 镜像&lt;/h3&gt;
&lt;p&gt;&lt;code&gt;__objc_catlist&lt;/code&gt; / &lt;code&gt;__objc_catlist2&lt;/code&gt; 中保存 &lt;code&gt;category_t *&lt;/code&gt;。runtime 通过 &lt;code&gt;header_info&lt;/code&gt; 知道分类来自哪个镜像。&lt;/p&gt;
&lt;p&gt;→&lt;/p&gt;
&lt;h3 id="分类分流"&gt;分类分流&lt;/h3&gt;
&lt;p&gt;目标类未实现则暂存到 &lt;code&gt;unattachedCategories&lt;/code&gt;；目标类已实现则立即 &lt;code&gt;attachCategories&lt;/code&gt;。&lt;/p&gt;
&lt;p&gt;→&lt;/p&gt;
&lt;h3 id="列表前插"&gt;列表前插&lt;/h3&gt;
&lt;p&gt;&lt;code&gt;attachLists&lt;/code&gt; 把新增列表放在旧列表前面，方法查找和反射会先看到分类列表。&lt;/p&gt;
&lt;p&gt;依据：&lt;code&gt;load_categories_nolock&lt;/code&gt; 分流逻辑见 runtime/objc-runtime-new.mm:3585-3717；列表前插见 runtime/objc-runtime-new.h:2021-2105。&lt;/p&gt;
&lt;p&gt;&lt;a id="structures"&gt;&lt;/a&gt;&lt;/p&gt;</description></item><item><title>APM-产品与架构设计</title><link>https://amatsuzero.github.io/LastStand/posts/interview/ios-apm/%E4%BA%A7%E5%93%81%E4%B8%8E%E6%9E%B6%E6%9E%84%E8%AE%BE%E8%AE%A1/</link><pubDate>Thu, 07 May 2026 15:42:48 +0800</pubDate><guid>https://amatsuzero.github.io/LastStand/posts/interview/ios-apm/%E4%BA%A7%E5%93%81%E4%B8%8E%E6%9E%B6%E6%9E%84%E8%AE%BE%E8%AE%A1/</guid><description>&lt;p&gt;APM 系统的产品设计不能从“要采哪些指标”开始，而应该从“谁要用这些数据解决什么问题”开始。iOS APM 的产品形态可以分成 C 端真实用户体验、B 端研发治理平台两面；技术实现则分成 iOS SDK、数据平台、Web 控制台三层。&lt;/p&gt;
&lt;hr&gt;
&lt;h2 id="一产品边界"&gt;一、产品边界&lt;/h2&gt;
&lt;p&gt;APM 的 C 端不是一个给用户看的页面，而是运行在用户设备里的监控能力；APM 的 B 端才是研发、测试、架构、运维、产品、客服使用的控制台。&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;视角&lt;/th&gt;
&lt;th&gt;C 端&lt;/th&gt;
&lt;th&gt;B 端&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;用户&lt;/td&gt;
&lt;td&gt;App 真实用户&lt;/td&gt;
&lt;td&gt;研发、测试、架构、运维、产品、客服&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;形态&lt;/td&gt;
&lt;td&gt;iOS SDK，无感运行&lt;/td&gt;
&lt;td&gt;Web 控制台、告警、工单、报表&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;核心体验&lt;/td&gt;
&lt;td&gt;不打扰、不拖慢、不泄露隐私&lt;/td&gt;
&lt;td&gt;快速发现、下钻、归因、分发、验证&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;主要风险&lt;/td&gt;
&lt;td&gt;SDK 自身引发卡顿、崩溃、耗电、流量&lt;/td&gt;
&lt;td&gt;指标口径混乱、告警疲劳、无法定位&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;成功标准&lt;/td&gt;
&lt;td&gt;数据真实且采集成本低&lt;/td&gt;
&lt;td&gt;问题能被稳定治理，发布劣化能被拦截&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;因此产品设计要同时回答两类问题：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-text" data-lang="text"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;C端：真实用户到底经历了什么？
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;B端：团队如何用这些数据把问题修掉？
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;hr&gt;
&lt;h2 id="二用户角色"&gt;二、用户角色&lt;/h2&gt;
&lt;p&gt;APM B 端不是只给研发看，不同角色需要不同入口。&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;角色&lt;/th&gt;
&lt;th&gt;典型问题&lt;/th&gt;
&lt;th&gt;核心视图&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;客户端研发&lt;/td&gt;
&lt;td&gt;我负责的模块有没有新 Crash、卡顿、FOOM&lt;/td&gt;
&lt;td&gt;我的 Issue、堆栈详情、会话时间线&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;后端研发&lt;/td&gt;
&lt;td&gt;某接口在真实用户侧是否变慢、失败率是否升高&lt;/td&gt;
&lt;td&gt;网络资源详情、Trace 关联、接口维度大盘&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;测试/QA&lt;/td&gt;
&lt;td&gt;灰度版本是否比线上版本变差&lt;/td&gt;
&lt;td&gt;版本对比、灰度监控、回归报告&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;架构/技术负责人&lt;/td&gt;
&lt;td&gt;App 整体质量趋势如何，哪个团队拖后腿&lt;/td&gt;
&lt;td&gt;质量大盘、模块排行、SLO&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;产品/业务负责人&lt;/td&gt;
&lt;td&gt;性能是否影响转化、留存、下单&lt;/td&gt;
&lt;td&gt;页面秒开率、关键路径成功率、业务漏斗&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;客服/运营&lt;/td&gt;
&lt;td&gt;单个用户为什么反馈无法使用&lt;/td&gt;
&lt;td&gt;用户查询、Session 轨迹、错误上下文&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;设计 B 端时不要把所有人塞进同一个大盘。首页可以共用，但下钻路径要按角色分流。&lt;/p&gt;</description></item><item><title>Kingfisher源码导读</title><link>https://amatsuzero.github.io/LastStand/posts/interview/ios-source-analysis/kingfisher%E6%BA%90%E7%A0%81%E5%AF%BC%E8%AF%BB/</link><pubDate>Sat, 02 May 2026 22:32:27 +0800</pubDate><guid>https://amatsuzero.github.io/LastStand/posts/interview/ios-source-analysis/kingfisher%E6%BA%90%E7%A0%81%E5%AF%BC%E8%AF%BB/</guid><description>&lt;p&gt;Kingfisher 是一款纯 Swift 图片下载和缓存库，支持 iOS、macOS、tvOS、watchOS 和 visionOS 全平台。当前最新版本为 &lt;strong&gt;8.8.0&lt;/strong&gt;（2026年3月），已全面适配 Swift 6 严格并发模型。本文基于 v8.x 源码进行分析。&lt;/p&gt;
&lt;hr&gt;
&lt;h2 id="一整体架构"&gt;一、整体架构&lt;/h2&gt;
&lt;p&gt;Kingfisher 采用&lt;strong&gt;协议导向&lt;/strong&gt;的模块化设计，核心由四大组件构成：&lt;/p&gt;
&lt;pre class="mermaid"&gt;graph TB
subgraph "UI层"
A["UIImageView.kf / KFImage"]
end
subgraph "管理层"
B["KingfisherManager"]
end
subgraph "功能层"
C["ImageDownloader"]
D["ImageCache"]
E["ImageProcessor"]
end
subgraph "存储层"
F["MemoryStorage.Backend&lt;br/&gt;(NSCache)"]
G["DiskStorage.Backend&lt;br/&gt;(FileManager)"]
end
A --&gt;|"retrieveImage"| B
B --&gt;|"下载"| C
B --&gt;|"缓存"| D
B --&gt;|"处理"| E
D --&gt; F
D --&gt; G
&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;源码目录结构：&lt;/strong&gt;&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-gdscript3" data-lang="gdscript3"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;Sources&lt;span style="color:#f92672"&gt;/&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#960050;background-color:#1e0010"&gt;├──&lt;/span&gt; General&lt;span style="color:#f92672"&gt;/&lt;/span&gt; &lt;span style="color:#75715e"&gt;# KingfisherManager, KingfisherOptionsInfo, Resource, Source&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#960050;background-color:#1e0010"&gt;├──&lt;/span&gt; Networking&lt;span style="color:#f92672"&gt;/&lt;/span&gt; &lt;span style="color:#75715e"&gt;# ImageDownloader, SessionDelegate, ImagePrefetcher&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#960050;background-color:#1e0010"&gt;├──&lt;/span&gt; Cache&lt;span style="color:#f92672"&gt;/&lt;/span&gt; &lt;span style="color:#75715e"&gt;# ImageCache, MemoryStorage, DiskStorage&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#960050;background-color:#1e0010"&gt;├──&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;Image&lt;/span&gt;&lt;span style="color:#f92672"&gt;/&lt;/span&gt; &lt;span style="color:#75715e"&gt;# ImageProcessor, 图片格式处理, 滤镜&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#960050;background-color:#1e0010"&gt;├──&lt;/span&gt; Extensions&lt;span style="color:#f92672"&gt;/&lt;/span&gt; &lt;span style="color:#75715e"&gt;# UIKit/AppKit 扩展 (ImageView+Kingfisher, UIButton+Kingfisher)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#960050;background-color:#1e0010"&gt;├──&lt;/span&gt; SwiftUI&lt;span style="color:#f92672"&gt;/&lt;/span&gt; &lt;span style="color:#75715e"&gt;# KFImage, KFAnimatedImage, ImageBinder&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#960050;background-color:#1e0010"&gt;├──&lt;/span&gt; Views&lt;span style="color:#f92672"&gt;/&lt;/span&gt; &lt;span style="color:#75715e"&gt;# AnimatedImageView&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#960050;background-color:#1e0010"&gt;└──&lt;/span&gt; Utility&lt;span style="color:#f92672"&gt;/&lt;/span&gt; &lt;span style="color:#75715e"&gt;# 辅助工具类&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;hr&gt;
&lt;h2 id="二命名空间设计--kingfisherwrapper"&gt;二、命名空间设计 — KingfisherWrapper&lt;/h2&gt;
&lt;p&gt;Kingfisher 使用 &lt;code&gt;kf&lt;/code&gt; 命名空间来避免对系统类型的污染，这是 Swift 社区广泛使用的一种模式。&lt;/p&gt;</description></item><item><title>KVC底层原理</title><link>https://amatsuzero.github.io/LastStand/posts/interview/ios-basics/kvc%E5%BA%95%E5%B1%82%E5%8E%9F%E7%90%86/</link><pubDate>Sat, 02 May 2026 22:32:27 +0800</pubDate><guid>https://amatsuzero.github.io/LastStand/posts/interview/ios-basics/kvc%E5%BA%95%E5%B1%82%E5%8E%9F%E7%90%86/</guid><description>&lt;h2 id="基础概念"&gt;基础概念&lt;/h2&gt;
&lt;p&gt;KVC（Key-Value Coding，键值编码）是 Apple 提供的一种通过字符串 key 间接访问对象属性的机制，定义在 &lt;code&gt;NSKeyValueCoding&lt;/code&gt; 协议中，&lt;code&gt;NSObject&lt;/code&gt; 默认遵循该协议。&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-objc" data-lang="objc"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;// 直接访问
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;person.name &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#e6db74"&gt;@&amp;#34;Tom&amp;#34;&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;NSString &lt;span style="color:#f92672"&gt;*&lt;/span&gt;name &lt;span style="color:#f92672"&gt;=&lt;/span&gt; person.name;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;// KVC 访问
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;[person setValue:&lt;span style="color:#e6db74"&gt;@&amp;#34;Tom&amp;#34;&lt;/span&gt; forKey:&lt;span style="color:#e6db74"&gt;@&amp;#34;name&amp;#34;&lt;/span&gt;];
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;NSString &lt;span style="color:#f92672"&gt;*&lt;/span&gt;name &lt;span style="color:#f92672"&gt;=&lt;/span&gt; [person valueForKey:&lt;span style="color:#e6db74"&gt;@&amp;#34;name&amp;#34;&lt;/span&gt;];
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;KVC 的核心价值在于：通过字符串动态访问属性，不需要在编译期知道属性名。这使得字典转模型、序列化/反序列化、Interface Builder 的 Runtime Attributes 等场景成为可能。&lt;/p&gt;
&lt;h2 id="setvalueforkey-的底层流程"&gt;setValue:forKey: 的底层流程&lt;/h2&gt;
&lt;p&gt;当调用 &lt;code&gt;[obj setValue:value forKey:@&amp;quot;name&amp;quot;]&lt;/code&gt; 时，Runtime 按照以下顺序查找：&lt;/p&gt;
&lt;pre class="mermaid"&gt;flowchart TD
A["setValue:forKey:@'name'"] --&gt; B{"查找 setter 方法"}
B --&gt;|"找到"| C["调用 setter"]
B --&gt;|"未找到"| D{"accessInstanceVariablesDirectly&lt;br/&gt;返回 YES?"}
D --&gt;|"YES"| E{"按顺序查找实例变量&lt;br/&gt;_name → _isName → name → isName"}
D --&gt;|"NO"| F["调用 setValue:forUndefinedKey:&lt;br/&gt;默认抛出 NSUndefinedKeyException"]
E --&gt;|"找到"| G["直接设置实例变量值"]
E --&gt;|"未找到"| F
&lt;/pre&gt;
&lt;h3 id="第一步查找-setter-方法"&gt;第一步：查找 setter 方法&lt;/h3&gt;
&lt;p&gt;Runtime 按以下顺序查找 setter 方法：&lt;/p&gt;</description></item><item><title>MVVM架构详解</title><link>https://amatsuzero.github.io/LastStand/posts/interview/ios-architecture/mvvm/</link><pubDate>Sat, 02 May 2026 22:32:27 +0800</pubDate><guid>https://amatsuzero.github.io/LastStand/posts/interview/ios-architecture/mvvm/</guid><description>&lt;h2 id="什么是mvvm"&gt;什么是MVVM&lt;/h2&gt;
&lt;p&gt;MVVM（Model-View-ViewModel）是一种通过数据绑定实现View和业务逻辑解耦的架构模式。它最初由Microsoft提出，用于WPF开发，后来被广泛应用于iOS开发。&lt;/p&gt;
&lt;p&gt;MVVM的核心特点是：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;ViewModel不持有View的引用&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;通过数据绑定实现View和ViewModel的同步&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;View的状态完全由ViewModel驱动&lt;/strong&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="mvvm的结构"&gt;MVVM的结构&lt;/h2&gt;
&lt;pre class="mermaid"&gt;flowchart TB
subgraph View["View (ViewController)"]
V1["绑定ViewModel的属性"]
V2["将用户事件传递给ViewModel"]
end
subgraph ViewModel["ViewModel"]
VM1["暴露可观察的属性"]
VM2["展示逻辑 + 业务逻辑"]
end
subgraph Model["Model"]
M1["数据模型"]
M2["数据访问 (API/DB)"]
end
View &lt;--&gt;|"数据绑定 (Binding)"| ViewModel
ViewModel --&gt;|"获取/更新数据"| Model
&lt;/pre&gt;
&lt;h2 id="mvvm的数据流"&gt;MVVM的数据流&lt;/h2&gt;
&lt;p&gt;MVVM的核心原则是：&lt;strong&gt;View不直接访问Model&lt;/strong&gt;，所有交互都通过ViewModel进行。在iOS开发中，由于&lt;code&gt;UIViewController&lt;/code&gt;的特殊地位，MVVM的数据流可以更细化为四个角色：&lt;/p&gt;
&lt;pre class="mermaid"&gt;flowchart LR
subgraph View["View"]
V["纯UI展示&lt;br/&gt;用户交互触发"]
end
subgraph ViewController["ViewController"]
VC["数据绑定&lt;br/&gt;生命周期管理&lt;br/&gt;路由/导航"]
end
subgraph ViewModel["ViewModel"]
VM["业务逻辑&lt;br/&gt;数据转换&lt;br/&gt;状态管理"]
end
subgraph Model["Model"]
M["数据结构&lt;br/&gt;数据存储"]
end
VC --&gt;|"持有"| V
VC --&gt;|"持有"| VM
V --&gt;|"1. 用户交互"| VC
VC --&gt;|"2. 转发事件"| VM
VM --&gt;|"3. 业务处理"| M
M --&gt;|"4. 数据变化"| VM
VM --&gt;|"5. 状态更新"| VC
VC --&gt;|"6. 更新UI"| V
&lt;/pre&gt;
&lt;h3 id="各层职责与持有关系"&gt;各层职责与持有关系&lt;/h3&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;组件&lt;/th&gt;
&lt;th&gt;职责&lt;/th&gt;
&lt;th&gt;持有关系&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;View&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;纯UI展示、触发用户交互事件&lt;/td&gt;
&lt;td&gt;不持有其他层&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;ViewController&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;数据绑定、生命周期管理、持有View和ViewModel&lt;/td&gt;
&lt;td&gt;持有View和ViewModel&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;ViewModel&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;业务逻辑、数据转换、状态管理&lt;/td&gt;
&lt;td&gt;持有Model/Service&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Model&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;数据结构、数据存储&lt;/td&gt;
&lt;td&gt;不持有其他层&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;h3 id="详细数据流说明"&gt;详细数据流说明&lt;/h3&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;View → ViewController（用户交互）&lt;/strong&gt;&lt;/p&gt;</description></item><item><title>WebView离线包</title><link>https://amatsuzero.github.io/LastStand/posts/interview/ios-advanced/webview%E7%A6%BB%E7%BA%BF%E5%8C%85/</link><pubDate>Sat, 02 May 2026 22:32:27 +0800</pubDate><guid>https://amatsuzero.github.io/LastStand/posts/interview/ios-advanced/webview%E7%A6%BB%E7%BA%BF%E5%8C%85/</guid><description>&lt;h2 id="背景"&gt;背景&lt;/h2&gt;
&lt;p&gt;Hybrid 开发模式下，WebView 加载 H5 页面的体验一直是痛点。一个典型的 H5 页面加载流程涉及：初始化 WebView -&amp;gt; DNS 解析 -&amp;gt; 建立连接 -&amp;gt; 下载 HTML -&amp;gt; 解析 HTML -&amp;gt; 下载 CSS/JS/图片 -&amp;gt; 渲染页面。在弱网或首次加载场景下，白屏时间常常达到 2~5 秒，远不如 Native 体验。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;离线包&lt;/strong&gt;的核心思路是：将 H5 的静态资源（HTML、CSS、JS、图片、字体等）预先打包下发到客户端本地，WebView 加载时直接从本地读取资源，跳过网络请求环节，从而大幅缩短页面加载时间。&lt;/p&gt;
&lt;h2 id="离线包加载-vs-在线加载"&gt;离线包加载 vs 在线加载&lt;/h2&gt;
&lt;pre class="mermaid"&gt;sequenceDiagram
participant App
participant WebView
participant Local as 本地离线包
participant Server as 远程服务器
Note over App, Server: 在线加载流程
App-&gt;&gt;WebView: loadURL
WebView-&gt;&gt;Server: DNS + TCP + TLS + HTTP请求
Server--&gt;&gt;WebView: HTML
WebView-&gt;&gt;Server: 请求 CSS/JS/图片
Server--&gt;&gt;WebView: 资源文件
WebView-&gt;&gt;WebView: 渲染页面
Note over App, Server: 离线包加载流程
App-&gt;&gt;WebView: loadURL（被拦截）
WebView-&gt;&gt;Local: 读取本地 HTML
Local--&gt;&gt;WebView: HTML
WebView-&gt;&gt;Local: 读取本地 CSS/JS/图片
Local--&gt;&gt;WebView: 资源文件
WebView-&gt;&gt;WebView: 渲染页面
&lt;/pre&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;对比项&lt;/th&gt;
&lt;th&gt;在线加载&lt;/th&gt;
&lt;th&gt;离线包加载&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;首屏时间&lt;/td&gt;
&lt;td&gt;2~5秒（弱网更久）&lt;/td&gt;
&lt;td&gt;0.5~1秒&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;网络依赖&lt;/td&gt;
&lt;td&gt;强依赖&lt;/td&gt;
&lt;td&gt;仅更新时需要网络&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;白屏问题&lt;/td&gt;
&lt;td&gt;严重&lt;/td&gt;
&lt;td&gt;基本消除&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;资源新鲜度&lt;/td&gt;
&lt;td&gt;实时最新&lt;/td&gt;
&lt;td&gt;有一定延迟&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;流量消耗&lt;/td&gt;
&lt;td&gt;每次访问都消耗&lt;/td&gt;
&lt;td&gt;仅增量更新消耗&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;h2 id="整体架构"&gt;整体架构&lt;/h2&gt;
&lt;p&gt;一个完整的离线包系统包含三大部分：&lt;/p&gt;</description></item><item><title>启动优化-didFinishLaunching</title><link>https://amatsuzero.github.io/LastStand/posts/interview/ios-performance/launch-didfinishlaunching/</link><pubDate>Sat, 02 May 2026 22:32:27 +0800</pubDate><guid>https://amatsuzero.github.io/LastStand/posts/interview/ios-performance/launch-didfinishlaunching/</guid><description>&lt;p&gt;&lt;code&gt;didFinishLaunchingWithOptions&lt;/code&gt;是main阶段的核心入口，在这里初始化大量SDK和服务会阻塞启动。本文介绍如何优化这个阶段的耗时。&lt;/p&gt;
&lt;hr&gt;
&lt;h2 id="问题分析"&gt;问题分析&lt;/h2&gt;
&lt;p&gt;典型的问题代码：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-swift" data-lang="swift"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;func&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;application&lt;/span&gt;(&lt;span style="color:#66d9ef"&gt;_&lt;/span&gt; application: UIApplication,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -&amp;gt; Bool {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#75715e"&gt;// 所有初始化都在主线程同步执行&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; CrashReporter.setup()
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; Analytics.setup()
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; PushNotification.setup()
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; NetworkManager.setup()
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; DatabaseManager.setup()
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; ImageCache.setup()
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; AdSDK.setup()
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; SocialSDK.setup()
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#75715e"&gt;// ... 更多SDK&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;return&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;true&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;这种写法的问题：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;所有初始化都在主线程同步执行&lt;/li&gt;
&lt;li&gt;无论是否需要，所有SDK都在启动时初始化&lt;/li&gt;
&lt;li&gt;阻塞首帧渲染&lt;/li&gt;
&lt;/ol&gt;
&lt;hr&gt;
&lt;h2 id="优化方案"&gt;优化方案&lt;/h2&gt;
&lt;h3 id="方案1分级启动任务管理"&gt;方案1：分级启动任务管理&lt;/h3&gt;
&lt;p&gt;将启动任务按优先级分类，只在启动时执行必要的任务：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-swift" data-lang="swift"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;// 启动任务优先级&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;enum&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;LaunchTaskPriority&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;case&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;required&lt;/span&gt; &lt;span style="color:#75715e"&gt;// 必须在首帧前完成&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;case&lt;/span&gt; high &lt;span style="color:#75715e"&gt;// 首帧后立即执行&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;case&lt;/span&gt; normal &lt;span style="color:#75715e"&gt;// 首屏稳定后执行&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;case&lt;/span&gt; low &lt;span style="color:#75715e"&gt;// 空闲时执行&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;// 启动任务管理器&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;class&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;LaunchTaskManager&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;static&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;let&lt;/span&gt; shared = LaunchTaskManager()
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;private&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;var&lt;/span&gt; tasks: [LaunchTaskPriority: [() -&amp;gt; Void]] = [:]
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;func&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;register&lt;/span&gt;(priority: LaunchTaskPriority, task: @escaping () -&amp;gt; Void) {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;if&lt;/span&gt; tasks[priority] == &lt;span style="color:#66d9ef"&gt;nil&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; tasks[priority] = []
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; }
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; tasks[priority]?.append(task)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; }
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;func&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;executeRequiredTasks&lt;/span&gt;() {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; tasks[.&lt;span style="color:#66d9ef"&gt;required&lt;/span&gt;]?.forEach { $0() }
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; }
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;func&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;executeHighPriorityTasks&lt;/span&gt;() {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; DispatchQueue.main.async {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;self&lt;/span&gt;.tasks[.high]?.forEach { $0() }
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; }
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; }
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;func&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;executeNormalTasks&lt;/span&gt;() {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; DispatchQueue.main.asyncAfter(deadline: .now() &lt;span style="color:#f92672"&gt;+&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;1.0&lt;/span&gt;) {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;self&lt;/span&gt;.tasks[.normal]?.forEach { $0() }
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; }
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; }
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;func&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;executeLowPriorityTasks&lt;/span&gt;() {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#75715e"&gt;// 监听RunLoop空闲时执行&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; CFRunLoopPerformBlock(CFRunLoopGetMain(), kCFRunLoopDefaultMode) {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;self&lt;/span&gt;.tasks[.low]?.forEach { $0() }
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; }
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; }
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h3 id="使用示例"&gt;使用示例&lt;/h3&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-swift" data-lang="swift"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;func&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;application&lt;/span&gt;(&lt;span style="color:#66d9ef"&gt;_&lt;/span&gt; application: UIApplication,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -&amp;gt; Bool {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;let&lt;/span&gt; manager = LaunchTaskManager.shared
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#75715e"&gt;// 必须在首帧前完成&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; manager.register(priority: .&lt;span style="color:#66d9ef"&gt;required&lt;/span&gt;) {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; CrashReporter.setup() &lt;span style="color:#75715e"&gt;// 崩溃收集必须最先初始化&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; }
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#75715e"&gt;// 首帧后立即执行&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; manager.register(priority: .high) {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; Analytics.setup()
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; PushNotification.setup()
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; }
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#75715e"&gt;// 首屏稳定后执行&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; manager.register(priority: .normal) {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; AdSDK.setup()
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; SocialSDK.setup()
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; }
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#75715e"&gt;// 空闲时执行&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; manager.register(priority: .low) {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; PreloadManager.preloadResources()
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; }
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#75715e"&gt;// 只执行必须的任务&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; manager.executeRequiredTasks()
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;return&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;true&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h3 id="任务分级建议"&gt;任务分级建议&lt;/h3&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;优先级&lt;/th&gt;
&lt;th&gt;适用场景&lt;/th&gt;
&lt;th&gt;示例&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;required&lt;/td&gt;
&lt;td&gt;崩溃收集、核心功能依赖&lt;/td&gt;
&lt;td&gt;Crash SDK、必要的配置加载&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;high&lt;/td&gt;
&lt;td&gt;用户可能很快用到&lt;/td&gt;
&lt;td&gt;推送、统计、网络配置&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;normal&lt;/td&gt;
&lt;td&gt;非首屏功能&lt;/td&gt;
&lt;td&gt;广告SDK、社交分享&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;low&lt;/td&gt;
&lt;td&gt;预加载、缓存&lt;/td&gt;
&lt;td&gt;图片预加载、数据预热&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;hr&gt;
&lt;h3 id="方案2并行初始化"&gt;方案2：并行初始化&lt;/h3&gt;
&lt;p&gt;将无依赖关系的初始化任务并行执行：&lt;/p&gt;</description></item><item><title>编译优化-Swift编译优化</title><link>https://amatsuzero.github.io/LastStand/posts/interview/ios-build/swift%E7%BC%96%E8%AF%91%E4%BC%98%E5%8C%96/</link><pubDate>Sat, 02 May 2026 22:32:27 +0800</pubDate><guid>https://amatsuzero.github.io/LastStand/posts/interview/ios-build/swift%E7%BC%96%E8%AF%91%E4%BC%98%E5%8C%96/</guid><description>&lt;p&gt;Swift 的类型推导、泛型约束求解、WMO / CMO 是编译性能的核心影响因素。理解它们能让源码层面的小改动带来显著的编译加速。本文聚焦&amp;quot;代码写法 + 编译开关&amp;quot;两方面的优化。&lt;/p&gt;
&lt;hr&gt;
&lt;h2 id="swift-编译流程速览"&gt;Swift 编译流程速览&lt;/h2&gt;
&lt;p&gt;相比 C/OC，Swift 编译多出大量工作：&lt;/p&gt;
&lt;pre class="mermaid"&gt;flowchart LR
A[Parse] --&gt; B[Sema&lt;br/&gt;类型检查]
B --&gt; C[SILGen&lt;br/&gt;生成 SIL]
C --&gt; D[SIL Optimization]
D --&gt; E[IRGen&lt;br/&gt;LLVM IR]
E --&gt; F[LLVM Optimization]
F --&gt; G[CodeGen]
&lt;/pre&gt;
&lt;p&gt;其中 &lt;strong&gt;Sema（语义分析）&lt;/strong&gt; 阶段负责类型推导，是 Swift 特有的性能热点。&lt;code&gt;-debug-time-compilation&lt;/code&gt; 看到的 &amp;ldquo;Type checking&amp;rdquo; 时间基本都集中在这里。&lt;/p&gt;
&lt;hr&gt;
&lt;h2 id="类型推导与-too-complex-错误"&gt;类型推导与 &amp;ldquo;Too Complex&amp;rdquo; 错误&lt;/h2&gt;
&lt;h3 id="约束求解"&gt;约束求解&lt;/h3&gt;
&lt;p&gt;Swift 的类型系统比大多数语言复杂：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;函数重载 + 运算符重载&lt;/li&gt;
&lt;li&gt;隐式字面量类型（&lt;code&gt;Int&lt;/code&gt;、&lt;code&gt;Double&lt;/code&gt;、&lt;code&gt;Float80&lt;/code&gt;…）&lt;/li&gt;
&lt;li&gt;泛型 + 协议 + 关联类型&lt;/li&gt;
&lt;li&gt;闭包参数类型推导&lt;/li&gt;
&lt;li&gt;SwiftUI 风格的 ViewBuilder / Result Builders&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;遇到表达式 &lt;code&gt;let x = a + b * c - d&lt;/code&gt;，编译器需要给 &lt;code&gt;+ * -&lt;/code&gt; 每个运算符枚举所有可能的重载，在多个候选里做约束传播。当候选组合爆炸时，Sema 会放弃并抛出：&lt;/p&gt;</description></item><item><title>Swift 面试：编译流程、Runtime 与元数据源码解析</title><link>https://amatsuzero.github.io/LastStand/posts/swiftinterviewsourcecode/compiler-runtime/</link><pubDate>Tue, 16 Jun 2026 09:06:27 +0800</pubDate><guid>https://amatsuzero.github.io/LastStand/posts/swiftinterviewsourcecode/compiler-runtime/</guid><description>&lt;h1 id="swift-面试编译流程runtime-与元数据源码解析"&gt;Swift 面试：编译流程、Runtime 与元数据源码解析&lt;/h1&gt;
&lt;p&gt;Swift 面试里问编译流程和 Runtime，通常不是想听一串名词，而是想看你能不能把 &lt;strong&gt;源码 -&amp;gt; AST -&amp;gt; SIL -&amp;gt; 优化 -&amp;gt; IRGen -&amp;gt; LLVM -&amp;gt; Runtime Metadata&lt;/strong&gt; 串起来。&lt;/p&gt;
&lt;p&gt;这篇文章按面试题展开，把答案落到 Swift 编译器源码里的 SILGen、SILOptimizer、IRGen、Metadata、Value Witness Table、Protocol Witness Table 和 HeapObject。&lt;/p&gt;
&lt;h2 id="面试高频问题"&gt;面试高频问题&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;Swift 源码从 &lt;code&gt;.swift&lt;/code&gt; 到机器码经历哪些阶段？&lt;/li&gt;
&lt;li&gt;AST、SIL、LLVM IR 分别负责什么？&lt;/li&gt;
&lt;li&gt;为什么 Swift 需要 SIL，而不是直接生成 LLVM IR？&lt;/li&gt;
&lt;li&gt;SILGen 做什么？SILOptimizer 做什么？&lt;/li&gt;
&lt;li&gt;IRGen 为什么要生成 Metadata 和 Witness Table？&lt;/li&gt;
&lt;li&gt;Swift Runtime Metadata 保存了哪些信息？&lt;/li&gt;
&lt;li&gt;Value Witness Table 是什么？&lt;/li&gt;
&lt;li&gt;Protocol Witness Table 和 class vtable 有什么区别？&lt;/li&gt;
&lt;li&gt;class、struct、enum 在 Runtime 表示上有什么差异？&lt;/li&gt;
&lt;li&gt;HeapObject 和 Metadata 有什么关系？&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="30-秒回答版"&gt;30 秒回答版&lt;/h2&gt;
&lt;p&gt;Swift 编译流程可以简化为：&lt;/p&gt;</description></item><item><title>Objective-C +load 调度：load_images 与 call_load_methods</title><link>https://amatsuzero.github.io/LastStand/posts/ocsourcecodeanalysis/load-method-explained/</link><pubDate>Mon, 01 Jun 2026 19:50:12 +0800</pubDate><guid>https://amatsuzero.github.io/LastStand/posts/ocsourcecodeanalysis/load-method-explained/</guid><description>&lt;p&gt;objc4 runtime&lt;/p&gt;
&lt;h1 id="load-调度从-load_images-到-call_load_methods"&gt;+load 调度：从 load_images 到 call_load_methods&lt;/h1&gt;
&lt;p&gt;这页解释 objc4 如何在 dyld 映射镜像后发现、排队并调用 Objective-C 的 &lt;code&gt;+load&lt;/code&gt;。 重点是类与分类的顺序、父类优先、递归和重入处理，以及 &lt;code&gt;runtimeLock&lt;/code&gt; 与 &lt;code&gt;loadMethodLock&lt;/code&gt; 的边界。&lt;/p&gt;
&lt;p&gt;入口：dyld callback 队列：loadable_classes / loadable_categories 调度：call_load_methods 测试：load*.m&lt;/p&gt;
&lt;h2 id="目录"&gt;目录&lt;/h2&gt;
&lt;p&gt;&lt;a href="#purpose"&gt;作用&lt;/a&gt; &lt;a href="#principle"&gt;实现原理&lt;/a&gt; &lt;a href="#structures"&gt;核心结构和关键函数&lt;/a&gt; &lt;a href="#flow"&gt;关键流程&lt;/a&gt; &lt;a href="#code"&gt;带注释代码片段&lt;/a&gt; &lt;a href="#tests"&gt;测试体现的语义&lt;/a&gt;&lt;/p&gt;
&lt;h2 id="作用"&gt;作用&lt;/h2&gt;
&lt;p&gt;&lt;code&gt;+load&lt;/code&gt; 是 Objective-C 运行时在类或分类被装入进程时主动调用的类方法。 它不依赖消息发送触发，也早于普通的 &lt;code&gt;+initialize&lt;/code&gt;。objc4 的任务不是简单遍历所有方法并调用， 而是在 dyld 映射镜像、runtime 完成类注册和分类附着后，按照语言语义和装载依赖稳定地调用。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;装载时机&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;dyld 通过 &lt;code&gt;_dyld_objc_register_callbacks&lt;/code&gt; 注册 runtime 回调。镜像映射后先走 &lt;code&gt;map_images&lt;/code&gt;，随后 &lt;code&gt;load_images&lt;/code&gt; 处理该镜像中的非懒加载类和分类。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;顺序语义&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;类 &lt;code&gt;+load&lt;/code&gt; 必须父类优先；所有当前可调用的类 &lt;code&gt;+load&lt;/code&gt; 先于分类 &lt;code&gt;+load&lt;/code&gt;；分类必须等宿主类已经完成自己的 &lt;code&gt;+load&lt;/code&gt;。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;重入安全&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;&lt;code&gt;+load&lt;/code&gt; 内部可能 &lt;code&gt;dlopen&lt;/code&gt; 新镜像，再次进入 &lt;code&gt;load_images&lt;/code&gt;。objc4 让内层调用只排队，真正调用由最外层 &lt;code&gt;call_load_methods&lt;/code&gt; 收尾。&lt;/p&gt;
&lt;h2 id="实现原理"&gt;实现原理&lt;/h2&gt;
&lt;p&gt;objc4 将 &lt;code&gt;+load&lt;/code&gt; 分成“发现”和“调用”两阶段。发现阶段需要持有 &lt;code&gt;runtimeLock&lt;/code&gt;， 因为它要读取和实现类、解析分类、查找元类方法列表。调用阶段释放 &lt;code&gt;runtimeLock&lt;/code&gt;， 只持有递归的 &lt;code&gt;loadMethodLock&lt;/code&gt;，因为用户代码可能执行任意 Objective-C 行为并重新映射镜像。&lt;/p&gt;</description></item><item><title>APM-指标体系</title><link>https://amatsuzero.github.io/LastStand/posts/interview/ios-apm/%E6%8C%87%E6%A0%87%E4%BD%93%E7%B3%BB/</link><pubDate>Thu, 07 May 2026 15:42:48 +0800</pubDate><guid>https://amatsuzero.github.io/LastStand/posts/interview/ios-apm/%E6%8C%87%E6%A0%87%E4%BD%93%E7%B3%BB/</guid><description>&lt;p&gt;APM 的第一步不是写代码，而是&lt;strong&gt;定义指标&lt;/strong&gt;。一个 App 的性能好坏不是一句话能说清的，必须把模糊的&amp;quot;快 / 稳 / 省&amp;quot;拆解为可量化、可对比、可报警的数字。本文把业界常用指标按&amp;quot;稳定性 / 流畅性 / 启动 / 资源 / 业务 / 网络&amp;quot;六大族分类，并补充 RUM 的 &lt;code&gt;Session / View / Action / Resource / Error&lt;/code&gt; 口径，给出每个指标的定义、计算方式、典型目标值与常见陷阱。&lt;/p&gt;
&lt;hr&gt;
&lt;h2 id="一指标设计原则"&gt;一、指标设计原则&lt;/h2&gt;
&lt;p&gt;设计指标前先达成共识：&lt;/p&gt;
&lt;h3 id="11-北极星分层"&gt;1.1 北极星分层&lt;/h3&gt;
&lt;pre class="mermaid"&gt;graph TB
L0[用户体验北极星&lt;br/&gt;留存率 / NPS]
L1[业务指标&lt;br/&gt;秒开率 / 转化率 / 关键路径完成率]
L2[技术指标&lt;br/&gt;FPS / Crash率 / 启动时间]
L3[原子指标&lt;br/&gt;单帧耗时 / 内存峰值 / 单请求耗时]
L0 --&gt; L1 --&gt; L2 --&gt; L3
&lt;/pre&gt;
&lt;p&gt;好的指标体系应该：&lt;strong&gt;技术指标能解释业务指标，业务指标能解释北极星&lt;/strong&gt;。否则就是&amp;quot;为了采集而采集&amp;quot;。&lt;/p&gt;
&lt;h3 id="12-分位数思维"&gt;1.2 分位数思维&lt;/h3&gt;
&lt;p&gt;&lt;strong&gt;永远不要只看平均值&lt;/strong&gt;。同一个启动指标：&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;设备&lt;/th&gt;
&lt;th&gt;平均&lt;/th&gt;
&lt;th&gt;P50&lt;/th&gt;
&lt;th&gt;P90&lt;/th&gt;
&lt;th&gt;P99&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;iPhone 15&lt;/td&gt;
&lt;td&gt;800ms&lt;/td&gt;
&lt;td&gt;750ms&lt;/td&gt;
&lt;td&gt;900ms&lt;/td&gt;
&lt;td&gt;1200ms&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;iPhone SE 2&lt;/td&gt;
&lt;td&gt;2000ms&lt;/td&gt;
&lt;td&gt;1500ms&lt;/td&gt;
&lt;td&gt;3500ms&lt;/td&gt;
&lt;td&gt;8000ms&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;平均值把两者拉成 1400ms，但 iPhone SE 的 P99 用户&amp;quot;实际等了 8 秒&amp;quot;。APM 的所有耗时指标都必须同时提供 P50 / P90 / P99。&lt;/p&gt;</description></item><item><title>iOS国际化</title><link>https://amatsuzero.github.io/LastStand/posts/interview/ios-advanced/ios%E5%9B%BD%E9%99%85%E5%8C%96/</link><pubDate>Sat, 02 May 2026 22:32:27 +0800</pubDate><guid>https://amatsuzero.github.io/LastStand/posts/interview/ios-advanced/ios%E5%9B%BD%E9%99%85%E5%8C%96/</guid><description>&lt;h2 id="前言"&gt;前言&lt;/h2&gt;
&lt;p&gt;很多团队对&amp;quot;国际化&amp;quot;的理解停留在&amp;quot;把中文文案翻译成英文&amp;quot;，等真正把 App 推向多区域时就会发现远远不够：阿拉伯语用户看到的界面左右颠倒了，用户在纽约和东京看到的&amp;quot;今天&amp;quot;不是同一天，欧洲的小数点变成了逗号，日本用户抱怨价格里的¥符号指向人民币而不是日元，印度用户发现自己的 ₹1,23,456.78 被错误地按千分位显示成 ₹123,456.78，复数规则在俄语里比英语复杂得多，而这些问题单靠&amp;quot;翻译&amp;quot;都解决不了。&lt;/p&gt;
&lt;p&gt;国际化（Internationalization，简称 i18n，取首末字母与中间 18 个字符）是&lt;strong&gt;架构层面的能力建设&lt;/strong&gt;，让 App 能够适配不同语言、地区、文字方向、日历、时区、货币、单位制与文化习俗；而本地化（Localization，l10n）是针对某个具体地区的&amp;quot;适配落地&amp;quot;。两者的关系是：&amp;ldquo;国际化一次，本地化 N 次&amp;rdquo;。&lt;/p&gt;
&lt;p&gt;本文从 &lt;code&gt;NSLocale&lt;/code&gt;/&lt;code&gt;Locale&lt;/code&gt; 的基础模型开始，把 iOS 国际化的完整工程面梳理清楚——文案本地化、复数/性别规则、RTL 布局、多时区、多币种、单位与数字格式、图片资源、字体、App 内切换语言、测试方法，最后给出研发规范与排查清单。&lt;/p&gt;
&lt;h2 id="一基础概念localelanguage-与-region"&gt;一、基础概念：Locale、Language 与 Region&lt;/h2&gt;
&lt;h3 id="11-locale-不等于-language"&gt;1.1 Locale 不等于 Language&lt;/h3&gt;
&lt;p&gt;大多数工程师第一次接触国际化时会把&amp;quot;语言&amp;quot;和&amp;quot;地区&amp;quot;混为一谈，这在 iOS 下会直接导致格式错误。&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Language（语言）&lt;/strong&gt;：&lt;code&gt;zh&lt;/code&gt;、&lt;code&gt;en&lt;/code&gt;、&lt;code&gt;ar&lt;/code&gt;、&lt;code&gt;ja&lt;/code&gt;…决定 UI 文字内容。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Region（地区）&lt;/strong&gt;：&lt;code&gt;CN&lt;/code&gt;、&lt;code&gt;US&lt;/code&gt;、&lt;code&gt;SA&lt;/code&gt;、&lt;code&gt;JP&lt;/code&gt;…决定格式（日期、数字、货币、时间制 12/24h、起始星期、度量单位）。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Locale（语言+地区）&lt;/strong&gt;：两者合成一个完整的标识，如 &lt;code&gt;zh_CN&lt;/code&gt;、&lt;code&gt;en_US&lt;/code&gt;、&lt;code&gt;ar_SA&lt;/code&gt;、&lt;code&gt;en_IN&lt;/code&gt;。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;一个美国人移居日本后，完全可能把 iPhone 语言设为英文，但地区设为日本。此时：&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;场景&lt;/th&gt;
&lt;th&gt;期望&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;UI 文案&lt;/td&gt;
&lt;td&gt;英文&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;日期格式&lt;/td&gt;
&lt;td&gt;&lt;code&gt;1月23日(月)&lt;/code&gt; 风格？No，应显示 &lt;code&gt;January 23 (Mon)&lt;/code&gt;，因为语言决定月/星期的&lt;strong&gt;名字&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;数字分隔符&lt;/td&gt;
&lt;td&gt;&lt;code&gt;,&lt;/code&gt; 作千分位（与日本/美国一致）&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;货币符号&lt;/td&gt;
&lt;td&gt;&lt;code&gt;¥&lt;/code&gt;（JPY）&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;温度单位&lt;/td&gt;
&lt;td&gt;&lt;code&gt;℃&lt;/code&gt;（日本）&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;首日周&lt;/td&gt;
&lt;td&gt;周日（日本区域）&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;对应的 &lt;code&gt;Locale&lt;/code&gt; 是 &lt;code&gt;en_JP&lt;/code&gt;——看似奇怪，但在现实中非常普遍。代码里要区分&amp;quot;用哪个语言去查字符串&amp;quot;和&amp;quot;用哪个 Locale 去格式化数据&amp;quot;：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-swift" data-lang="swift"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;let&lt;/span&gt; preferredLanguage = Locale.preferredLanguages.first ?? &lt;span style="color:#e6db74"&gt;&amp;#34;en&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;let&lt;/span&gt; currentLocale = Locale.current
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;let&lt;/span&gt; formatter = DateFormatter()
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;formatter.locale = currentLocale
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;formatter.dateStyle = .long
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;print(formatter.string(from: Date()))
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;不要传 &lt;code&gt;Locale(identifier: &amp;quot;en&amp;quot;)&lt;/code&gt; 去格式化数字，那会丢掉用户的区域偏好。&lt;/p&gt;</description></item><item><title>KVO底层原理</title><link>https://amatsuzero.github.io/LastStand/posts/interview/ios-basics/kvo%E5%BA%95%E5%B1%82%E5%8E%9F%E7%90%86/</link><pubDate>Sat, 02 May 2026 22:32:27 +0800</pubDate><guid>https://amatsuzero.github.io/LastStand/posts/interview/ios-basics/kvo%E5%BA%95%E5%B1%82%E5%8E%9F%E7%90%86/</guid><description>&lt;h2 id="基础概念"&gt;基础概念&lt;/h2&gt;
&lt;p&gt;KVO（Key-Value Observing，键值观察）是 Apple 基于 KVC 实现的一种观察者模式，允许对象监听另一个对象特定属性的变化。当被观察对象的属性值发生改变时，观察者会收到通知。&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-objc" data-lang="objc"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;// 注册观察
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;[person addObserver:self
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; forKeyPath:&lt;span style="color:#e6db74"&gt;@&amp;#34;name&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; options:NSKeyValueObservingOptionNew &lt;span style="color:#f92672"&gt;|&lt;/span&gt; NSKeyValueObservingOptionOld
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; context:nil];
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;// 接收通知
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;- (&lt;span style="color:#66d9ef"&gt;void&lt;/span&gt;)&lt;span style="color:#a6e22e"&gt;observeValueForKeyPath:&lt;/span&gt;(NSString &lt;span style="color:#f92672"&gt;*&lt;/span&gt;)keyPath
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;ofObject:&lt;/span&gt;(&lt;span style="color:#66d9ef"&gt;id&lt;/span&gt;)object
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;change:&lt;/span&gt;(NSDictionary&lt;span style="color:#f92672"&gt;&amp;lt;&lt;/span&gt;NSKeyValueChangeKey, &lt;span style="color:#66d9ef"&gt;id&lt;/span&gt;&lt;span style="color:#f92672"&gt;&amp;gt;&lt;/span&gt; &lt;span style="color:#f92672"&gt;*&lt;/span&gt;)change
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;context:&lt;/span&gt;(&lt;span style="color:#66d9ef"&gt;void&lt;/span&gt; &lt;span style="color:#f92672"&gt;*&lt;/span&gt;)context {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;if&lt;/span&gt; ([keyPath isEqualToString:&lt;span style="color:#e6db74"&gt;@&amp;#34;name&amp;#34;&lt;/span&gt;]) {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; NSLog(&lt;span style="color:#e6db74"&gt;@&amp;#34;name changed: %@ → %@&amp;#34;&lt;/span&gt;, change[NSKeyValueChangeOldKey], change[NSKeyValueChangeNewKey]);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; }
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;// 移除观察
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;- (&lt;span style="color:#66d9ef"&gt;void&lt;/span&gt;)&lt;span style="color:#a6e22e"&gt;dealloc&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; [person removeObserver:self forKeyPath:&lt;span style="color:#e6db74"&gt;@&amp;#34;name&amp;#34;&lt;/span&gt;];
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h2 id="kvo-的底层实现原理isa-swizzling"&gt;KVO 的底层实现原理：isa-swizzling&lt;/h2&gt;
&lt;p&gt;KVO 的核心实现机制是 &lt;strong&gt;isa-swizzling&lt;/strong&gt;（isa 指针替换）。当对象被添加观察者时，Runtime 会在运行时动态创建该对象所属类的一个子类，并将对象的 isa 指针指向这个新的子类。&lt;/p&gt;
&lt;h3 id="完整流程"&gt;完整流程&lt;/h3&gt;
&lt;pre class="mermaid"&gt;flowchart TD
A["addObserver:forKeyPath:"] --&gt; B["Runtime 动态创建子类&lt;br/&gt;NSKVONotifying_ClassName"]
B --&gt; C["重写被观察属性的 setter 方法"]
B --&gt; D["重写 class 方法&lt;br/&gt;返回原始类"]
B --&gt; E["重写 dealloc 方法"]
B --&gt; F["重写 _isKVOA 方法&lt;br/&gt;返回 YES"]
C --&gt; G["将对象的 isa 指向&lt;br/&gt;NSKVONotifying_ClassName"]
G --&gt; H["当属性值改变时"]
H --&gt; I["调用 willChangeValueForKey:"]
I --&gt; J["调用原始 setter 方法"]
J --&gt; K["调用 didChangeValueForKey:"]
K --&gt; L["通知所有观察者"]
&lt;/pre&gt;
&lt;h3 id="第一步动态创建子类"&gt;第一步：动态创建子类&lt;/h3&gt;
&lt;p&gt;当首次对某个类的实例调用 &lt;code&gt;addObserver:forKeyPath:options:context:&lt;/code&gt; 时，Runtime 会：&lt;/p&gt;</description></item><item><title>RxSwift源码导读</title><link>https://amatsuzero.github.io/LastStand/posts/interview/ios-source-analysis/rxswift%E6%BA%90%E7%A0%81%E5%AF%BC%E8%AF%BB/</link><pubDate>Sat, 02 May 2026 22:32:27 +0800</pubDate><guid>https://amatsuzero.github.io/LastStand/posts/interview/ios-source-analysis/rxswift%E6%BA%90%E7%A0%81%E5%AF%BC%E8%AF%BB/</guid><description>&lt;p&gt;RxSwift 是 ReactiveX 在 Swift 上的实现，提供了一套完整的响应式编程框架。它通过 Observable 序列和操作符组合的方式，简化了异步编程、事件处理和数据流管理。本文基于 &lt;strong&gt;v6.10.2&lt;/strong&gt;（2026年3月发布）源码进行分析。&lt;/p&gt;
&lt;hr&gt;
&lt;h2 id="一整体架构"&gt;一、整体架构&lt;/h2&gt;
&lt;p&gt;RxSwift 项目采用模块化设计，包含五个独立模块：&lt;/p&gt;
&lt;pre class="mermaid"&gt;graph TB
subgraph "核心层"
A["RxSwift&lt;br/&gt;核心响应式框架"]
end
subgraph "扩展层"
B["RxCocoa&lt;br/&gt;UIKit/AppKit绑定"]
C["RxRelay&lt;br/&gt;Relay封装"]
end
subgraph "工具层"
D["RxBlocking&lt;br/&gt;阻塞操作"]
E["RxTest&lt;br/&gt;测试工具"]
end
B --&gt; A
C --&gt; A
D --&gt; A
E --&gt; A
&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;源码目录结构：&lt;/strong&gt;&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-fallback" data-lang="fallback"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;RxSwift/
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;├── Concurrency/ # 并发工具（AsyncLock等）
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;├── Disposables/ # 资源释放（DisposeBag、CompositeDisposable等）
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;├── Extensions/ # Swift扩展
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;├── Observables/ # Observable实现（Create、Map、Filter、Merge等）
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;├── Observers/ # Observer实现（AnonymousObserver、ObserverBase等）
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;├── Platform/ # 平台适配（原子操作、锁等）
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;├── Schedulers/ # 调度器（MainScheduler、SerialDispatchQueueScheduler等）
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;├── Subjects/ # Subject实现（PublishSubject、BehaviorSubject等）
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;├── SwiftSupport/ # Swift语言支持
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;├── Traits/ # 特化序列（Single、Completable、Maybe、Infallible）
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;├── Observable.swift # Observable基类
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;├── ObservableType.swift # Observable协议
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;├── ObserverType.swift # Observer协议
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;├── Event.swift # 事件枚举
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;├── Disposable.swift # Disposable协议
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;├── Binder.swift # UI绑定
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;├── AnyObserver.swift # 类型擦除Observer
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;└── Reactive.swift # .rx命名空间
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;&lt;strong&gt;语言构成：&lt;/strong&gt; 纯 Swift 实现，100% Swift 代码。&lt;/p&gt;</description></item><item><title>TCA（The Composable Architecture）详解</title><link>https://amatsuzero.github.io/LastStand/posts/interview/ios-architecture/tca/</link><pubDate>Sat, 02 May 2026 22:32:27 +0800</pubDate><guid>https://amatsuzero.github.io/LastStand/posts/interview/ios-architecture/tca/</guid><description>&lt;h2 id="什么是tca"&gt;什么是TCA&lt;/h2&gt;
&lt;p&gt;TCA（The Composable Architecture）是由&lt;a href="https://www.pointfree.co"&gt;Point-Free&lt;/a&gt;团队开发的Swift架构框架，受&lt;a href="https://elm-lang.org"&gt;Elm&lt;/a&gt;和&lt;a href="https://redux.js.org/"&gt;Redux&lt;/a&gt;启发，为Apple平台提供了一套完整的应用构建工具，涵盖状态管理、副作用处理、模块化组合以及测试支持。&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;GitHub仓库&lt;/strong&gt;：&lt;a href="https://github.com/pointfreeco/swift-composable-architecture"&gt;swift-composable-architecture&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;适用平台&lt;/strong&gt;：iOS、macOS、iPadOS、visionOS、tvOS、watchOS&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;适用UI框架&lt;/strong&gt;：SwiftUI、UIKit&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;TCA的核心理念是：将应用状态、变更动作、副作用和依赖显式化，构建可组合、可测试的&lt;strong&gt;单向数据流&lt;/strong&gt;架构。整体架构与Swift的语言特性（值语义、async/await、Observation、SwiftUI）紧密结合，强调小而纯的Reducer组合与明确的副作用管理。&lt;/p&gt;
&lt;h3 id="为什么需要tca"&gt;为什么需要TCA&lt;/h3&gt;
&lt;p&gt;在日常iOS开发中，TCA解决了以下核心问题：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;状态管理&lt;/strong&gt;：使用简单的值类型管理应用状态，支持在多个屏幕间共享状态，使一个屏幕的修改能立即反映到另一个屏幕&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;组合性&lt;/strong&gt;：将大型功能拆分成可独立开发、独立测试的小组件，提取到独立模块后可轻松组合回完整功能&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;副作用处理&lt;/strong&gt;：以最可测试和可理解的方式让应用的某些部分与外部世界通信&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;测试能力&lt;/strong&gt;：不仅能测试单个功能，还能编写由多个部分组成的功能的集成测试，以及端到端测试来验证副作用如何影响应用&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;人机工程学&lt;/strong&gt;：用尽可能少的概念和组成部分，通过简单的API实现以上所有目标&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id="tca的架构渊源"&gt;TCA的架构渊源&lt;/h3&gt;
&lt;p&gt;TCA的设计灵感主要来自Elm Architecture和Redux，同时与&lt;a href="https://amatsuzero.github.io/LastStand/posts/interview/ios-architecture/mvi/"&gt;MVI架构&lt;/a&gt;思想有诸多相似之处，但在Swift生态中进行了大量增强：&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;特性&lt;/th&gt;
&lt;th&gt;Elm/Redux/MVI&lt;/th&gt;
&lt;th&gt;TCA&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;核心思想&lt;/td&gt;
&lt;td&gt;Action -&amp;gt; State -&amp;gt; View 单向数据流&lt;/td&gt;
&lt;td&gt;同样的单向数据流，但深度融合Swift特性&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;副作用处理&lt;/td&gt;
&lt;td&gt;自定义Middleware或自行实现&lt;/td&gt;
&lt;td&gt;内置Effect系统（基于async/await）&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;依赖注入&lt;/td&gt;
&lt;td&gt;需手动实现&lt;/td&gt;
&lt;td&gt;内置@Dependency系统&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;测试支持&lt;/td&gt;
&lt;td&gt;需自己构建&lt;/td&gt;
&lt;td&gt;提供TestStore，支持穷尽式断言&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;组合能力&lt;/td&gt;
&lt;td&gt;基础支持&lt;/td&gt;
&lt;td&gt;Scope、forEach等丰富的Reducer组合手段&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;导航管理&lt;/td&gt;
&lt;td&gt;需自己实现&lt;/td&gt;
&lt;td&gt;内置状态化导航系统&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;状态共享&lt;/td&gt;
&lt;td&gt;需自己实现&lt;/td&gt;
&lt;td&gt;内置@Shared系统&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;h2 id="tca的核心概念"&gt;TCA的核心概念&lt;/h2&gt;
&lt;p&gt;TCA包含以下核心概念：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Feature&lt;/strong&gt;：一个功能模块的整体单元，由&lt;code&gt;@Reducer&lt;/code&gt;标注，内含State、Action和Reducer&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;State&lt;/strong&gt;：描述功能所需的数据&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Action&lt;/strong&gt;：功能中可能发生的所有事件&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Reducer&lt;/strong&gt;：接收State和Action，更新State并产生副作用（Effect）&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Store&lt;/strong&gt;：持有State、驱动Reducer执行的运行时&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Scope&lt;/strong&gt;：从父Store中切出子Store，实现Feature的模块化组合&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Effect&lt;/strong&gt;：封装异步操作的副作用&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Dependency&lt;/strong&gt;：可替换的外部依赖&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;它们之间的协作关系如下：&lt;/p&gt;
&lt;pre class="mermaid"&gt;flowchart LR
View --&gt;|"send(Action)"| Store
Store --&gt;|"传递 State + Action"| Reducer
Reducer --&gt;|"更新后的 State"| Store
Reducer --&gt;|"返回 Effect"| Store
Store --&gt;|"State 变化驱动"| View
Store -.-&gt;|"scope"| ChildStore["子Store"]
&lt;/pre&gt;
&lt;h3 id="state状态"&gt;State（状态）&lt;/h3&gt;
&lt;p&gt;State是描述功能模块在某一时刻全部数据的值类型结构体：&lt;/p&gt;</description></item><item><title>启动优化-load方法</title><link>https://amatsuzero.github.io/LastStand/posts/interview/ios-performance/launch-load%E6%96%B9%E6%B3%95/</link><pubDate>Sat, 02 May 2026 22:32:27 +0800</pubDate><guid>https://amatsuzero.github.io/LastStand/posts/interview/ios-performance/launch-load%E6%96%B9%E6%B3%95/</guid><description>&lt;p&gt;&lt;code&gt;+load&lt;/code&gt;方法是ObjC运行时在类被加载时自动调用的方法，所有&lt;code&gt;+load&lt;/code&gt;方法在main函数之前同步执行，会阻塞启动。&lt;/p&gt;
&lt;hr&gt;
&lt;h2 id="问题分析"&gt;问题分析&lt;/h2&gt;
&lt;p&gt;&lt;code&gt;+load&lt;/code&gt;方法的特点：&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;特性&lt;/th&gt;
&lt;th&gt;说明&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;调用时机&lt;/td&gt;
&lt;td&gt;main函数之前，ObjC Runtime初始化时&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;调用顺序&lt;/td&gt;
&lt;td&gt;父类 → 子类 → Category&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;线程&lt;/td&gt;
&lt;td&gt;主线程，同步执行&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;影响&lt;/td&gt;
&lt;td&gt;直接阻塞启动&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-objc" data-lang="objc"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;// 问题代码：+load中执行耗时操作
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;@implementation&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;HeavyModule&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;+ (&lt;span style="color:#66d9ef"&gt;void&lt;/span&gt;)&lt;span style="color:#a6e22e"&gt;load&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#75715e"&gt;// 耗时操作会阻塞启动
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; [self setupDatabase];
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; [self preloadResources];
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; [self registerServices];
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;@end&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;hr&gt;
&lt;h2 id="load与initialize的区别"&gt;+load与+initialize的区别&lt;/h2&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;特性&lt;/th&gt;
&lt;th&gt;+load&lt;/th&gt;
&lt;th&gt;+initialize&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;调用时机&lt;/td&gt;
&lt;td&gt;main之前&lt;/td&gt;
&lt;td&gt;类首次使用时&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;调用次数&lt;/td&gt;
&lt;td&gt;只调用一次&lt;/td&gt;
&lt;td&gt;可能多次（子类触发）&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;是否阻塞启动&lt;/td&gt;
&lt;td&gt;是&lt;/td&gt;
&lt;td&gt;否&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;线程安全&lt;/td&gt;
&lt;td&gt;是&lt;/td&gt;
&lt;td&gt;是&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;调用顺序&lt;/td&gt;
&lt;td&gt;父类→子类→Category&lt;/td&gt;
&lt;td&gt;父类→子类&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;blockquote&gt;
&lt;p&gt;更详细的对比请参考：&lt;a href="https://amatsuzero.github.io/LastStand/posts/interview/ios-basics/load%E4%B8%8Einitialize%E7%9A%84%E5%8C%BA%E5%88%AB/"&gt;+load与+initialize的区别&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;hr&gt;
&lt;h2 id="优化方案"&gt;优化方案&lt;/h2&gt;
&lt;h3 id="方案1使用initialize替代"&gt;方案1：使用+initialize替代&lt;/h3&gt;
&lt;p&gt;将&lt;code&gt;+load&lt;/code&gt;中的逻辑迁移到&lt;code&gt;+initialize&lt;/code&gt;，延迟到类首次使用时执行：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-objc" data-lang="objc"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;@implementation&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;HeavyModule&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;// 优化前
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;+ (&lt;span style="color:#66d9ef"&gt;void&lt;/span&gt;)&lt;span style="color:#a6e22e"&gt;load&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; [self setupDatabase];
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;// 优化后
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;+ (&lt;span style="color:#66d9ef"&gt;void&lt;/span&gt;)&lt;span style="color:#a6e22e"&gt;initialize&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;static&lt;/span&gt; dispatch_once_t onceToken;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; dispatch_once(&lt;span style="color:#f92672"&gt;&amp;amp;&lt;/span&gt;onceToken, &lt;span style="color:#f92672"&gt;^&lt;/span&gt;{
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#75715e"&gt;// 延迟到类首次使用时执行
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; [self setupDatabase];
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; });
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;@end&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;注意&lt;/strong&gt;：&lt;code&gt;+initialize&lt;/code&gt;可能被子类触发多次调用，需要使用&lt;code&gt;dispatch_once&lt;/code&gt;保证只执行一次。&lt;/p&gt;</description></item><item><title>编译优化-Xcode构建系统</title><link>https://amatsuzero.github.io/LastStand/posts/interview/ios-build/xcode%E6%9E%84%E5%BB%BA%E7%B3%BB%E7%BB%9F/</link><pubDate>Sat, 02 May 2026 22:32:27 +0800</pubDate><guid>https://amatsuzero.github.io/LastStand/posts/interview/ios-build/xcode%E6%9E%84%E5%BB%BA%E7%B3%BB%E7%BB%9F/</guid><description>&lt;p&gt;Xcode 的构建系统由多个组件协同完成，从 &lt;code&gt;Cmd+B&lt;/code&gt; 到生成 &lt;code&gt;.app&lt;/code&gt; 经历了完整的任务图构建、依赖分析、并行调度流程。理解这套体系是后续一切优化的基础。&lt;/p&gt;
&lt;hr&gt;
&lt;h2 id="构建系统组成"&gt;构建系统组成&lt;/h2&gt;
&lt;p&gt;Xcode 10 之后默认采用 &lt;strong&gt;Swift Build System&lt;/strong&gt;（基于 llbuild），整体架构如下：&lt;/p&gt;
&lt;pre class="mermaid"&gt;flowchart TD
A[Xcode IDE] --&gt; B[XCBBuildService&lt;br/&gt;Daemon]
B --&gt; C[Build Description&lt;br/&gt;任务图 JSON]
C --&gt; D[llbuild&lt;br/&gt;调度内核]
D --&gt; E1[Swift Driver / swiftc]
D --&gt; E2[clang]
D --&gt; E3[ld / ld-prime]
D --&gt; E4[actool / ibtool / 脚本]
E1 &amp; E2 &amp; E3 &amp; E4 --&gt; F[产物缓存]
&lt;/pre&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;组件&lt;/th&gt;
&lt;th&gt;职责&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;XCBBuildService&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;独立进程，为 Xcode / xcodebuild 提供构建 RPC 服务&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Build Description&lt;/td&gt;
&lt;td&gt;根据 Scheme、Target、Build Settings 生成的任务图&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;llbuild&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;通用构建引擎，执行任务图、做增量与并行调度&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;swift-driver&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Swift 编译驱动，生成 frontend job 并驱动 swiftc&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;clang&lt;/code&gt; / &lt;code&gt;swift-frontend&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;真正的编译器前端&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;ld&lt;/code&gt; / &lt;code&gt;ld-prime&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;链接器&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;h3 id="xcbbuildservice"&gt;XCBBuildService&lt;/h3&gt;
&lt;p&gt;Xcode 和 &lt;code&gt;xcodebuild&lt;/code&gt; 都是&lt;strong&gt;客户端&lt;/strong&gt;，真正的构建逻辑在 &lt;code&gt;XCBBuildService&lt;/code&gt; 这个独立进程。它通过 XPC 接收请求，生成并执行任务。社区工具 &lt;a href="https://github.com/target/XCBBuildServiceProxy"&gt;&lt;code&gt;XCBBuildServiceProxy&lt;/code&gt;&lt;/a&gt; 利用这一架构在中间插一层代理，实现自定义构建（Bazel、远程执行等）。字节 &lt;code&gt;BitSky&lt;/code&gt;、Tuist Cloud 都基于此类模式。&lt;/p&gt;</description></item><item><title>+initialize 懒初始化与并发状态机</title><link>https://amatsuzero.github.io/LastStand/posts/ocsourcecodeanalysis/initialize-method-explained/</link><pubDate>Mon, 01 Jun 2026 19:50:12 +0800</pubDate><guid>https://amatsuzero.github.io/LastStand/posts/ocsourcecodeanalysis/initialize-method-explained/</guid><description>&lt;p&gt;objc4 runtime 懒初始化 并发等待 fork safety&lt;/p&gt;
&lt;h1 id="initialize-懒初始化与并发状态机"&gt;+initialize 懒初始化与并发状态机&lt;/h1&gt;
&lt;p&gt;&lt;code&gt;+initialize&lt;/code&gt; 是 Objective-C 运行时在类第一次被真正使用时触发的类级初始化钩子。 objc4 的实现重点不是“调用一个方法”，而是用每个类的递归初始化锁、元类上的状态位、线程本地的初始化列表和 fork 子进程保护规则，保证父类优先、单线程执行、并发可等待、重入不死锁。&lt;/p&gt;
&lt;h2 id="目录"&gt;目录&lt;/h2&gt;
&lt;ol&gt;
&lt;li&gt;&lt;a href="#purpose"&gt;作用&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="#principle"&gt;实现原理&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="#state"&gt;核心状态字段&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="#entry"&gt;入口与触发&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="#machine"&gt;并发状态机&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="#flows"&gt;关键流程&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="#tests"&gt;测试依据&lt;/a&gt;&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;&lt;a id="purpose"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;h2 id="作用"&gt;作用&lt;/h2&gt;
&lt;p&gt;&lt;code&gt;+initialize&lt;/code&gt; 的语义是：在某个类或其子类第一次收到会触发初始化的消息前，运行时先给该类发送一次 &lt;code&gt;+initialize&lt;/code&gt;。 这让类可以延迟建立全局状态、注册方法、准备缓存或执行只依赖本类的初始化逻辑。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;懒触发&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;&lt;code&gt;objc_getClass()&lt;/code&gt; 只查找类，不触发初始化；普通消息发送、部分运行时查询、autorelease 返回值路径和弱引用相关路径可能需要先完成初始化。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;父类优先&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;子类开始初始化前，运行时递归确保父类已经初始化，避免类层次中间被并发线程插入造成死锁。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;一次完成&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;同一类只有一个线程真正发送 &lt;code&gt;+initialize&lt;/code&gt;；其他线程要么等待，要么在同一初始化线程重入时直接放行。&lt;/p&gt;
&lt;p&gt;&lt;a id="principle"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;h2 id="实现原理"&gt;实现原理&lt;/h2&gt;
&lt;p&gt;objc4 把 &lt;code&gt;+initialize&lt;/code&gt; 做成一个按需进入的并发状态机：消息查找路径发现目标类未初始化时，先把类 realize，再释放 &lt;code&gt;runtimeLock&lt;/code&gt;，进入 &lt;code&gt;initializeNonMetaClass()&lt;/code&gt;。 后者用父类递归、每类递归锁、元类状态位和线程本地初始化列表协调所有线程。真正执行用户代码的线程设置 &lt;code&gt;INITIALIZING&lt;/code&gt;，发送 &lt;code&gt;+initialize&lt;/code&gt;，最后在 &lt;code&gt;@finally&lt;/code&gt; 中切换到 &lt;code&gt;INITIALIZED&lt;/code&gt;；其他线程通过同一把类锁等待状态稳定。&lt;/p&gt;
&lt;p&gt;这个设计的核心约束是单调性：类状态只从“未初始化”前进到“初始化中”，再前进到“已初始化”。即使 &lt;code&gt;+initialize&lt;/code&gt; 抛异常，状态机也会完成收尾；即使发生重入，只有当前初始化线程能绕过等待；即使 fork 发生在多线程初始化期间，子进程也只允许 trivial 初始化继续，其他自定义初始化会主动终止。&lt;/p&gt;
&lt;p&gt;&lt;a id="state"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;h2 id="核心类结构状态字段"&gt;核心类/结构状态字段&lt;/h2&gt;
&lt;p&gt;初始化状态存在类对象的元类标志位里。源码注释明确约束：初始时 &lt;code&gt;RW_INITIALIZING&lt;/code&gt; 和 &lt;code&gt;RW_INITIALIZED&lt;/code&gt; 都未设置；初始化中只设置前者；完成后清除前者并设置后者；两者永不同时为真，且 &lt;code&gt;RW_INITIALIZED&lt;/code&gt; 一旦设置就不会清除。&lt;/p&gt;</description></item><item><title>启动优化-二进制重排</title><link>https://amatsuzero.github.io/LastStand/posts/interview/ios-performance/launch-%E4%BA%8C%E8%BF%9B%E5%88%B6%E9%87%8D%E6%8E%92/</link><pubDate>Fri, 08 May 2026 22:56:38 +0800</pubDate><guid>https://amatsuzero.github.io/LastStand/posts/interview/ios-performance/launch-%E4%BA%8C%E8%BF%9B%E5%88%B6%E9%87%8D%E6%8E%92/</guid><description>&lt;p&gt;二进制重排是一种通过重新排列二进制文件中函数顺序来减少启动时Page Fault的优化技术。&lt;/p&gt;
&lt;hr&gt;
&lt;h2 id="基本原理"&gt;基本原理&lt;/h2&gt;
&lt;h3 id="page-fault问题"&gt;Page Fault问题&lt;/h3&gt;
&lt;p&gt;iOS使用虚拟内存管理，讨论Page Fault时需要先区分两层“内存”：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;虚拟地址空间&lt;/strong&gt;：进程看到的是一段连续的虚拟地址。App启动时，dyld会把Mach-O的&lt;code&gt;__TEXT&lt;/code&gt;、&lt;code&gt;__DATA&lt;/code&gt;等段映射到进程的虚拟地址空间里。这里的“映射”只是建立虚拟地址和文件偏移的关系，不代表整段二进制代码已经全部进入物理内存。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;物理内存&lt;/strong&gt;：CPU真正执行代码时，需要对应虚拟页背后有可用的物理页。代码页通常是文件映射页，第一次访问某个尚未驻留在物理内存中的代码页时，会触发Page Fault。内核再从App二进制文件中读取这个页的内容，填充到物理页，并更新页表。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;所以，更准确地说：程序代码按页映射到虚拟地址空间；启动过程中实际执行到某个函数时，才会按需把该函数所在的代码页调入物理内存。Page Fault本身不是异常崩溃，而是虚拟内存按需调页的正常机制，只是冷启动时如果触发太多文件读取，会增加启动耗时。&lt;/p&gt;
&lt;p&gt;默认情况下，编译器按照链接顺序排列函数，导致启动时调用的函数可能分散在不同的代码页中：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-plaintext" data-lang="plaintext"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;优化前（启动函数分散在不同代码页）：
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;┌────────┐ ┌────────┐ ┌────────┐ ┌────────┐
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;│ Page 1 │ │ Page 2 │ │ Page 3 │ │ Page 4 │
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;│ func_A │ │ func_X │ │ func_B │ │ func_C │
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;│ ... │ │ ... │ │ ... │ │ ... │
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;└────────┘ └────────┘ └────────┘ └────────┘
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;启动调用 A→B→C 会触达 Page 1, 3, 4。
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;如果这些代码页还没有驻留在物理内存中，就可能产生3次Page Fault。
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h3 id="二进制重排的效果"&gt;二进制重排的效果&lt;/h3&gt;
&lt;p&gt;通过重排，将启动时调用的函数集中排列在相邻的代码页中：&lt;/p&gt;</description></item><item><title>APM-数据模型与上报</title><link>https://amatsuzero.github.io/LastStand/posts/interview/ios-apm/%E6%95%B0%E6%8D%AE%E6%A8%A1%E5%9E%8B%E4%B8%8E%E4%B8%8A%E6%8A%A5/</link><pubDate>Thu, 07 May 2026 15:42:48 +0800</pubDate><guid>https://amatsuzero.github.io/LastStand/posts/interview/ios-apm/%E6%95%B0%E6%8D%AE%E6%A8%A1%E5%9E%8B%E4%B8%8E%E4%B8%8A%E6%8A%A5/</guid><description>&lt;p&gt;APM 的上报系统不只是“把 JSON 发到服务端”。它要解决三件事：&lt;strong&gt;数据如何建模、事件如何关联、移动端如何可靠且低成本地上传&lt;/strong&gt;。这一层设计不好，后面的服务端聚合、B 端下钻和告警都会变成补丁工程。&lt;/p&gt;
&lt;hr&gt;
&lt;h2 id="一设计目标"&gt;一、设计目标&lt;/h2&gt;
&lt;p&gt;数据模型与上报层要同时满足：&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;目标&lt;/th&gt;
&lt;th&gt;说明&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;可关联&lt;/td&gt;
&lt;td&gt;页面、操作、网络、错误、性能现场能被 Session 串起来&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;可聚合&lt;/td&gt;
&lt;td&gt;同类问题能按 fingerprint、版本、机型、页面、接口聚合&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;可重试&lt;/td&gt;
&lt;td&gt;弱网、后台、进程退出后数据不轻易丢&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;可去重&lt;/td&gt;
&lt;td&gt;重试不会造成重复统计&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;可采样&lt;/td&gt;
&lt;td&gt;高频数据不会压垮端侧、网络和服务端&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;可脱敏&lt;/td&gt;
&lt;td&gt;敏感数据在端侧就被过滤或掩码&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;可演进&lt;/td&gt;
&lt;td&gt;Schema 版本升级后新旧 SDK 可以共存&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;hr&gt;
&lt;h2 id="二rum-对象模型"&gt;二、RUM 对象模型&lt;/h2&gt;
&lt;p&gt;推荐用 RUM 层级组织端侧事件：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-text" data-lang="text"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;Session
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; View
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; Action
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; Resource
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; Error
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; LongTask / Freeze
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; Custom Event
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;对象&lt;/th&gt;
&lt;th&gt;含义&lt;/th&gt;
&lt;th&gt;示例&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Session&lt;/td&gt;
&lt;td&gt;一次用户前台使用会话&lt;/td&gt;
&lt;td&gt;打开 App 到退后台&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;View&lt;/td&gt;
&lt;td&gt;一个页面实例&lt;/td&gt;
&lt;td&gt;首页、详情页、支付页&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Action&lt;/td&gt;
&lt;td&gt;一次用户操作&lt;/td&gt;
&lt;td&gt;点击下单、搜索、提交表单&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Resource&lt;/td&gt;
&lt;td&gt;一次资源请求&lt;/td&gt;
&lt;td&gt;HTTP 请求、图片资源、WebView 资源&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Error&lt;/td&gt;
&lt;td&gt;一次错误&lt;/td&gt;
&lt;td&gt;Crash、业务错误、网络错误、JS 错误&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;LongTask / Freeze&lt;/td&gt;
&lt;td&gt;一次长任务或卡顿&lt;/td&gt;
&lt;td&gt;主线程阻塞 800ms&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;RUM 模型的价值是把“点状指标”变成“用户故事”：&lt;/p&gt;</description></item><item><title>iOS无障碍树详解</title><link>https://amatsuzero.github.io/LastStand/posts/interview/ios-advanced/ios%E6%97%A0%E9%9A%9C%E7%A2%8D%E6%A0%91/</link><pubDate>Sat, 02 May 2026 22:32:27 +0800</pubDate><guid>https://amatsuzero.github.io/LastStand/posts/interview/ios-advanced/ios%E6%97%A0%E9%9A%9C%E7%A2%8D%E6%A0%91/</guid><description>&lt;h2 id="前言"&gt;前言&lt;/h2&gt;
&lt;p&gt;打开 iPhone 的&amp;quot;设置 → 辅助功能 → 旁白（VoiceOver）&amp;quot;，再用三指在屏幕上滑动，iPhone 就会逐个读出当前界面上的每个控件：&lt;code&gt;&amp;quot;登录按钮，双击以激活&amp;quot;&lt;/code&gt;、&lt;code&gt;&amp;quot;用户名，文本框，已填写 ancheng&amp;quot;&lt;/code&gt;、&lt;code&gt;&amp;quot;价格，¥99&amp;quot;&lt;/code&gt;。这背后支撑 VoiceOver、开关控制（Switch Control）、语音控制（Voice Control）、全键盘访问（Full Keyboard Access）、Xcode UITest、AI Agent 识屏 等一系列能力的，是一棵并行于 &lt;code&gt;UIView&lt;/code&gt; 视图树的 &lt;strong&gt;无障碍树（Accessibility Tree，AX Tree）&lt;/strong&gt;。&lt;/p&gt;
&lt;p&gt;对大多数 iOS 工程师来说，无障碍树是&amp;quot;黑盒&amp;quot;：设了 &lt;code&gt;isAccessibilityElement = true&lt;/code&gt;、填了 &lt;code&gt;accessibilityLabel&lt;/code&gt;，然后就不管了。但一旦遇到以下问题，就不得不深入理解它的工作机制：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;为什么 UITest 里用 &lt;code&gt;XCUIElement&lt;/code&gt; 定位不到某个按钮？&lt;/li&gt;
&lt;li&gt;为什么打开 VoiceOver 后 App 明显变卡？&lt;/li&gt;
&lt;li&gt;为什么一个自绘的 &lt;code&gt;CALayer&lt;/code&gt; 按钮在 VoiceOver 下无法被朗读？&lt;/li&gt;
&lt;li&gt;为什么 &lt;code&gt;UILabel&lt;/code&gt; 嵌在 &lt;code&gt;UIStackView&lt;/code&gt; 里焦点顺序是乱的？&lt;/li&gt;
&lt;li&gt;SwiftUI 的 &lt;code&gt;.accessibilityElement(children: .combine)&lt;/code&gt; 到底合并了什么？&lt;/li&gt;
&lt;li&gt;Accessibility Inspector 里看到的树结构从哪儿来？&lt;/li&gt;
&lt;li&gt;AI Agent（如 iOS 上的 Claude、ChatGPT Mac 客户端）是如何&amp;quot;看到&amp;quot;屏幕的？&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;本文从&lt;strong&gt;操作系统层的 AX 架构&lt;/strong&gt;讲起，逐层拆解：AX Server 守护进程、UIKit 中的 &lt;code&gt;UIAccessibility&lt;/code&gt; 协议、&lt;code&gt;UIAccessibilityElement&lt;/code&gt; 类、&lt;code&gt;UIAccessibilityContainer&lt;/code&gt; 协议、焦点排序算法、SwiftUI 的 AX 实现、辅助技术的工作原理、性能优化、UITest 与 AI 识屏原理、调试工具与最佳实践。&lt;/p&gt;</description></item><item><title>Mach-O的链接、装载与库</title><link>https://amatsuzero.github.io/LastStand/posts/interview/ios-basics/mach-o%E7%9A%84%E9%93%BE%E6%8E%A5-%E8%A3%85%E8%BD%BD%E4%B8%8E%E5%BA%93/</link><pubDate>Sat, 02 May 2026 22:32:27 +0800</pubDate><guid>https://amatsuzero.github.io/LastStand/posts/interview/ios-basics/mach-o%E7%9A%84%E9%93%BE%E6%8E%A5-%E8%A3%85%E8%BD%BD%E4%B8%8E%E5%BA%93/</guid><description>&lt;p&gt;本文深入介绍iOS/macOS开发中的Mach-O文件格式、动态库与静态库，帮助理解程序的链接、装载过程，以及Rebase/Bind的底层原理。&lt;/p&gt;
&lt;hr&gt;
&lt;h2 id="一基础概念"&gt;一、基础概念&lt;/h2&gt;
&lt;p&gt;在深入学习之前，先了解几个核心概念。&lt;/p&gt;
&lt;h3 id="10-从源代码到可执行文件"&gt;1.0 从源代码到可执行文件&lt;/h3&gt;
&lt;p&gt;一段源代码要变成可执行文件，需要经历以下几个阶段：&lt;/p&gt;
&lt;pre class="mermaid"&gt;flowchart TB
A["源代码 (.m/.swift)"] --&gt; B["预处理&lt;br/&gt;展开宏、处理#import/#include"]
B --&gt; C["编译&lt;br/&gt;源代码 → 汇编代码"]
C --&gt; D["汇编&lt;br/&gt;汇编代码 → 目标文件(.o)"]
D --&gt; E["链接&lt;br/&gt;目标文件 + 库 → 可执行文件"]
E --&gt; F["可执行文件"]
&lt;/pre&gt;
&lt;h3 id="11-什么是符号symbol"&gt;1.1 什么是符号（Symbol）&lt;/h3&gt;
&lt;p&gt;符号是程序中函数、变量、类等实体的&lt;strong&gt;名称标识&lt;/strong&gt;。当你写下一个函数调用时，编译器需要知道这个函数在哪里，符号就是用来定位它的。&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-objc" data-lang="objc"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;// 这段代码中包含多个符号
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;void&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;myFunction&lt;/span&gt;(&lt;span style="color:#66d9ef"&gt;void&lt;/span&gt;) { &lt;span style="color:#75715e"&gt;// 定义了符号 _myFunction
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; NSLog(&lt;span style="color:#e6db74"&gt;@&amp;#34;Hello&amp;#34;&lt;/span&gt;); &lt;span style="color:#75715e"&gt;// 引用了外部符号 _NSLog
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;int&lt;/span&gt; globalVar &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;10&lt;/span&gt;; &lt;span style="color:#75715e"&gt;// 定义了符号 _globalVar
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;符号分为两类：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;已定义符号&lt;/strong&gt;：在当前编译单元（即当前源文件编译生成的.o文件）中有具体代码或数据定义的符号（如上例中的 &lt;code&gt;_myFunction&lt;/code&gt; 和 &lt;code&gt;_globalVar&lt;/code&gt;）&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;未定义符号&lt;/strong&gt;：当前编译单元只是引用，实际定义在其他编译单元或库中的符号（如上例中的 &lt;code&gt;_NSLog&lt;/code&gt;），需要在链接时解析&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id="12-什么是链接linking"&gt;1.2 什么是链接（Linking）&lt;/h3&gt;
&lt;p&gt;链接是将多个编译后的目标文件（.o）组合成一个可执行文件的过程。链接器的核心工作是&lt;strong&gt;符号解析&lt;/strong&gt;——把所有&amp;quot;未定义符号&amp;quot;与其他编译单元中的&amp;quot;已定义符号&amp;quot;关联起来。&lt;/p&gt;
&lt;pre class="mermaid"&gt;flowchart LR
subgraph 输入
A["main.o&lt;br/&gt;已定义: _main&lt;br/&gt;未定义: _foo"]
B["foo.o&lt;br/&gt;已定义: _foo&lt;br/&gt;未定义: _NSLog"]
C["Foundation&lt;br/&gt;已定义: _NSLog"]
end
A --&gt; D["链接器&lt;br/&gt;符号解析"]
B --&gt; D
C --&gt; D
D --&gt; E["可执行文件&lt;br/&gt;所有符号已解析"]
&lt;/pre&gt;
&lt;h4 id="符号解析的过程"&gt;符号解析的过程&lt;/h4&gt;
&lt;p&gt;链接器会遍历所有输入的目标文件和库，执行以下步骤：&lt;/p&gt;</description></item><item><title>SDWebImage源码导读</title><link>https://amatsuzero.github.io/LastStand/posts/interview/ios-source-analysis/sdwebimage%E6%BA%90%E7%A0%81%E5%AF%BC%E8%AF%BB/</link><pubDate>Sat, 02 May 2026 22:32:27 +0800</pubDate><guid>https://amatsuzero.github.io/LastStand/posts/interview/ios-source-analysis/sdwebimage%E6%BA%90%E7%A0%81%E5%AF%BC%E8%AF%BB/</guid><description>&lt;p&gt;SDWebImage 是 iOS 生态中历史最悠久、最流行的异步图片下载缓存库，由 Olivier Poitrey 在 2009 年创建，如今由社区维护。截至 2026 年 4 月，GitHub Star 数已超过 25.6k，最新稳定版本为 &lt;strong&gt;5.21.7&lt;/strong&gt;（2026 年 2 月）。5.21 系列引入了 HDR 图片编解码支持，并持续完善线程安全和 iOS 26 的兼容性。本文基于 master 分支源码（Objective-C 实现）进行分析。&lt;/p&gt;
&lt;hr&gt;
&lt;h2 id="一整体架构"&gt;一、整体架构&lt;/h2&gt;
&lt;p&gt;SDWebImage 采用&lt;strong&gt;协议导向 + 责任链&lt;/strong&gt;的模块化设计，核心由五大子系统构成：Manager 协调层、Cache 缓存层、Downloader 下载层、Coder 编解码层和 UI 扩展层。&lt;/p&gt;
&lt;pre class="mermaid"&gt;graph TB
subgraph "UI 扩展层"
A["UIImageView+WebCache&lt;br/&gt;UIButton+WebCache&lt;br/&gt;UIView+WebCache"]
end
subgraph "管理层"
B["SDWebImageManager"]
end
subgraph "缓存层 SDImageCache"
C1["SDMemoryCache&lt;br/&gt;(NSCache + NSMapTable)"]
C2["SDDiskCache&lt;br/&gt;(NSFileManager)"]
end
subgraph "下载层"
D1["SDWebImageDownloader"]
D2["SDWebImageDownloaderOperation&lt;br/&gt;(NSOperation)"]
end
subgraph "编解码层 SDImageCodersManager"
E1["SDImageIOCoder"]
E2["SDImageGIFCoder"]
E3["SDImageAPNGCoder"]
E4["SDImageHEICCoder&lt;br/&gt;WebP/AVIF (插件)"]
end
subgraph "辅助层"
F["SDImageTransformer&lt;br/&gt;SDWebImageCacheKeyFilter&lt;br/&gt;SDWebImageOptionsProcessor&lt;br/&gt;SDCallbackQueue"]
end
A --&gt;|sd_setImageWithURL| B
B --&gt; C1
B --&gt; C2
B --&gt; D1
D1 --&gt; D2
D2 --&gt; E1
B --&gt; F
&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;源码目录结构：&lt;/strong&gt;&lt;/p&gt;</description></item><item><title>VIPER架构详解</title><link>https://amatsuzero.github.io/LastStand/posts/interview/ios-architecture/viper/</link><pubDate>Sat, 02 May 2026 22:32:27 +0800</pubDate><guid>https://amatsuzero.github.io/LastStand/posts/interview/ios-architecture/viper/</guid><description>&lt;h2 id="什么是viper"&gt;什么是VIPER&lt;/h2&gt;
&lt;p&gt;VIPER是一种更加细粒度的架构模式，由Mutual Mobile公司提出。VIPER将应用分为五个层次：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;V&lt;/strong&gt;iew（视图）：负责UI展示&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;I&lt;/strong&gt;nteractor（交互器）：负责业务逻辑&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;P&lt;/strong&gt;resenter（展示器）：负责视图逻辑&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;E&lt;/strong&gt;ntity（实体）：数据模型&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;R&lt;/strong&gt;outer（路由）：负责页面导航&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;VIPER的核心思想是&lt;strong&gt;单一职责原则&lt;/strong&gt;，每个组件只负责一件事。&lt;/p&gt;
&lt;h2 id="viper的结构"&gt;VIPER的结构&lt;/h2&gt;
&lt;pre class="mermaid"&gt;flowchart TB
subgraph Module["Module"]
View["View"]
Presenter["Presenter"]
Interactor["Interactor"]
Router["Router"]
Entity["Entity"]
View --&gt;|用户事件| Presenter
Presenter --&gt;|更新UI| View
Presenter --&gt;|业务请求| Interactor
Interactor --&gt;|业务结果| Presenter
Presenter --&gt;|导航请求| Router
Interactor --&gt;|读写数据| Entity
Router -.-&gt;|创建并导航到其他模块| View
end
&lt;/pre&gt;
&lt;h3 id="数据流向说明"&gt;数据流向说明&lt;/h3&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;用户交互流&lt;/strong&gt;：View → Presenter → Interactor → Presenter → View&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;导航流&lt;/strong&gt;：View → Presenter → Router → 新的 View&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;数据流&lt;/strong&gt;：Interactor → Entity（数据存储）→ Interactor → Presenter → View（数据展示）&lt;/li&gt;
&lt;/ol&gt;
&lt;h2 id="viper的五个组件"&gt;VIPER的五个组件&lt;/h2&gt;
&lt;h3 id="view视图层"&gt;View（视图层）&lt;/h3&gt;
&lt;p&gt;View负责：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;展示UI&lt;/li&gt;
&lt;li&gt;接收用户输入并传递给Presenter&lt;/li&gt;
&lt;li&gt;实现Presenter定义的协议&lt;/li&gt;
&lt;/ul&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-swift" data-lang="swift"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;// View协议&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;protocol&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;UserListViewProtocol&lt;/span&gt;: AnyObject {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;func&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;showLoading&lt;/span&gt;()
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;func&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;showUsers&lt;/span&gt;(&lt;span style="color:#66d9ef"&gt;_&lt;/span&gt; users: [UserViewModel])
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;func&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;showError&lt;/span&gt;(&lt;span style="color:#66d9ef"&gt;_&lt;/span&gt; message: String)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;// ViewController实现&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;class&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;UserListViewController&lt;/span&gt;: UIViewController, UserListViewProtocol {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;var&lt;/span&gt; presenter: UserListPresenterProtocol!
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;private&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;var&lt;/span&gt; users: [UserViewModel] = []
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;override&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;func&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;viewDidLoad&lt;/span&gt;() {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;super&lt;/span&gt;.viewDidLoad()
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; presenter.viewDidLoad()
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; }
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;func&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;showUsers&lt;/span&gt;(&lt;span style="color:#66d9ef"&gt;_&lt;/span&gt; users: [UserViewModel]) {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;self&lt;/span&gt;.users = users
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; tableView.reloadData()
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; }
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;func&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;tableView&lt;/span&gt;(&lt;span style="color:#66d9ef"&gt;_&lt;/span&gt; tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; presenter.didSelectUser(at: indexPath.row)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; }
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h3 id="interactor交互器"&gt;Interactor（交互器）&lt;/h3&gt;
&lt;p&gt;Interactor负责：&lt;/p&gt;</description></item><item><title>编译优化-二进制化</title><link>https://amatsuzero.github.io/LastStand/posts/interview/ios-build/%E4%BA%8C%E8%BF%9B%E5%88%B6%E5%8C%96/</link><pubDate>Sat, 02 May 2026 22:32:27 +0800</pubDate><guid>https://amatsuzero.github.io/LastStand/posts/interview/ios-build/%E4%BA%8C%E8%BF%9B%E5%88%B6%E5%8C%96/</guid><description>&lt;p&gt;二进制化是大型 iOS 工程编译加速的&amp;quot;银弹&amp;quot;：把组件从源码编译改成预编译产物链接，在本地无需再跑 Swift/Clang 前端，直接链接已有的 &lt;code&gt;.a&lt;/code&gt; / &lt;code&gt;.framework&lt;/code&gt; / &lt;code&gt;.xcframework&lt;/code&gt;。美团在 &lt;code&gt;cocoapods-hmap-prebuilt&lt;/code&gt; 之外，还通过二进制化把整体编译速度提升 50%+。本文系统介绍二进制化的原理、实现方式与工具链。&lt;/p&gt;
&lt;hr&gt;
&lt;h2 id="为什么能加速"&gt;为什么能加速&lt;/h2&gt;
&lt;p&gt;典型项目的编译时间分布（抖音量级）：&lt;/p&gt;
&lt;pre class="mermaid"&gt;pie title 冷编译耗时占比
"业务代码编译" : 25
"第三方依赖编译" : 50
"链接" : 15
"其他" : 10
&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;超过一半的时间都花在编译 &amp;ldquo;不会改&amp;rdquo; 的依赖上&lt;/strong&gt;。把依赖预编译成二进制，本地只需要链接，这部分耗时直接归零。再配合远程缓存，第一次拉代码的同学也能命中他人产物。&lt;/p&gt;
&lt;hr&gt;
&lt;h2 id="二进制产物形态"&gt;二进制产物形态&lt;/h2&gt;
&lt;h3 id="静态库a"&gt;静态库（.a）&lt;/h3&gt;
&lt;p&gt;最传统的形态：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-text" data-lang="text"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;libSDWebImage.a
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;SDWebImage/Headers/
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;├── SDWebImage.h
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;└── ...
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;特点：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;最小体积，Mach-O 里没有 LC_SEGMENT_64 / LC_LOAD_DYLIB 负担&lt;/li&gt;
&lt;li&gt;启动最快，无 dyld 成本&lt;/li&gt;
&lt;li&gt;静态链接时整合到主可执行&lt;/li&gt;
&lt;li&gt;不支持资源文件（需要单独管理 bundle）&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id="frameworkframework"&gt;Framework（.framework）&lt;/h3&gt;
&lt;p&gt;Apple 推荐的打包形态：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-text" data-lang="text"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;SDWebImage.framework/
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;├── SDWebImage # 二进制（静态或动态）
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;├── Headers/ # 公开头文件
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;├── Modules/ # modulemap、swiftmodule
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;│ ├── module.modulemap
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;│ └── SDWebImage.swiftmodule/
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;│ ├── arm64-apple-ios.swiftmodule
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;│ └── arm64-apple-ios.swiftinterface
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;└── Info.plist
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;通过 &lt;code&gt;Mach-O Type&lt;/code&gt; 设置决定内部是静态还是动态库：&lt;/p&gt;</description></item><item><title>iOS架构概述</title><link>https://amatsuzero.github.io/LastStand/posts/interview/ios-architecture/ios%E6%9E%B6%E6%9E%84%E6%A6%82%E8%BF%B0/</link><pubDate>Sun, 21 Jun 2026 22:41:52 +0800</pubDate><guid>https://amatsuzero.github.io/LastStand/posts/interview/ios-architecture/ios%E6%9E%B6%E6%9E%84%E6%A6%82%E8%BF%B0/</guid><description>&lt;h2 id="什么是架构"&gt;什么是架构&lt;/h2&gt;
&lt;p&gt;软件架构是指软件系统的高层结构，定义了系统的各个组成部分及其之间的关系。一个好的架构能够帮助我们：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;职责分离&lt;/strong&gt;：将不同的功能模块分开，降低耦合度&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;可测试性&lt;/strong&gt;：使代码更容易进行单元测试&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;可维护性&lt;/strong&gt;：便于理解和修改代码&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;可扩展性&lt;/strong&gt;：方便添加新功能&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;团队协作&lt;/strong&gt;：不同开发者可以并行开发不同模块&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="架构的两个层次"&gt;架构的两个层次&lt;/h2&gt;
&lt;p&gt;在讨论iOS架构时，需要区分两种不同层次的架构：&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;类型&lt;/th&gt;
&lt;th&gt;关注点&lt;/th&gt;
&lt;th&gt;代表模式&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;页面架构&lt;/td&gt;
&lt;td&gt;单个页面内的代码组织&lt;/td&gt;
&lt;td&gt;MVC、MVP、MVVM、MVI、TCA、VIPER&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;工程架构&lt;/td&gt;
&lt;td&gt;整个App的模块划分与通信&lt;/td&gt;
&lt;td&gt;组件化、插件化、微服务化&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;两者并不冲突，大型项目通常会同时采用：工程层面使用组件化拆分业务，每个组件内部使用MVVM等页面架构。&lt;/p&gt;
&lt;h2 id="页面架构模式"&gt;页面架构模式&lt;/h2&gt;
&lt;h3 id="mvc-model-view-controller"&gt;MVC (Model-View-Controller)&lt;/h3&gt;
&lt;p&gt;MVC是Apple官方推荐的架构模式，也是iOS开发中最基础的架构。&lt;/p&gt;
&lt;pre class="mermaid"&gt;flowchart LR
Controller &lt;--&gt;|读写| Model
Controller --&gt;|更新| View
View -.-&gt;|用户交互| Controller
&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;特点&lt;/strong&gt;：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Controller作为中介者连接Model和View&lt;/li&gt;
&lt;li&gt;View和Model不直接通信&lt;/li&gt;
&lt;li&gt;在iOS中，ViewController往往承担了过多职责&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id="mvp-model-view-presenter"&gt;MVP (Model-View-Presenter)&lt;/h3&gt;
&lt;p&gt;MVP是MVC的演进版本，将业务逻辑从Controller中抽离到Presenter。&lt;/p&gt;
&lt;pre class="mermaid"&gt;flowchart LR
Presenter --&gt;|更新| Model
Presenter --&gt;|更新| View
Model -.-&gt;|数据| Presenter
View -.-&gt;|事件| Presenter
View --- ViewController
&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;特点&lt;/strong&gt;：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Presenter持有View的引用（通常是协议）&lt;/li&gt;
&lt;li&gt;View变得非常&amp;quot;被动&amp;quot;，只负责展示&lt;/li&gt;
&lt;li&gt;便于单元测试&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id="mvvm-model-view-viewmodel"&gt;MVVM (Model-View-ViewModel)&lt;/h3&gt;
&lt;p&gt;MVVM通过数据绑定实现View和ViewModel的同步更新。&lt;/p&gt;
&lt;pre class="mermaid"&gt;flowchart LR
ViewModel &lt;--&gt;|读写| Model
ViewModel &lt;--&gt;|数据绑定| View
&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;特点&lt;/strong&gt;：&lt;/p&gt;</description></item><item><title>objc4 Selector / SEL 注册、唯一化与方法名查找</title><link>https://amatsuzero.github.io/LastStand/posts/ocsourcecodeanalysis/selector-interning-explained/</link><pubDate>Mon, 01 Jun 2026 19:50:12 +0800</pubDate><guid>https://amatsuzero.github.io/LastStand/posts/ocsourcecodeanalysis/selector-interning-explained/</guid><description>&lt;h1 id="selector--sel-注册唯一化与方法名查找"&gt;Selector / SEL 注册、唯一化与方法名查找&lt;/h1&gt;
&lt;p&gt;在 objc4 中，&lt;code&gt;SEL&lt;/code&gt; 的关键价值不是承载一段复杂对象，而是把方法名字符串 “驻留”为全进程唯一的指针。注册、镜像加载 fixup、方法列表排序、方法查找和消息缓存都建立在这个事实上： 同名 selector 最终拥有同一个地址，因此比较 selector 可以退化为一次指针比较。&lt;/p&gt;
&lt;h2 id="作用"&gt;作用&lt;/h2&gt;
&lt;p&gt;&lt;strong&gt;统一方法名身份&lt;/strong&gt; 编译器、Mach-O 镜像、动态注册 API 和运行时内部方法列表都可能产生方法名。selector 唯一化后，同一个方法名只对应一个 &lt;code&gt;SEL&lt;/code&gt;。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;让查找足够便宜&lt;/strong&gt; 方法列表和缓存查找不需要反复比较字符串。命中条件基本都是 &lt;code&gt;method.name == sel&lt;/code&gt; 或 &lt;code&gt;bucket.sel == _cmd&lt;/code&gt;。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;支撑 dyld 预优化&lt;/strong&gt; 共享缓存中的 selector 可以由 dyld 提供内建唯一值；未优化镜像在 &lt;code&gt;_read_images&lt;/code&gt; 中被 runtime 修正到唯一值。&lt;/p&gt;
&lt;p&gt;对外头文件把 &lt;code&gt;SEL&lt;/code&gt; 声明为不透明类型：&lt;code&gt;typedef struct objc_selector *SEL;&lt;/code&gt;。 但在当前实现中，runtime 会把 selector 当成方法名 C 字符串指针使用，&lt;code&gt;sel_getName()&lt;/code&gt; 直接把 &lt;code&gt;SEL&lt;/code&gt; 转回 &lt;code&gt;const char *&lt;/code&gt;。&lt;/p&gt;
&lt;h2 id="核心结构函数与字段"&gt;核心结构、函数与字段&lt;/h2&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;&lt;/th&gt;
&lt;th&gt;&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;SEL&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;公开为不透明 selector 指针，实际唯一值是某个方法名字符串的地址。来源：&lt;code&gt;runtime/objc.h&lt;/code&gt;。&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;namedSelectors&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;ExplicitInitDenseSet&amp;lt;const char *&amp;gt;&lt;/code&gt;，保存非 dyld 内建 selector 的唯一字符串指针。来源：&lt;code&gt;runtime/objc-sel.mm&lt;/code&gt;。&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;selLock&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;保护 selector 表。&lt;code&gt;sel_registerName()&lt;/code&gt; 自行加锁；镜像加载和方法列表 fixup 常在外层持锁后调用 &lt;code&gt;sel_registerNameNoLock()&lt;/code&gt;。&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;_sel_searchBuiltins()&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;在支持预优化时向 dyld 查询共享缓存内建 selector，优先返回 dyld 已唯一化的值。&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;sel_registerName()&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;注册并返回 selector；若已存在则返回既有唯一值；会复制传入字符串。&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;sel_lookUpByName()&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;只查找，不创建。未注册返回 &lt;code&gt;NULL&lt;/code&gt;，测试 &lt;code&gt;test/sel.m&lt;/code&gt; 明确覆盖该行为。&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;method_t::name&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;方法条目的 selector 字段。方法列表 fixup 后，这个字段应是唯一化的 &lt;code&gt;SEL&lt;/code&gt;。&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;cache_t&lt;/code&gt; / &lt;code&gt;bucket_t&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;消息缓存以 &lt;code&gt;SEL&lt;/code&gt; 为 key，桶保存 &lt;code&gt;SEL + IMP&lt;/code&gt;，hash 直接来自 selector 地址。&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;h2 id="实现原理"&gt;实现原理&lt;/h2&gt;
&lt;p&gt;selector interning 的核心是“先按名字查找唯一槽，再把槽里的字符串地址作为 &lt;code&gt;SEL&lt;/code&gt; 返回”。 对 dyld 共享缓存内建 selector，runtime 先问 dyld；对普通 selector，runtime 使用 &lt;code&gt;namedSelectors&lt;/code&gt; 保存唯一字符串。&lt;/p&gt;</description></item><item><title>编译优化-二进制化实现原理</title><link>https://amatsuzero.github.io/LastStand/posts/interview/ios-build/%E4%BA%8C%E8%BF%9B%E5%88%B6%E5%8C%96%E5%AE%9E%E7%8E%B0%E5%8E%9F%E7%90%86/</link><pubDate>Fri, 08 May 2026 22:56:38 +0800</pubDate><guid>https://amatsuzero.github.io/LastStand/posts/interview/ios-build/%E4%BA%8C%E8%BF%9B%E5%88%B6%E5%8C%96%E5%AE%9E%E7%8E%B0%E5%8E%9F%E7%90%86/</guid><description>&lt;p&gt;本文结合 &lt;a href="https://github.com/tripleCC/cocoapods-bin"&gt;cocoapods-bin&lt;/a&gt;（社区最成熟的二进制化插件）拆解&amp;quot;Pod 二进制化&amp;quot;背后的工程机制：集成时如何透明替换 spec、打包时如何还原 Xcode 产物、调试时如何跳回源码。文末给出&amp;quot;自研一套二进制系统&amp;quot;的落地 checklist。&lt;/p&gt;
&lt;p&gt;想先了解二进制化的整体背景、坑点和适用场景，可以先看 &lt;a href="https://amatsuzero.github.io/LastStand/posts/interview/ios-build/%E4%BA%8C%E8%BF%9B%E5%88%B6%E5%8C%96/"&gt;编译优化-二进制化&lt;/a&gt;；想了解 pod install 阶段本身的优化（HMap、并发下载等）见 &lt;a href="https://amatsuzero.github.io/LastStand/posts/interview/ios-build/cocoapods%E4%BC%98%E5%8C%96/"&gt;编译优化-CocoaPods优化&lt;/a&gt;。&lt;/p&gt;
&lt;hr&gt;
&lt;h2 id="总体架构"&gt;总体架构&lt;/h2&gt;
&lt;p&gt;一套完整的 Pod 二进制化系统由三层组成：&lt;/p&gt;
&lt;pre class="mermaid"&gt;flowchart TB
subgraph CI[打包 CI]
A1[源码 podspec] --&gt; A2[壳工程 pod install]
A2 --&gt; A3[xcodebuild 双 SDK 编译]
A3 --&gt; A4[lipo / create-xcframework]
A4 --&gt; A5[上传 OSS]
A5 --&gt; A6[生成 binary podspec]
A6 --&gt; A7[push 到二进制仓]
end
subgraph Dev[开发机 pod install]
B1[Podfile 声明 plugin] --&gt; B2[Resolver/LazySpecification Hook]
B2 --&gt; B3{二进制仓&lt;br/&gt;是否有该版本?}
B3 -- 是 --&gt; B4[替换为 binary spec]
B3 -- 否 --&gt; B5[回退源码 spec]
B4 --&gt; B6[pod download zip]
B5 --&gt; B6
B6 --&gt; B7[Xcode 链接]
end
subgraph Debug[调试]
C1[dwarfdump 读取&lt;br/&gt;DW_AT_comp_dir] --&gt; C2[下载源码]
C2 --&gt; C3[软链到 DWARF 路径]
C3 --&gt; C4[LLDB 自动跳转源码]
end
A7 --&gt; B3
A3 -.DWARF 路径信息.-&gt; C1
&lt;/pre&gt;
&lt;p&gt;关键设计点：&lt;/p&gt;</description></item><item><title>Objective-C与Swift区别</title><link>https://amatsuzero.github.io/LastStand/posts/interview/ios-basics/objective-c%E4%B8%8Eswift%E5%8C%BA%E5%88%AB/</link><pubDate>Fri, 08 May 2026 13:07:14 +0800</pubDate><guid>https://amatsuzero.github.io/LastStand/posts/interview/ios-basics/objective-c%E4%B8%8Eswift%E5%8C%BA%E5%88%AB/</guid><description>&lt;h2 id="语言设计"&gt;语言设计&lt;/h2&gt;
&lt;h3 id="objective-c"&gt;Objective-C&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;是C的超集，在C的基础上添加了Smalltalk风格的消息传递机制&lt;/li&gt;
&lt;li&gt;对象间交互不通过调用方法而是发送消息，以实现面向对象编程和超高的动态性&lt;/li&gt;
&lt;li&gt;动态性由 Objective-C Runtime 系统支持，可以在运行时修改类结构、方法交换等，详见 &lt;a href="https://amatsuzero.github.io/LastStand/posts/interview/ios-basics/runtime/"&gt;Runtime&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;弱类型语言，核心类型&lt;code&gt;id&lt;/code&gt;可以指向任何Objective-C对象&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id="swift"&gt;Swift&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;从很多现代化语言中汲取精华，是一门偏重于安全、性能的现代化语言&lt;/li&gt;
&lt;li&gt;Swift 也有自己的运行时系统（Swift Runtime），但设计哲学完全不同，更强调编译期优化&lt;/li&gt;
&lt;li&gt;强类型语言，编译器在编译阶段进行严格的类型检查&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="语法特性"&gt;语法特性&lt;/h2&gt;
&lt;h3 id="objective-c-1"&gt;Objective-C&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;语法冗长，需要显式声明类型&lt;/li&gt;
&lt;li&gt;命名通常较长且需要添加前缀避免冲突&lt;/li&gt;
&lt;li&gt;需要单独的&lt;code&gt;.h&lt;/code&gt;和&lt;code&gt;.m&lt;/code&gt;文件声明接口和实现&lt;/li&gt;
&lt;li&gt;引用其他文件/模块必须要&lt;code&gt;import&lt;/code&gt;（&lt;a href="https://amatsuzero.github.io/LastStand/posts/interview/ios-basics/objective-c%E4%B8%ADimport%E8%AF%A6%E8%A7%A3/"&gt;Objective-C中import详解&lt;/a&gt;）&lt;/li&gt;
&lt;li&gt;协议不支持默认实现&lt;/li&gt;
&lt;li&gt;泛型是&amp;quot;轻量级泛型&amp;quot;，仅用于编译时类型检查，运行时类型信息会被擦除&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id="swift-1"&gt;Swift&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;语法简洁，强大的类型推断减少冗余的类型声明&lt;/li&gt;
&lt;li&gt;有命名空间（模块）的存在避免命名冲突&lt;/li&gt;
&lt;li&gt;不需要单独的头文件声明接口&lt;/li&gt;
&lt;li&gt;默认情况下变量必须初始化&lt;/li&gt;
&lt;li&gt;引用同模块的其他文件不需要&lt;code&gt;import&lt;/code&gt;（&lt;a href="https://amatsuzero.github.io/LastStand/posts/interview/ios-basics/swift%E4%B8%ADimport%E8%AF%A6%E8%A7%A3/"&gt;Swift中import详解&lt;/a&gt;）&lt;/li&gt;
&lt;li&gt;协议支持默认实现、支持拓展，支持关联类型以实现泛型协议&lt;/li&gt;
&lt;li&gt;值类型也可以遵守协议&lt;/li&gt;
&lt;li&gt;泛型在编译时进行类型特化优化，支持完整的泛型元编程&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="内存管理"&gt;内存管理&lt;/h2&gt;
&lt;h3 id="objective-c-2"&gt;Objective-C&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;大部分都是引用类型，依赖引用计数管理内存&lt;/li&gt;
&lt;li&gt;ARC在编译时自动插入&lt;code&gt;retain&lt;/code&gt;、&lt;code&gt;release&lt;/code&gt;、&lt;code&gt;autorelease&lt;/code&gt;调用&lt;/li&gt;
&lt;li&gt;64位系统使用优化的isa（Non-pointer isa），通过位域在isa中嵌入引用计数（&lt;code&gt;extra_rc&lt;/code&gt;字段），溢出时使用SideTable存储&lt;/li&gt;
&lt;li&gt;实例变量（ivar）会被Runtime自动初始化为0/nil&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id="swift-2"&gt;Swift&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;引用类型也是依赖引用计数管理内存&lt;/li&gt;
&lt;li&gt;存在大量的值类型，例如结构体、枚举、数组、字典等&lt;/li&gt;
&lt;li&gt;非逃逸的值类型的内存存在栈区由系统进行自动管理&lt;/li&gt;
&lt;li&gt;纯Swift类的引用计数直接存储在对象头部的RefCount字段中，无需SideTable，访问更高效&lt;/li&gt;
&lt;li&gt;编译器在编译时就确保了初始化，不需要运行时统一清零&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;拓展：&lt;a href="https://amatsuzero.github.io/LastStand/posts/interview/ios-basics/%E5%80%BC%E7%B1%BB%E5%9E%8B%E5%92%8C%E5%BC%95%E7%94%A8%E7%B1%BB%E5%9E%8B%E7%9A%84%E5%8C%BA%E5%88%AB/"&gt;值类型和引用类型的区别&lt;/a&gt;
拓展：&lt;a href="https://amatsuzero.github.io/LastStand/posts/interview/ios-basics/ios%E4%B8%AD%E7%9A%84%E5%86%85%E5%AD%98%E7%AE%A1%E7%90%86/"&gt;iOS中的内存管理&lt;/a&gt;&lt;/p&gt;
&lt;h2 id="性能对比"&gt;性能对比&lt;/h2&gt;
&lt;h3 id="objective-c-3"&gt;Objective-C&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;基于消息传递机制本质上是动态派发，运行时查找方法实现，有一定开销&lt;/li&gt;
&lt;li&gt;ARC管理引用计数也有开销&lt;/li&gt;
&lt;li&gt;引用类型内存存在堆区，内存管理的性能开销会比栈区多很多&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id="swift-3"&gt;Swift&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;方法派发尽可能使用静态派发（如对&lt;code&gt;final&lt;/code&gt;类/方法、私有方法、值类型方法的调用）&lt;/li&gt;
&lt;li&gt;编译器可以内联优化，速度接近C
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;内联优化&lt;/strong&gt;：比如A方法调用B方法，B方法调用C方法，代码编写调用A方法时编译器通过内联直接调用C方法的实现&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;值类型内存分配在栈区，性能开销相对较小&lt;/li&gt;
&lt;li&gt;虽然值类型是深拷贝，Swift为了优化值类型性能引入写时拷贝（Copy-on-Write）机制，值类型只在写操作发生深拷贝，其他时候都是浅拷贝&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="安全性"&gt;安全性&lt;/h2&gt;
&lt;h3 id="objective-c-4"&gt;Objective-C&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;弱类型（动态类型）占主导&lt;/li&gt;
&lt;li&gt;核心类型&lt;code&gt;id&lt;/code&gt;可以指向任何Objective-C对象&lt;/li&gt;
&lt;li&gt;编译器几乎不做类型检查，会有运行时崩溃的风险（如向不响应某消息的对象发送该消息）&lt;/li&gt;
&lt;li&gt;&lt;code&gt;nil&lt;/code&gt;消息发送不会崩溃但可能导致逻辑错误，不容易感知&lt;/li&gt;
&lt;li&gt;局部变量不会自动初始化，可能包含栈上的垃圾数据（未定义行为）&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id="swift-4"&gt;Swift&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;可选类型强制处理空值，编译器强制解包检查&lt;/li&gt;
&lt;li&gt;强类型和编译时检查阻止了大量常见错误&lt;/li&gt;
&lt;li&gt;变量必须初始化后才能使用，编译器在编译阶段强制检查，消除未定义行为&lt;/li&gt;
&lt;li&gt;强制初始化使编译器能更精确地追踪变量生命周期，带来更多优化机会&lt;/li&gt;
&lt;li&gt;数组越界等操作会在运行时触发明确的崩溃，便于定位问题&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="编程范式"&gt;编程范式&lt;/h2&gt;
&lt;h3 id="objective-c-5"&gt;Objective-C&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;主要是面向对象编程（OOP）&lt;/li&gt;
&lt;li&gt;通过继承实现代码复用&lt;/li&gt;
&lt;li&gt;依赖Runtime实现面向切面编程（AOP），如Method Swizzling&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id="swift-5"&gt;Swift&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;拥抱多范式，对函数式编程、面向协议编程（POP）、声明式编程很友好&lt;/li&gt;
&lt;li&gt;通过协议扩展提供默认实现，协议组合替代多继承&lt;/li&gt;
&lt;li&gt;值类型（struct/enum）也可以遵循协议，不再局限于类&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;拓展：&lt;a href="https://amatsuzero.github.io/LastStand/posts/interview/ios-advanced/oop-pop-aop/"&gt;OOP、POP与AOP&lt;/a&gt;&lt;/p&gt;</description></item><item><title>APM-数据采集</title><link>https://amatsuzero.github.io/LastStand/posts/interview/ios-apm/%E6%95%B0%E6%8D%AE%E9%87%87%E9%9B%86/</link><pubDate>Sat, 02 May 2026 22:32:27 +0800</pubDate><guid>https://amatsuzero.github.io/LastStand/posts/interview/ios-apm/%E6%95%B0%E6%8D%AE%E9%87%87%E9%9B%86/</guid><description>&lt;p&gt;本文聚焦 iOS APM SDK 的&lt;strong&gt;采集层&lt;/strong&gt;，把 &lt;code&gt;APM-指标体系&lt;/code&gt; 定义好的指标落地到具体代码与底层原理。按照采集对象分八个模块展开：崩溃、卡死、内存/OOM、FPS 卡顿、启动、网络、CPU/磁盘、业务。&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;原理深度与相关文章联动：本文给出整体采集设计与关键代码；单项（如 Mach 异常、Signal、MemoryGraph 等）的纯原理细节在&amp;quot;崩溃/卡顿/启动/耗电&amp;quot;系列中已有深入剖析，本篇通过链接形式串联，避免重复。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;hr&gt;
&lt;h2 id="一采集技术图谱"&gt;一、采集技术图谱&lt;/h2&gt;
&lt;pre class="mermaid"&gt;graph TB
subgraph Hook[Hook 技术]
H1[Method Swizzling&lt;br/&gt;Objective-C Runtime]
H2[fishhook&lt;br/&gt;C 函数符号重绑]
H3[Objc Categroy + +load]
H4[KVO / NSNotificationCenter]
H5[C++ Virtual Table Hook]
end
subgraph System[系统 API]
S1[MetricKit]
S2[os_signpost / OSLog]
S3[Runtime&lt;br/&gt;task_* / thread_*]
S4[libdispatch signpost]
S5[URLSessionTaskMetrics]
end
subgraph Signal[信号/异常]
E1[NSSetUncaughtExceptionHandler]
E2[signal / sigaction]
E3[Mach Exception Port]
E4[libc++ abi 异常]
end
subgraph Sampling[采样]
P1[RunLoop Observer]
P2[Timer/GCD Source]
P3[CADisplayLink]
P4[backtrace 回溯]
end
&lt;/pre&gt;
&lt;hr&gt;
&lt;h2 id="二崩溃采集"&gt;二、崩溃采集&lt;/h2&gt;
&lt;blockquote&gt;
&lt;p&gt;原理文章：&lt;a href="https://amatsuzero.github.io/LastStand/posts/interview/ios-performance/crash-%E5%8E%9F%E7%90%86/"&gt;崩溃-原理&lt;/a&gt; · &lt;a href="https://amatsuzero.github.io/LastStand/posts/interview/ios-performance/crash-mach%E5%BC%82%E5%B8%B8/"&gt;崩溃-Mach异常&lt;/a&gt; · &lt;a href="https://amatsuzero.github.io/LastStand/posts/interview/ios-performance/crash-%E4%BF%A1%E5%8F%B7%E5%A4%84%E7%90%86/"&gt;崩溃-信号处理&lt;/a&gt; · &lt;a href="https://amatsuzero.github.io/LastStand/posts/interview/ios-performance/crash-%E9%87%87%E9%9B%86/"&gt;崩溃-采集&lt;/a&gt;&lt;/p&gt;</description></item><item><title>iOS音视频原理</title><link>https://amatsuzero.github.io/LastStand/posts/interview/ios-advanced/%E9%9F%B3%E8%A7%86%E9%A2%91%E5%8E%9F%E7%90%86/</link><pubDate>Sat, 02 May 2026 22:32:27 +0800</pubDate><guid>https://amatsuzero.github.io/LastStand/posts/interview/ios-advanced/%E9%9F%B3%E8%A7%86%E9%A2%91%E5%8E%9F%E7%90%86/</guid><description>&lt;p&gt;音视频开发是iOS中一个庞大且核心的技术领域，涵盖采集、编码、传输、解码、渲染等完整链路。本文从基础概念出发，深入iOS平台提供的音视频框架和底层原理。&lt;/p&gt;
&lt;h2 id="音视频处理全链路"&gt;音视频处理全链路&lt;/h2&gt;
&lt;p&gt;一个完整的音视频系统（如直播、视频通话、短视频）包含以下环节：&lt;/p&gt;
&lt;pre class="mermaid"&gt;flowchart LR
A["采集&lt;br/&gt;Camera/Mic"] --&gt; B["前处理&lt;br/&gt;美颜/降噪"]
B --&gt; C["编码&lt;br/&gt;H.264/AAC"]
C --&gt; D["封装&lt;br/&gt;FLV/MP4"]
D --&gt; E["传输&lt;br/&gt;RTMP/HLS"]
E --&gt; F["解封装&lt;br/&gt;解析容器"]
F --&gt; G["解码&lt;br/&gt;VideoToolbox"]
G --&gt; H["后处理&lt;br/&gt;滤镜/混音"]
H --&gt; I["渲染&lt;br/&gt;Metal/Speaker"]
&lt;/pre&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;环节&lt;/th&gt;
&lt;th&gt;做什么&lt;/th&gt;
&lt;th&gt;iOS中对应的技术&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;采集&lt;/td&gt;
&lt;td&gt;从摄像头/麦克风获取原始数据&lt;/td&gt;
&lt;td&gt;AVCaptureSession&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;前处理&lt;/td&gt;
&lt;td&gt;美颜、滤镜、降噪、回声消除&lt;/td&gt;
&lt;td&gt;CoreImage、vDSP&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;编码&lt;/td&gt;
&lt;td&gt;将原始数据压缩为体积更小的格式&lt;/td&gt;
&lt;td&gt;VideoToolbox、AudioToolbox&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;封装&lt;/td&gt;
&lt;td&gt;将编码后的音视频数据打包到容器中&lt;/td&gt;
&lt;td&gt;AVAssetWriter&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;传输&lt;/td&gt;
&lt;td&gt;通过网络发送到服务器或其他端&lt;/td&gt;
&lt;td&gt;URLSession、第三方推流SDK&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;解封装&lt;/td&gt;
&lt;td&gt;从容器中分离出音频流和视频流&lt;/td&gt;
&lt;td&gt;AVAssetReader&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;解码&lt;/td&gt;
&lt;td&gt;将压缩数据还原为原始像素/采样数据&lt;/td&gt;
&lt;td&gt;VideoToolbox、AudioToolbox&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;后处理&lt;/td&gt;
&lt;td&gt;滤镜、水印、混音等&lt;/td&gt;
&lt;td&gt;CoreImage、Metal&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;渲染&lt;/td&gt;
&lt;td&gt;将画面显示到屏幕、声音输出到扬声器&lt;/td&gt;
&lt;td&gt;AVSampleBufferDisplayLayer、Metal、AudioUnit&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;h2 id="核心术语"&gt;核心术语&lt;/h2&gt;
&lt;p&gt;在深入细节之前，先了解几个贯穿全文的核心概念：&lt;/p&gt;
&lt;h3 id="什么是编解码器codec"&gt;什么是编解码器（Codec）&lt;/h3&gt;
&lt;p&gt;&lt;strong&gt;Codec&lt;/strong&gt; = Coder + Decoder，即编码器+解码器的合称。编码器负责将原始音视频数据压缩为更小的格式，解码器负责将压缩数据还原。&lt;/p&gt;
&lt;p&gt;音视频中有两类完全不同的&amp;quot;格式&amp;quot;概念，初学者极易混淆：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-fallback" data-lang="fallback"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;编码格式（Codec）：定义数据怎么压缩
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; 视频：H.264、H.265、VP9、AV1
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; 音频：AAC、MP3、Opus、FLAC
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;封装格式（Container）：定义压缩后的数据怎么组织存储
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; MP4、MOV、FLV、MKV、TS
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;两者是独立的，可以自由组合:
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; MP4容器 + H.264视频 + AAC音频 （最常见的组合）
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; MOV容器 + H.265视频 + AAC音频 （iPhone录制默认）
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; FLV容器 + H.264视频 + AAC音频 （直播推流常用）
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; MKV容器 + AV1视频 + Opus音频 （新一代免费组合）
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h3 id="什么是h264和h265"&gt;什么是H.264和H.265&lt;/h3&gt;
&lt;p&gt;&lt;strong&gt;H.264&lt;/strong&gt;（也叫AVC，Advanced Video Coding）是目前使用最广泛的视频编码标准，由ITU-T和ISO/IEC联合制定，2003年发布。它定义了一套将视频帧压缩为比特流的算法规范——包括如何划分图像块、如何预测、如何变换量化等。几乎所有设备和平台都支持H.264硬件解码。&lt;/p&gt;</description></item><item><title>SnapKit源码导读</title><link>https://amatsuzero.github.io/LastStand/posts/interview/ios-source-analysis/snapkit%E6%BA%90%E7%A0%81%E5%AF%BC%E8%AF%BB/</link><pubDate>Sat, 02 May 2026 22:32:27 +0800</pubDate><guid>https://amatsuzero.github.io/LastStand/posts/interview/ios-source-analysis/snapkit%E6%BA%90%E7%A0%81%E5%AF%BC%E8%AF%BB/</guid><description>&lt;p&gt;SnapKit 是 iOS / macOS 社区最广泛使用的 Auto Layout DSL 库，由 Robert Payne 等人维护，目前在 GitHub 已收获 &lt;strong&gt;20k+ star&lt;/strong&gt;。它在 &lt;code&gt;NSLayoutConstraint&lt;/code&gt; 之上构建了一整套链式、类型安全、面向协议的声明式约束语法。本文基于 &lt;strong&gt;v5.7.1&lt;/strong&gt;（2025 年 2 月发布，最后 master commit 2025-05-08 &lt;code&gt;19f59a6&lt;/code&gt;）源码进行分析，代码总量不足 &lt;strong&gt;3500 行&lt;/strong&gt;，却用一个分级的 Builder 链路，把 &lt;code&gt;NSLayoutConstraint&lt;/code&gt; 那套冗长的 API 封装成了今天我们习惯的 &lt;code&gt;make.left.equalTo(x).offset(10)&lt;/code&gt;。&lt;/p&gt;
&lt;hr&gt;
&lt;h2 id="一整体架构"&gt;一、整体架构&lt;/h2&gt;
&lt;p&gt;SnapKit 的核心设计可以用一句话概括：&lt;strong&gt;用编译期强约束的链式 Builder，驱动一个延迟构建的 &lt;code&gt;ConstraintDescription&lt;/code&gt;，最终在闭包结束后一次性生成 &lt;code&gt;NSLayoutConstraint&lt;/code&gt; 并激活&lt;/strong&gt;。&lt;/p&gt;
&lt;pre class="mermaid"&gt;graph TB
subgraph "DSL 入口层"
V["UIView / NSView / UILayoutGuide"]
SNP["view.snp&lt;br/&gt;(ConstraintViewDSL)"]
MK["makeConstraints&lt;br/&gt;remakeConstraints&lt;br/&gt;updateConstraints"]
end
subgraph "Builder 链（阶段化构建器）"
CM["ConstraintMaker&lt;br/&gt;(属性起点 make.left)"]
CME["ConstraintMakerExtendable&lt;br/&gt;(追加属性 .top.right)"]
CMR["ConstraintMakerRelatable&lt;br/&gt;(关系 equalTo/greaterThan)"]
CMED["ConstraintMakerEditable&lt;br/&gt;(multipliedBy/offset/inset)"]
CMP["ConstraintMakerPrioritizable&lt;br/&gt;(priority)"]
CMF["ConstraintMakerFinalizable&lt;br/&gt;(labeled)"]
end
subgraph "描述 &amp; 协议层"
DESC["ConstraintDescription&lt;br/&gt;(懒加载装配)"]
TARGETS["Target 协议族&lt;br/&gt;Relatable/Constant/Offset&lt;br/&gt;Inset/Multiplier/Priority"]
ATTR["ConstraintAttributes&lt;br/&gt;(OptionSet 位运算)"]
end
subgraph "约束层"
C["Constraint&lt;br/&gt;(封装一组 LayoutConstraint)"]
LC["LayoutConstraint&lt;br/&gt;(NSLayoutConstraint 子类)"]
ITEM["LayoutConstraintItem&lt;br/&gt;(UIView/UILayoutGuide)"]
end
subgraph "系统层"
NSLC["NSLayoutConstraint.activate"]
end
V --&gt;|扩展属性| SNP
SNP --&gt; MK
MK --&gt;|创建| CM
CM --&gt;|返回| CME
CME --&gt;|继承| CMR
CMR --&gt;|equalTo| CMED
CMED --&gt;|继承| CMP
CMP --&gt;|priority| CMF
CM -.写入.-&gt; DESC
CME &amp; CMR &amp; CMED &amp; CMP &amp; CMF -.读写.-&gt; DESC
DESC -.lazy 构建.-&gt; C
C --&gt; LC
C -.关联对象.-&gt; ITEM
DESC -.使用.-&gt; ATTR
CMR -.类型匹配.-&gt; TARGETS
C --&gt; NSLC
&lt;/pre&gt;
&lt;h3 id="源码目录sources约-3500-行"&gt;源码目录（&lt;code&gt;Sources/&lt;/code&gt;，约 3500 行）&lt;/h3&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-gdscript3" data-lang="gdscript3"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;Sources&lt;span style="color:#f92672"&gt;/&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#960050;background-color:#1e0010"&gt;├──&lt;/span&gt; ConstraintView&lt;span style="color:#f92672"&gt;.&lt;/span&gt;swift &lt;span style="color:#75715e"&gt;# typealias UIView/NSView → ConstraintView&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#960050;background-color:#1e0010"&gt;├──&lt;/span&gt; ConstraintLayoutGuide&lt;span style="color:#f92672"&gt;.&lt;/span&gt;swift &lt;span style="color:#75715e"&gt;# typealias UILayoutGuide/NSLayoutGuide&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#960050;background-color:#1e0010"&gt;├──&lt;/span&gt; ConstraintLayoutSupport&lt;span style="color:#f92672"&gt;.&lt;/span&gt;swift &lt;span style="color:#75715e"&gt;# typealias UILayoutSupport&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#960050;background-color:#1e0010"&gt;├──&lt;/span&gt; Typealiases&lt;span style="color:#f92672"&gt;.&lt;/span&gt;swift &lt;span style="color:#75715e"&gt;# LayoutRelation / LayoutAttribute / LayoutPriority&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#960050;background-color:#1e0010"&gt;├──&lt;/span&gt; ConstraintConfig&lt;span style="color:#f92672"&gt;.&lt;/span&gt;swift &lt;span style="color:#75715e"&gt;# interfaceLayoutDirection 全局开关&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#960050;background-color:#1e0010"&gt;│&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#960050;background-color:#1e0010"&gt;├──&lt;/span&gt; ConstraintView&lt;span style="color:#f92672"&gt;+&lt;/span&gt;Extensions&lt;span style="color:#f92672"&gt;.&lt;/span&gt;swift &lt;span style="color:#75715e"&gt;# view.snp 入口（含 snp_ 老别名）&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#960050;background-color:#1e0010"&gt;├──&lt;/span&gt; ConstraintLayoutGuide&lt;span style="color:#f92672"&gt;+&lt;/span&gt;Extensions&lt;span style="color:#f92672"&gt;.&lt;/span&gt;swift &lt;span style="color:#75715e"&gt;# guide.snp 入口&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#960050;background-color:#1e0010"&gt;├──&lt;/span&gt; UILayoutSupport&lt;span style="color:#f92672"&gt;+&lt;/span&gt;Extensions&lt;span style="color:#f92672"&gt;.&lt;/span&gt;swift &lt;span style="color:#75715e"&gt;# topLayoutGuide.snp（iOS 11 前）&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#960050;background-color:#1e0010"&gt;├──&lt;/span&gt; ConstraintViewDSL&lt;span style="color:#f92672"&gt;.&lt;/span&gt;swift &lt;span style="color:#75715e"&gt;# makeConstraints / remake / update / remove&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#960050;background-color:#1e0010"&gt;├──&lt;/span&gt; ConstraintLayoutGuideDSL&lt;span style="color:#f92672"&gt;.&lt;/span&gt;swift &lt;span style="color:#75715e"&gt;# LayoutGuide 版 DSL&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#960050;background-color:#1e0010"&gt;├──&lt;/span&gt; ConstraintLayoutSupportDSL&lt;span style="color:#f92672"&gt;.&lt;/span&gt;swift &lt;span style="color:#75715e"&gt;# LayoutSupport 版 DSL&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#960050;background-color:#1e0010"&gt;├──&lt;/span&gt; ConstraintDSL&lt;span style="color:#f92672"&gt;.&lt;/span&gt;swift &lt;span style="color:#75715e"&gt;# DSL 协议 + 属性定义（left/top/edges/...）&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#960050;background-color:#1e0010"&gt;│&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#960050;background-color:#1e0010"&gt;├──&lt;/span&gt; ConstraintMaker&lt;span style="color:#f92672"&gt;.&lt;/span&gt;swift &lt;span style="color:#75715e"&gt;# 属性起点（make.left / make.edges / ...）&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#960050;background-color:#1e0010"&gt;├──&lt;/span&gt; ConstraintMakerExtendable&lt;span style="color:#f92672"&gt;.&lt;/span&gt;swift &lt;span style="color:#75715e"&gt;# 可追加属性（.top.right）&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#960050;background-color:#1e0010"&gt;├──&lt;/span&gt; ConstraintMakerRelatable&lt;span style="color:#f92672"&gt;.&lt;/span&gt;swift &lt;span style="color:#75715e"&gt;# equalTo / lessThanOrEqual / greaterThanOrEqual&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#960050;background-color:#1e0010"&gt;├──&lt;/span&gt; ConstraintMakerRelatable&lt;span style="color:#f92672"&gt;+&lt;/span&gt;Extensions&lt;span style="color:#f92672"&gt;.&lt;/span&gt;swift &lt;span style="color:#75715e"&gt;# equalToSuperview 闭包版&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#960050;background-color:#1e0010"&gt;├──&lt;/span&gt; ConstraintMakerEditable&lt;span style="color:#f92672"&gt;.&lt;/span&gt;swift &lt;span style="color:#75715e"&gt;# multipliedBy / dividedBy / offset / inset&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#960050;background-color:#1e0010"&gt;├──&lt;/span&gt; ConstraintMakerPrioritizable&lt;span style="color:#f92672"&gt;.&lt;/span&gt;swift &lt;span style="color:#75715e"&gt;# priority(...)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#960050;background-color:#1e0010"&gt;├──&lt;/span&gt; ConstraintMakerFinalizable&lt;span style="color:#f92672"&gt;.&lt;/span&gt;swift &lt;span style="color:#75715e"&gt;# labeled(...) + .constraint&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#960050;background-color:#1e0010"&gt;│&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#960050;background-color:#1e0010"&gt;├──&lt;/span&gt; ConstraintAttributes&lt;span style="color:#f92672"&gt;.&lt;/span&gt;swift &lt;span style="color:#75715e"&gt;# OptionSet 属性位图&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#960050;background-color:#1e0010"&gt;├──&lt;/span&gt; ConstraintRelation&lt;span style="color:#f92672"&gt;.&lt;/span&gt;swift &lt;span style="color:#75715e"&gt;# equal / lessThanOrEqual / greaterThanOrEqual&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#960050;background-color:#1e0010"&gt;├──&lt;/span&gt; ConstraintPriority&lt;span style="color:#f92672"&gt;.&lt;/span&gt;swift &lt;span style="color:#75715e"&gt;# required/high/medium/low&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#960050;background-color:#1e0010"&gt;├──&lt;/span&gt; ConstraintDescription&lt;span style="color:#f92672"&gt;.&lt;/span&gt;swift &lt;span style="color:#75715e"&gt;# Builder 中间态 + lazy Constraint&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#960050;background-color:#1e0010"&gt;├──&lt;/span&gt; ConstraintItem&lt;span style="color:#f92672"&gt;.&lt;/span&gt;swift &lt;span style="color:#75715e"&gt;# (target, attributes) 二元组（弱引用）&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#960050;background-color:#1e0010"&gt;├──&lt;/span&gt; LayoutConstraintItem&lt;span style="color:#f92672"&gt;.&lt;/span&gt;swift &lt;span style="color:#75715e"&gt;# UIView/UILayoutGuide 统一协议&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#960050;background-color:#1e0010"&gt;├──&lt;/span&gt; ConstraintInsets&lt;span style="color:#f92672"&gt;.&lt;/span&gt;swift &lt;span style="color:#75715e"&gt;# UIEdgeInsets typealias&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#960050;background-color:#1e0010"&gt;├──&lt;/span&gt; ConstraintDirectionalInsets&lt;span style="color:#f92672"&gt;.&lt;/span&gt;swift &lt;span style="color:#75715e"&gt;# NSDirectionalEdgeInsets（iOS 11+）&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#960050;background-color:#1e0010"&gt;│&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#960050;background-color:#1e0010"&gt;├──&lt;/span&gt; ConstraintRelatableTarget&lt;span style="color:#f92672"&gt;.&lt;/span&gt;swift &lt;span style="color:#75715e"&gt;# 可作为 equalTo 参数的类型标记&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#960050;background-color:#1e0010"&gt;├──&lt;/span&gt; ConstraintConstantTarget&lt;span style="color:#f92672"&gt;.&lt;/span&gt;swift &lt;span style="color:#75715e"&gt;# constant 目标 + 属性→CGFloat 的派发&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#960050;background-color:#1e0010"&gt;├──&lt;/span&gt; ConstraintOffsetTarget&lt;span style="color:#f92672"&gt;.&lt;/span&gt;swift &lt;span style="color:#75715e"&gt;# offset 目标&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#960050;background-color:#1e0010"&gt;├──&lt;/span&gt; ConstraintInsetTarget&lt;span style="color:#f92672"&gt;.&lt;/span&gt;swift &lt;span style="color:#75715e"&gt;# inset 目标（含标量→insets 转换）&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#960050;background-color:#1e0010"&gt;├──&lt;/span&gt; ConstraintDirectionalInsetTarget&lt;span style="color:#f92672"&gt;.&lt;/span&gt;swift &lt;span style="color:#75715e"&gt;# 方向 insets 目标&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#960050;background-color:#1e0010"&gt;├──&lt;/span&gt; ConstraintMultiplierTarget&lt;span style="color:#f92672"&gt;.&lt;/span&gt;swift &lt;span style="color:#75715e"&gt;# multiplier 目标&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#960050;background-color:#1e0010"&gt;├──&lt;/span&gt; ConstraintPriorityTarget&lt;span style="color:#f92672"&gt;.&lt;/span&gt;swift &lt;span style="color:#75715e"&gt;# priority 目标（Int/Float/UILayoutPriority）&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#960050;background-color:#1e0010"&gt;│&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#960050;background-color:#1e0010"&gt;├──&lt;/span&gt; Constraint&lt;span style="color:#f92672"&gt;.&lt;/span&gt;swift &lt;span style="color:#75715e"&gt;# 真正的约束对象 + activate/deactivate&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#960050;background-color:#1e0010"&gt;├──&lt;/span&gt; LayoutConstraint&lt;span style="color:#f92672"&gt;.&lt;/span&gt;swift &lt;span style="color:#75715e"&gt;# NSLayoutConstraint 子类，回指 Constraint&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#960050;background-color:#1e0010"&gt;├──&lt;/span&gt; Debugging&lt;span style="color:#f92672"&gt;.&lt;/span&gt;swift &lt;span style="color:#75715e"&gt;# LayoutConstraint.description 美化&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#960050;background-color:#1e0010"&gt;└──&lt;/span&gt; PrivacyInfo&lt;span style="color:#f92672"&gt;.&lt;/span&gt;xcprivacy &lt;span style="color:#75715e"&gt;# 隐私清单&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h3 id="核心设计思想"&gt;核心设计思想&lt;/h3&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;模式&lt;/th&gt;
&lt;th&gt;作用&lt;/th&gt;
&lt;th&gt;源码体现&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;阶段化 Builder&lt;/strong&gt;（Staged Builder / Step Builder）&lt;/td&gt;
&lt;td&gt;通过继承链控制链式调用的合法顺序，让 &lt;code&gt;make.left.offset(10).equalTo(...)&lt;/code&gt; 这类非法组合在编译期报错&lt;/td&gt;
&lt;td&gt;&lt;code&gt;ConstraintMaker → Extendable → Relatable → Editable → Prioritizable → Finalizable&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;协议 + 类型擦除&lt;/strong&gt;（POP）&lt;/td&gt;
&lt;td&gt;让 &lt;code&gt;Int / Float / CGFloat / CGSize / CGPoint / UIEdgeInsets / UIView / ConstraintItem&lt;/code&gt; 等异构类型可以统一作为 &lt;code&gt;equalTo&lt;/code&gt; / &lt;code&gt;offset&lt;/code&gt; / &lt;code&gt;priority&lt;/code&gt; 的参数&lt;/td&gt;
&lt;td&gt;&lt;code&gt;Constraint*Target&lt;/code&gt; 协议族&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;OptionSet 位运算&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;用 32 位整型表达「属性集合」，&lt;code&gt;.edges = [.left, .top, .right, .bottom]&lt;/code&gt; 这类聚合用位或实现，避免反复建数组&lt;/td&gt;
&lt;td&gt;&lt;code&gt;ConstraintAttributes&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Associated Object&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;在不污染 &lt;code&gt;UIView&lt;/code&gt; 原类的前提下，为每个 View 绑定「它持有的 SnapKit Constraint 集合」和「snp.label」&lt;/td&gt;
&lt;td&gt;&lt;code&gt;LayoutConstraintItem.constraintsSet&lt;/code&gt; + &lt;code&gt;ConstraintDSL.setLabel&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Lazy 求值&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;ConstraintDescription.constraint&lt;/code&gt; 是 &lt;code&gt;lazy var&lt;/code&gt;，闭包执行结束前只是收集参数，真正的 &lt;code&gt;Constraint&lt;/code&gt; 构造和 &lt;code&gt;NSLayoutConstraint&lt;/code&gt; 生成都推迟到最后&lt;/td&gt;
&lt;td&gt;&lt;code&gt;ConstraintDescription.constraint&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;跨平台 typealias&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;通过一组 typealias 把 iOS / macOS / tvOS 的 &lt;code&gt;UIView&lt;/code&gt;/&lt;code&gt;NSView&lt;/code&gt;、&lt;code&gt;UIEdgeInsets&lt;/code&gt;/&lt;code&gt;NSEdgeInsets&lt;/code&gt;、&lt;code&gt;UILayoutPriority&lt;/code&gt;/&lt;code&gt;NSLayoutConstraint.Priority&lt;/code&gt; 等抹平&lt;/td&gt;
&lt;td&gt;&lt;code&gt;ConstraintView.swift&lt;/code&gt; / &lt;code&gt;Typealiases.swift&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;hr&gt;
&lt;h2 id="二dsl-入口viewsnp"&gt;二、DSL 入口：&lt;code&gt;view.snp&lt;/code&gt;&lt;/h2&gt;
&lt;p&gt;SnapKit 没有像 Masonry 那样污染 &lt;code&gt;UIView&lt;/code&gt; 的命名空间，而是通过一个&lt;strong&gt;命名空间结构体&lt;/strong&gt;暴露 DSL。&lt;/p&gt;</description></item><item><title>启动优化-减少动态库</title><link>https://amatsuzero.github.io/LastStand/posts/interview/ios-performance/launch-%E5%87%8F%E5%B0%91%E5%8A%A8%E6%80%81%E5%BA%93/</link><pubDate>Sat, 02 May 2026 22:32:27 +0800</pubDate><guid>https://amatsuzero.github.io/LastStand/posts/interview/ios-performance/launch-%E5%87%8F%E5%B0%91%E5%8A%A8%E6%80%81%E5%BA%93/</guid><description>&lt;p&gt;动态库加载是Pre-main阶段的重要组成部分，每个动态库都需要加载、验证签名、进行符号绑定，这些操作会显著影响启动时间。&lt;/p&gt;
&lt;hr&gt;
&lt;h2 id="问题分析"&gt;问题分析&lt;/h2&gt;
&lt;p&gt;当App启动时，dyld需要：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;分析Mach-O文件的Load Commands，找出依赖的动态库&lt;/li&gt;
&lt;li&gt;递归加载所有依赖的动态库&lt;/li&gt;
&lt;li&gt;对每个动态库进行签名验证&lt;/li&gt;
&lt;li&gt;执行Rebase和Bind操作&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;动态库数量越多，这些操作的耗时就越长。Apple建议将自定义动态库数量控制在6个以内。关于动态库加载的详细流程，可以参考&lt;a href="https://amatsuzero.github.io/LastStand/posts/interview/ios-basics/mach-o%E7%9A%84%E9%93%BE%E6%8E%A5-%E8%A3%85%E8%BD%BD%E4%B8%8E%E5%BA%93/"&gt;Mach-O的链接、装载与库&lt;/a&gt;。&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;关于缓存机制&lt;/strong&gt;：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;系统动态库&lt;/strong&gt;：已被放入 dyld shared cache 中，其加载和符号绑定操作已预先完成，不会影响 App 启动时间&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;App 动态库&lt;/strong&gt;：dyld 3 引入的 Launch Closure 机制会缓存依赖分析、Rebase/Bind 信息等元数据。首次启动（或 App 更新后）会生成缓存，后续启动直接使用&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;但即使有 Launch Closure 缓存，&lt;strong&gt;Rebase/Bind 操作本身仍需执行&lt;/strong&gt;（因为 ASLR slide 每次启动都不同），动态库数量越多，这些操作的耗时仍然越长。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-plaintext" data-lang="plaintext"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;App可执行文件
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; ├── UIKit.framework
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; │ ├── Foundation.framework
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; │ │ └── CoreFoundation.framework
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; │ └── CoreGraphics.framework
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; ├── 自定义Framework A
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; │ └── 依赖库...
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; └── 自定义Framework B
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; └── 依赖库...
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;hr&gt;
&lt;h2 id="优化方案"&gt;优化方案&lt;/h2&gt;
&lt;h3 id="1-合并动态库"&gt;1. 合并动态库&lt;/h3&gt;
&lt;p&gt;将功能相近的动态库合并为一个：&lt;/p&gt;</description></item><item><title>iOS中import详解</title><link>https://amatsuzero.github.io/LastStand/posts/interview/ios-basics/objective-c%E4%B8%ADimport%E8%AF%A6%E8%A7%A3/</link><pubDate>Mon, 08 Jun 2026 23:06:52 +0800</pubDate><guid>https://amatsuzero.github.io/LastStand/posts/interview/ios-basics/objective-c%E4%B8%ADimport%E8%AF%A6%E8%A7%A3/</guid><description>&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;源码版本说明&lt;/strong&gt;：本文涉及的源码基于 &lt;strong&gt;LLVM/Clang 23.0.0&lt;/strong&gt; 开发版本（llvm-project main分支，commit: &lt;code&gt;301c0d91b558&lt;/code&gt;，2026-01-16）。不同版本的实现细节可能略有差异，但核心机制保持一致。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;在Objective-C开发中，头文件引用是日常开发中最基础的操作之一。本文将从Clang编译器的角度，深入讲解iOS中各种import方式的区别、底层查找原理以及最佳实践。&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;引用方式&lt;/th&gt;
&lt;th&gt;语法示例&lt;/th&gt;
&lt;th&gt;适用场景&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;#include&lt;/td&gt;
&lt;td&gt;&lt;code&gt;#include &amp;quot;Header.h&amp;quot;&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;C/C++传统方式&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;#import&lt;/td&gt;
&lt;td&gt;&lt;code&gt;#import &amp;quot;Header.h&amp;quot;&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Objective-C项目内部引用&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;#import&lt;/td&gt;
&lt;td&gt;&lt;code&gt;#import &amp;lt;Framework/Header.h&amp;gt;&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;系统/第三方Framework&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;@import&lt;/td&gt;
&lt;td&gt;&lt;code&gt;@import Foundation;&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Clang Modules方式&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;PCH&lt;/td&gt;
&lt;td&gt;Prefix Header文件&lt;/td&gt;
&lt;td&gt;预编译公共头文件&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;h2 id="include-vs-import"&gt;#include vs #import&lt;/h2&gt;
&lt;h3 id="include的工作原理"&gt;#include的工作原理&lt;/h3&gt;
&lt;p&gt;&lt;code&gt;#include&lt;/code&gt;是C/C++中的头文件引用方式，它的工作原理非常简单：&lt;strong&gt;预处理器会将目标头文件的内容原封不动地复制粘贴到当前文件中&lt;/strong&gt;。&lt;/p&gt;
&lt;p&gt;这种方式存在一个问题：&lt;strong&gt;重复引用&lt;/strong&gt;。如果多个文件都include了同一个头文件，或者存在循环引用，会导致编译错误。传统的解决方案是使用&lt;strong&gt;Include Guard&lt;/strong&gt;：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-c" data-lang="c"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;// Header.h
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;#ifndef HEADER_H
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;#define HEADER_H
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;// 头文件内容
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;#endif
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;现代编译器还支持&lt;code&gt;#pragma once&lt;/code&gt;指令，功能相同但更简洁：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-c" data-lang="c"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;// Header.h
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;#pragma once
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;// 头文件内容
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h3 id="import的增强"&gt;#import的增强&lt;/h3&gt;
&lt;p&gt;&lt;code&gt;#import&lt;/code&gt;是Objective-C对&lt;code&gt;#include&lt;/code&gt;的封装和增强。它在&lt;code&gt;#include&lt;/code&gt;的基础上增加了一层&lt;strong&gt;判重逻辑&lt;/strong&gt;，自动防止同一个头文件被重复引用。&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-objective-c" data-lang="objective-c"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;// BClass.m
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;#import &amp;#34;AClass.h&amp;#34;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;#import &amp;#34;AClass.h&amp;#34; &lt;/span&gt;&lt;span style="color:#75715e"&gt;// 第二次import会被自动忽略
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h3 id="双引号-vs-尖括号"&gt;双引号 vs 尖括号&lt;/h3&gt;
&lt;p&gt;在日常开发中，我们经常会看到两种不同的引用方式：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-objective-c" data-lang="objective-c"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;#import &amp;#34;MyClass.h&amp;#34; &lt;/span&gt;&lt;span style="color:#75715e"&gt;// 双引号形式
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;#import &amp;lt;UIKit/UIKit.h&amp;gt; &lt;/span&gt;&lt;span style="color:#75715e"&gt;// 尖括号形式
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;它们的核心区别在于&lt;strong&gt;搜索路径的范围不同&lt;/strong&gt;：&lt;/p&gt;</description></item><item><title>objc4 Protocol 结构、注册与查询</title><link>https://amatsuzero.github.io/LastStand/posts/ocsourcecodeanalysis/protocol-runtime-explained/</link><pubDate>Mon, 01 Jun 2026 19:50:12 +0800</pubDate><guid>https://amatsuzero.github.io/LastStand/posts/ocsourcecodeanalysis/protocol-runtime-explained/</guid><description>&lt;h2 id="目录"&gt;目录&lt;/h2&gt;
&lt;p&gt;&lt;a href="#role"&gt;1. Protocol 的作用&lt;/a&gt; &lt;a href="#model"&gt;2. 核心结构&lt;/a&gt; &lt;a href="#load"&gt;3. read_images 读取协议&lt;/a&gt; &lt;a href="#remap"&gt;4. remap 与重复协议&lt;/a&gt; &lt;a href="#query"&gt;5. 查询与 conforms 判断&lt;/a&gt; &lt;a href="#dynamic"&gt;6. 动态创建与注册&lt;/a&gt; &lt;a href="#tests"&gt;7. 测试体现的行为&lt;/a&gt; &lt;a href="#summary"&gt;8. 总结&lt;/a&gt;&lt;/p&gt;
&lt;h2 id="1-protocol-的作用"&gt;1. Protocol 的作用&lt;/h2&gt;
&lt;p&gt;在 objc4 中，&lt;code&gt;Protocol *&lt;/code&gt; 并不是一个只有名字的轻量句柄，而是运行时管理的一类 Objective-C 对象。 它承载协议名、继承的协议列表、必需/可选方法列表、实例/类属性列表等元数据。类、分类和协议自身都可以引用这些对象。&lt;/p&gt;
&lt;p&gt;对外 API 位于 &lt;code&gt;runtime/runtime.h&lt;/code&gt; 的 “Working with Protocols” 区域，例如 &lt;code&gt;objc_getProtocol&lt;/code&gt;、&lt;code&gt;objc_copyProtocolList&lt;/code&gt;、&lt;code&gt;protocol_conformsToProtocol&lt;/code&gt;、 &lt;code&gt;protocol_getMethodDescription&lt;/code&gt;、&lt;code&gt;objc_allocateProtocol&lt;/code&gt; 与 &lt;code&gt;objc_registerProtocol&lt;/code&gt;。 &lt;code&gt;runtime/Protocol.mm&lt;/code&gt; 中的 &lt;code&gt;@implementation Protocol&lt;/code&gt; 则把老式 Objective-C 消息转接到这些 C API。&lt;/p&gt;
&lt;p&gt;关键心智模型：编译器把协议写进镜像的 &lt;code&gt;__objc_protolist&lt;/code&gt; 等段；runtime 在 &lt;code&gt;_read_images&lt;/code&gt; 中发现并安装协议； 后续所有查询都尽量通过“协议名 =&amp;gt; 胜出的协议对象”来回到唯一的、当前有效的定义。&lt;/p&gt;
&lt;h2 id="2-核心结构"&gt;2. 核心结构&lt;/h2&gt;
&lt;p&gt;当前实现中的底层结构定义在 &lt;code&gt;runtime/objc-runtime-new.h&lt;/code&gt;。公开的 &lt;code&gt;Protocol *&lt;/code&gt; 在实现里经常通过 &lt;code&gt;newprotocol(p)&lt;/code&gt; 转成 &lt;code&gt;protocol_t *&lt;/code&gt; 使用。&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-javascript" data-lang="javascript"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;// runtime/objc-runtime-new.h，保留关键字段并加注释
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#a6e22e"&gt;typedef&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;uintptr_t&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;protocol_ref_t&lt;/span&gt;; &lt;span style="color:#75715e"&gt;// 尚未 remap 的 protocol_t *
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#a6e22e"&gt;struct&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;protocol_t&lt;/span&gt; &lt;span style="color:#f92672"&gt;:&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;objc_object&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;const&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;char&lt;/span&gt; &lt;span style="color:#f92672"&gt;*&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;mangledName&lt;/span&gt;; &lt;span style="color:#75715e"&gt;// 协议的运行时名字；Swift v1 可能是 mangled 名
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;struct&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;protocol_list_t&lt;/span&gt; &lt;span style="color:#f92672"&gt;*&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;protocols&lt;/span&gt;; &lt;span style="color:#75715e"&gt;// 该协议继承/组合的其他协议
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;method_list_t&lt;/span&gt; &lt;span style="color:#f92672"&gt;*&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;instanceMethods&lt;/span&gt;; &lt;span style="color:#75715e"&gt;// @required 实例方法
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;method_list_t&lt;/span&gt; &lt;span style="color:#f92672"&gt;*&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;classMethods&lt;/span&gt;; &lt;span style="color:#75715e"&gt;// @required 类方法
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;method_list_t&lt;/span&gt; &lt;span style="color:#f92672"&gt;*&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;optionalInstanceMethods&lt;/span&gt;; &lt;span style="color:#75715e"&gt;// @optional 实例方法
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;method_list_t&lt;/span&gt; &lt;span style="color:#f92672"&gt;*&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;optionalClassMethods&lt;/span&gt;; &lt;span style="color:#75715e"&gt;// @optional 类方法
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;property_list_t&lt;/span&gt; &lt;span style="color:#f92672"&gt;*&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;instanceProperties&lt;/span&gt;; &lt;span style="color:#75715e"&gt;// required instance properties
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;uint32_t&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;size&lt;/span&gt;; &lt;span style="color:#75715e"&gt;// 磁盘结构大小；用于判断尾部字段是否存在
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;uint32_t&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;flags&lt;/span&gt;; &lt;span style="color:#75715e"&gt;// fixed-up、canonical 等运行时标志
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#75715e"&gt;// 以下字段不是所有磁盘协议结构都有，访问前必须看 size。
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;const&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;char&lt;/span&gt; &lt;span style="color:#f92672"&gt;**&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;_extendedMethodTypes&lt;/span&gt;; &lt;span style="color:#75715e"&gt;// 扩展类型编码
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;const&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;char&lt;/span&gt; &lt;span style="color:#f92672"&gt;*&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;_demangledName&lt;/span&gt;; &lt;span style="color:#75715e"&gt;// Swift demangled 名称缓存
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;property_list_t&lt;/span&gt; &lt;span style="color:#f92672"&gt;*&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;_classProperties&lt;/span&gt;; &lt;span style="color:#75715e"&gt;// 类属性列表
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;};
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#a6e22e"&gt;struct&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;protocol_list_t&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;uintptr_t&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;count&lt;/span&gt;; &lt;span style="color:#75715e"&gt;// 历史原因：count 是指针宽度
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;protocol_ref_t&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;list&lt;/span&gt;[&lt;span style="color:#ae81ff"&gt;0&lt;/span&gt;]; &lt;span style="color:#75715e"&gt;// 变长数组；元素可能需要 remap
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;};
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h3 id="关键字段与方法"&gt;关键字段与方法&lt;/h3&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;&lt;/th&gt;
&lt;th&gt;&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;mangledName&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;全局协议表的 key。&lt;code&gt;objc_getProtocol&lt;/code&gt; 先按原名查，再查 dyld 预优化表，再尝试 Swift v1 mangled 等价名。&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;protocols&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;协议继承关系。&lt;code&gt;protocol_conformsToProtocol&lt;/code&gt; 会递归遍历它；&lt;code&gt;protocol_copyProtocolList&lt;/code&gt; 只复制直接继承项。&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;四个方法列表&lt;/td&gt;
&lt;td&gt;按 required/optional 与 instance/class 分成四组。&lt;code&gt;protocol_copyMethodDescriptionList&lt;/code&gt; 只返回当前协议直接声明的方法，不包含父协议。&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;size&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;兼容小协议或旧 ABI 的关键字段。&lt;code&gt;protocolSmall.m&lt;/code&gt; 手工构造较小结构，验证访问尾部字段前必须判定字段是否存在。&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;flags&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;高位用于 &lt;code&gt;PROTOCOL_FIXED_UP_*&lt;/code&gt; 与 &lt;code&gt;PROTOCOL_IS_CANONICAL&lt;/code&gt;，标记是否已修正以及共享缓存中的 canonical 定义。&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;h3 id="protocol-类"&gt;&lt;code&gt;Protocol&lt;/code&gt; 类&lt;/h3&gt;
&lt;p&gt;&lt;code&gt;runtime/Protocol.h&lt;/code&gt; 只暴露不可直接使用的 &lt;code&gt;@interface Protocol&lt;/code&gt;； &lt;code&gt;Protocol.mm&lt;/code&gt; 中 &lt;code&gt;-conformsTo:&lt;/code&gt;、&lt;code&gt;-name&lt;/code&gt;、&lt;code&gt;-isEqual:&lt;/code&gt; 分别调用 &lt;code&gt;protocol_conformsToProtocol&lt;/code&gt;、&lt;code&gt;protocol_getName&lt;/code&gt; 与 &lt;code&gt;protocol_isEqual&lt;/code&gt;。&lt;/p&gt;</description></item><item><title>APM-服务端数据架构</title><link>https://amatsuzero.github.io/LastStand/posts/interview/ios-apm/%E6%9C%8D%E5%8A%A1%E7%AB%AF%E6%95%B0%E6%8D%AE%E6%9E%B6%E6%9E%84/</link><pubDate>Thu, 07 May 2026 15:42:48 +0800</pubDate><guid>https://amatsuzero.github.io/LastStand/posts/interview/ios-apm/%E6%9C%8D%E5%8A%A1%E7%AB%AF%E6%95%B0%E6%8D%AE%E6%9E%B6%E6%9E%84/</guid><description>&lt;p&gt;APM 服务端本质上是一个面向移动端遥测数据的实时数据平台。它不是简单的“接收接口 + MySQL”，而要处理高吞吐写入、弱 Schema 演进、实时聚合、明细查询、符号化、Issue 聚类、告警计算和配置反控。&lt;/p&gt;
&lt;hr&gt;
&lt;h2 id="一整体架构"&gt;一、整体架构&lt;/h2&gt;
&lt;pre class="mermaid"&gt;flowchart TB
SDK["iOS SDK"] --&gt; Gateway["接入网关"]
Gateway --&gt; RawQueue["Raw Queue&lt;br/&gt;Kafka / Pulsar"]
RawQueue --&gt; Clean["清洗标准化&lt;br/&gt;Schema / 脱敏 / 维度补全"]
Clean --&gt; Stream["实时计算&lt;br/&gt;Flink / Spark Streaming"]
Clean --&gt; RawStore["原始冷存储&lt;br/&gt;OSS / HDFS / S3"]
Stream --&gt; DetailStore["明细存储&lt;br/&gt;ClickHouse / Doris"]
Stream --&gt; MetricStore["指标存储&lt;br/&gt;Prometheus / VictoriaMetrics / M3"]
Stream --&gt; SearchStore["搜索存储&lt;br/&gt;Elasticsearch / OpenSearch"]
Stream --&gt; IssueService["Issue 聚合服务"]
IssueService --&gt; Symbol["符号化服务"]
IssueService --&gt; Alert["告警服务"]
Alert --&gt; Notify["IM / Email / Phone / Webhook"]
DetailStore --&gt; Query["查询 API / BFF"]
MetricStore --&gt; Query
SearchStore --&gt; Query
IssueService --&gt; Query
Config["配置服务"] --&gt; SDK
&lt;/pre&gt;
&lt;p&gt;核心原则：&lt;/p&gt;</description></item><item><title>Swinject源码导读</title><link>https://amatsuzero.github.io/LastStand/posts/interview/ios-source-analysis/swinject%E6%BA%90%E7%A0%81%E5%AF%BC%E8%AF%BB/</link><pubDate>Sat, 02 May 2026 22:32:27 +0800</pubDate><guid>https://amatsuzero.github.io/LastStand/posts/interview/ios-source-analysis/swinject%E6%BA%90%E7%A0%81%E5%AF%BC%E8%AF%BB/</guid><description>&lt;p&gt;Swinject 是一款轻量级的 Swift 依赖注入（Dependency Injection）框架，灵感来自 .NET 的 Ninject。它通过&lt;strong&gt;类型安全的方式&lt;/strong&gt;管理对象之间的依赖关系，将对象的创建和使用解耦。本文基于 &lt;strong&gt;v2.8.3&lt;/strong&gt; 源码进行分析。&lt;/p&gt;
&lt;hr&gt;
&lt;h2 id="一整体架构"&gt;一、整体架构&lt;/h2&gt;
&lt;p&gt;Swinject 的核心设计围绕**注册-解析（Register-Resolve）**模式展开，整个框架仅约 20 个源码文件，代码极为精简。&lt;/p&gt;
&lt;pre class="mermaid"&gt;graph TB
subgraph "组织层"
A["Assembler"]
B["Assembly (Protocol)"]
end
subgraph "核心层"
C["Container"]
D["Resolver (Protocol)"]
end
subgraph "注册层"
E["ServiceEntry&amp;lt;Service&amp;gt;"]
F["ServiceKey"]
end
subgraph "作用域层"
G["ObjectScope"]
H["InstanceStorage (Protocol)"]
end
subgraph "存储实现"
I["TransientStorage"]
J["GraphStorage"]
K["PermanentStorage"]
L["WeakStorage"]
end
subgraph "包装器"
M["Lazy&amp;lt;Service&amp;gt;"]
N["Provider&amp;lt;Service&amp;gt;"]
end
A --&gt;|"管理"| B
B --&gt;|"assemble(container:)"| C
C --&gt;|"实现"| D
C --&gt;|"存储注册信息"| E
E --&gt;|"由 ServiceKey 索引"| F
E --&gt;|"关联"| G
G --&gt;|"创建"| H
H --- I
H --- J
H --- K
H --- L
C --&gt;|"延迟解析"| M
C --&gt;|"每次新建"| N
&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;源码文件结构：&lt;/strong&gt;&lt;/p&gt;</description></item><item><title>启动优化-观测</title><link>https://amatsuzero.github.io/LastStand/posts/interview/ios-performance/launch-%E8%A7%82%E6%B5%8B/</link><pubDate>Sat, 02 May 2026 22:32:27 +0800</pubDate><guid>https://amatsuzero.github.io/LastStand/posts/interview/ios-performance/launch-%E8%A7%82%E6%B5%8B/</guid><description>&lt;p&gt;准确测量启动时间是优化的前提。启动时间是用户体验的关键指标之一，研究表明，应用性能直接影响用户留存：页面加载时间每增加1秒，用户流失率会显著上升。对于iOS应用，需要在20秒内完成启动，否则可能会被watchdog强制终止。&lt;/p&gt;
&lt;p&gt;本文介绍如何测量和监控iOS应用的启动时间。关于启动流程的详细介绍，请参考 &lt;a href="https://amatsuzero.github.io/LastStand/posts/interview/ios-basics/app%E5%90%AF%E5%8A%A8%E6%B5%81%E7%A8%8B/"&gt;App启动流程&lt;/a&gt;。&lt;/p&gt;
&lt;hr&gt;
&lt;h2 id="一测量方式概览"&gt;一、测量方式概览&lt;/h2&gt;
&lt;p&gt;iOS 提供了多种测量启动时间的方式，适用于不同场景：&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;方式&lt;/th&gt;
&lt;th&gt;适用场景&lt;/th&gt;
&lt;th&gt;粒度&lt;/th&gt;
&lt;th&gt;是否需要代码&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;dyld 环境变量&lt;/td&gt;
&lt;td&gt;开发调试&lt;/td&gt;
&lt;td&gt;定性分析&lt;/td&gt;
&lt;td&gt;否&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Instruments App Launch&lt;/td&gt;
&lt;td&gt;深度分析&lt;/td&gt;
&lt;td&gt;函数级&lt;/td&gt;
&lt;td&gt;否&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;代码埋点&lt;/td&gt;
&lt;td&gt;开发调试 + 线上监控&lt;/td&gt;
&lt;td&gt;自定义&lt;/td&gt;
&lt;td&gt;是&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;MetricKit&lt;/td&gt;
&lt;td&gt;线上监控&lt;/td&gt;
&lt;td&gt;冷启动/热启动&lt;/td&gt;
&lt;td&gt;少量代码&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;hr&gt;
&lt;h2 id="二开发调试阶段"&gt;二、开发调试阶段&lt;/h2&gt;
&lt;h3 id="21-dyld-环境变量"&gt;2.1 dyld 环境变量&lt;/h3&gt;
&lt;p&gt;通过设置 dyld 环境变量可以在控制台查看启动过程中的加载信息：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-plaintext" data-lang="plaintext"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;Edit Scheme → Run → Arguments → Environment Variables
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;与启动测量相关的环境变量：&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;环境变量&lt;/th&gt;
&lt;th&gt;作用&lt;/th&gt;
&lt;th&gt;启动分析用途&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;DYLD_PRINT_LIBRARIES&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;打印每个加载的 mach-o 镜像&lt;/td&gt;
&lt;td&gt;查看动态库加载顺序，确认是否加载了不必要的库&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;DYLD_PRINT_LOADERS&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;打印镜像的加载器类型（JustInTimeLoader / PrebuiltLoader）&lt;/td&gt;
&lt;td&gt;分析是否使用了启动闭包优化&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;DYLD_PRINT_INITIALIZERS&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;打印每个 initializer 的执行&lt;/td&gt;
&lt;td&gt;查看 +load、constructor、C++ 静态构造函数的执行顺序&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;DYLD_PRINT_BINDINGS&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;打印每次符号绑定&lt;/td&gt;
&lt;td&gt;分析符号绑定情况（输出量很大）&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;DYLD_PRINT_SEARCHING&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;打印库搜索路径&lt;/td&gt;
&lt;td&gt;排查库加载问题&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;DYLD_PRINT_APIS&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;打印 dyld API 调用（如 dlopen）&lt;/td&gt;
&lt;td&gt;检测运行时动态加载行为&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;DYLD_PRINT_TO_FILE&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;将日志输出到指定文件&lt;/td&gt;
&lt;td&gt;避免控制台日志过多，方便后续分析&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;&lt;strong&gt;使用示例&lt;/strong&gt;：&lt;/p&gt;</description></item><item><title>微服务化架构详解</title><link>https://amatsuzero.github.io/LastStand/posts/interview/ios-architecture/%E5%BE%AE%E6%9C%8D%E5%8A%A1%E5%8C%96/</link><pubDate>Sat, 02 May 2026 22:32:27 +0800</pubDate><guid>https://amatsuzero.github.io/LastStand/posts/interview/ios-architecture/%E5%BE%AE%E6%9C%8D%E5%8A%A1%E5%8C%96/</guid><description>&lt;h2 id="什么是客户端微服务化"&gt;什么是客户端微服务化&lt;/h2&gt;
&lt;p&gt;微服务化是将后端微服务的思想应用到客户端，将App内部按&lt;strong&gt;业务域&lt;/strong&gt;拆分为多个独立服务。每个服务拥有独立的数据存储和业务逻辑，服务间通过定义良好的接口通信。&lt;/p&gt;
&lt;p&gt;微服务化的核心关注点是：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;业务域的逻辑划分&lt;/strong&gt;：按领域边界划分服务，而非按代码结构&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;运行时隔离&lt;/strong&gt;：服务在运行时保持独立，数据不互相污染&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;服务自治&lt;/strong&gt;：每个服务独立演进，对外提供稳定的契约&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id="客户端微服务化-vs-后端微服务"&gt;客户端微服务化 vs 后端微服务&lt;/h3&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;维度&lt;/th&gt;
&lt;th&gt;后端微服务&lt;/th&gt;
&lt;th&gt;客户端微服务化&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;部署&lt;/td&gt;
&lt;td&gt;独立部署、独立运行的进程&lt;/td&gt;
&lt;td&gt;同一App内的独立服务&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;通信&lt;/td&gt;
&lt;td&gt;HTTP/RPC/消息队列&lt;/td&gt;
&lt;td&gt;进程内通信（协议、事件总线）&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;数据库&lt;/td&gt;
&lt;td&gt;每个服务独立数据库&lt;/td&gt;
&lt;td&gt;每个服务独立数据存储空间&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;扩缩容&lt;/td&gt;
&lt;td&gt;水平扩展多实例&lt;/td&gt;
&lt;td&gt;不适用&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;故障隔离&lt;/td&gt;
&lt;td&gt;进程级隔离&lt;/td&gt;
&lt;td&gt;逻辑隔离（防御性编程）&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;核心目标&lt;/td&gt;
&lt;td&gt;独立部署、水平扩展&lt;/td&gt;
&lt;td&gt;业务域划分、运行时隔离&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;h3 id="微服务化与组件化的关系"&gt;微服务化与组件化的关系&lt;/h3&gt;
&lt;p&gt;微服务化和组件化是&lt;strong&gt;不同维度&lt;/strong&gt;的概念：&lt;/p&gt;
&lt;pre class="mermaid"&gt;flowchart TB
subgraph 组件化视角["组件化视角 (物理结构)"]
C1["首页组件"]
C2["商城组件"]
C3["用户组件"]
C4["订单组件"]
end
subgraph 微服务化视角["微服务化视角 (逻辑划分)"]
S1["用户服务"]
S2["交易服务"]
S3["内容服务"]
end
C3 -.-&gt;|"实现"| S1
C4 -.-&gt;|"实现"| S2
C2 -.-&gt;|"实现"| S2
C1 -.-&gt;|"实现"| S3
&lt;/pre&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;维度&lt;/th&gt;
&lt;th&gt;组件化&lt;/th&gt;
&lt;th&gt;微服务化&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;关注点&lt;/td&gt;
&lt;td&gt;代码的物理隔离、编译解耦&lt;/td&gt;
&lt;td&gt;业务域的逻辑划分、运行时隔离&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;划分依据&lt;/td&gt;
&lt;td&gt;功能模块、代码边界&lt;/td&gt;
&lt;td&gt;业务领域、数据边界&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;解决的问题&lt;/td&gt;
&lt;td&gt;编译依赖、团队协作、代码复用&lt;/td&gt;
&lt;td&gt;业务自治、数据隔离、服务演进&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;粒度&lt;/td&gt;
&lt;td&gt;可大可小（页面、功能模块）&lt;/td&gt;
&lt;td&gt;通常较粗（业务域）&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;&lt;strong&gt;实践中两者结合使用&lt;/strong&gt;：&lt;/p&gt;</description></item><item><title>编译优化-头文件与HMap</title><link>https://amatsuzero.github.io/LastStand/posts/interview/ios-build/%E5%A4%B4%E6%96%87%E4%BB%B6%E4%B8%8Ehmap/</link><pubDate>Sat, 02 May 2026 22:32:27 +0800</pubDate><guid>https://amatsuzero.github.io/LastStand/posts/interview/ios-build/%E5%A4%B4%E6%96%87%E4%BB%B6%E4%B8%8Ehmap/</guid><description>&lt;p&gt;对以 Objective-C 为主或混编的 iOS 大型工程，头文件查找是一个被严重低估的编译开销点。美团的统计显示，400+ Pod 组件的工程会产生近 5 万个头文件，导致海量的 IO 操作和编译参数膨胀。Header Map（HMap）技术能把头文件查找从 O(n) 的目录扫描退化为 O(1) 的哈希查表。&lt;/p&gt;
&lt;hr&gt;
&lt;h2 id="头文件查找的代价"&gt;头文件查找的代价&lt;/h2&gt;
&lt;h3 id="clang-的查找流程"&gt;Clang 的查找流程&lt;/h3&gt;
&lt;p&gt;当 Clang 遇到 &lt;code&gt;#import &amp;lt;AFNetworking/AFNetworking.h&amp;gt;&lt;/code&gt; 时：&lt;/p&gt;
&lt;pre class="mermaid"&gt;flowchart TD
A[遇到 #import] --&gt; B{是否系统头?}
B -- 是 --&gt; C[SYSTEM_HEADER_SEARCH_PATHS]
B -- 否 --&gt; D[USER_HEADER_SEARCH_PATHS]
C --&gt; E[按顺序遍历 HEADER_SEARCH_PATHS]
D --&gt; E
E --&gt; F{路径下有吗?}
F -- 否 --&gt; G[下一个路径]
G --&gt; E
F -- 是 --&gt; H[stat + open]
H --&gt; I[解析头文件]
&lt;/pre&gt;
&lt;p&gt;每一次查找都要对&lt;strong&gt;所有&lt;/strong&gt; &lt;code&gt;HEADER_SEARCH_PATHS&lt;/code&gt; 执行 &lt;code&gt;stat(2)&lt;/code&gt; 系统调用，当路径数量达到数千时，光 &lt;code&gt;stat&lt;/code&gt; 就是显著开销。&lt;/p&gt;</description></item><item><title>Tagged Pointer 对象实现讲解</title><link>https://amatsuzero.github.io/LastStand/posts/ocsourcecodeanalysis/tagged-pointer-explained/</link><pubDate>Mon, 01 Jun 2026 19:50:12 +0800</pubDate><guid>https://amatsuzero.github.io/LastStand/posts/ocsourcecodeanalysis/tagged-pointer-explained/</guid><description>&lt;p&gt;objc4 runtime internals&lt;/p&gt;
&lt;h1 id="tagged-pointer-对象"&gt;Tagged Pointer 对象&lt;/h1&gt;
&lt;p&gt;Tagged Pointer 是一种“指针即对象”的表示法：对象没有堆内存，类信息和 payload 直接编码在指针位中。objc4 对它提供了创建、取 tag、取 payload、取类、消息发送、禁用和混淆等完整路径。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;目录&lt;/strong&gt; &lt;a href="#why"&gt;作用&lt;/a&gt; &lt;a href="#layout"&gt;实现原理&lt;/a&gt; &lt;a href="#symbols"&gt;核心宏、结构、函数&lt;/a&gt; &lt;a href="#flows"&gt;关键流程&lt;/a&gt; &lt;a href="#tests"&gt;测试视角&lt;/a&gt; &lt;a href="#sources"&gt;源码依据&lt;/a&gt;&lt;/p&gt;
&lt;h2 id="作用"&gt;作用&lt;/h2&gt;
&lt;h3 id="减少堆分配"&gt;减少堆分配&lt;/h3&gt;
&lt;p&gt;小整数、短字符串、日期、索引路径等小对象可以直接塞进指针。&lt;code&gt;NSNumber&lt;/code&gt; 的小整数就是典型例子，&lt;code&gt;test/taggedNSPointers.m&lt;/code&gt; 验证了 &lt;code&gt;NSNumber numberWithInt:1234&lt;/code&gt; 是 tagged pointer。&lt;/p&gt;
&lt;h3 id="保留对象语义"&gt;保留对象语义&lt;/h3&gt;
&lt;p&gt;虽然指针不指向对象内存，它仍能接收消息、查询类、作为字典 key/value，并通过 Foundation/CF 桥接。运行时把 tag 映射到真实 Class 后，继续走常规方法缓存查找。&lt;/p&gt;
&lt;h3 id="绕开生命周期表"&gt;绕开生命周期表&lt;/h3&gt;
&lt;p&gt;&lt;code&gt;test/taggedPointers.m&lt;/code&gt; 验证 retain、release、autorelease、weak store/load 对 tagged pointer 不产生真实引用计数或弱引用表负担。它们本质上是立即值，不需要释放。&lt;/p&gt;
&lt;p&gt;**一句话：**Tagged Pointer 把“对象身份”改成“位编码值”。运行时需要做的，是在所有需要对象元数据的地方识别它，并把 tag 翻译成类。&lt;/p&gt;
&lt;h2 id="实现原理"&gt;实现原理&lt;/h2&gt;
&lt;p&gt;objc4 在 64 位平台启用 tagged pointer。&lt;code&gt;runtime/objc-config.h&lt;/code&gt; 中 &lt;code&gt;SUPPORT_TAGGED_POINTERS&lt;/code&gt; 对 &lt;code&gt;__LP64__&lt;/code&gt; 为 1；非 64 位平台关闭。tag 标记位在大多数平台使用 MSB，macOS x86_64 使用 LSB。arm64 还使用 split tagged pointer 布局。&lt;/p&gt;</description></item><item><title>编译优化-编译缓存</title><link>https://amatsuzero.github.io/LastStand/posts/interview/ios-build/%E7%BC%96%E8%AF%91%E7%BC%93%E5%AD%98/</link><pubDate>Fri, 08 May 2026 13:07:14 +0800</pubDate><guid>https://amatsuzero.github.io/LastStand/posts/interview/ios-build/%E7%BC%96%E8%AF%91%E7%BC%93%E5%AD%98/</guid><description>&lt;p&gt;&amp;ldquo;已经编译过的东西不再编译一遍&amp;rdquo;——这是编译优化的基础原理。Xcode 的增量编译、CocoaPods 的二进制缓存、Bazel 的 Action Cache 都是不同层次的编译缓存。本文聚焦 &lt;code&gt;ccache&lt;/code&gt;、Clang/Swift module cache、远程缓存等通用方案的原理与 iOS 落地。&lt;/p&gt;
&lt;hr&gt;
&lt;h2 id="缓存分层"&gt;缓存分层&lt;/h2&gt;
&lt;p&gt;缓存按命中粒度可以分为三个层次：&lt;/p&gt;
&lt;pre class="mermaid"&gt;flowchart TD
A[编译缓存] --&gt; B[编译器内部缓存&lt;br/&gt;PCH/PCM/module cache]
A --&gt; C[Action 级缓存&lt;br/&gt;ccache/sccache]
A --&gt; D[产物级缓存&lt;br/&gt;framework/xcframework]
B --&gt; B1[进程内复用模块]
C --&gt; C1[按 .o 粒度缓存]
D --&gt; D1[按 Pod/module 缓存]
&lt;/pre&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;层次&lt;/th&gt;
&lt;th&gt;粒度&lt;/th&gt;
&lt;th&gt;代表&lt;/th&gt;
&lt;th&gt;命中率&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;编译器内部&lt;/td&gt;
&lt;td&gt;frontend 解析结果&lt;/td&gt;
&lt;td&gt;Clang ModuleCache、Swift Module Cache&lt;/td&gt;
&lt;td&gt;高（本地）&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Action&lt;/td&gt;
&lt;td&gt;源文件 → 目标文件&lt;/td&gt;
&lt;td&gt;ccache、sccache、Bazel&lt;/td&gt;
&lt;td&gt;中（取决于参数稳定性）&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;产物&lt;/td&gt;
&lt;td&gt;整个 Pod 或 module&lt;/td&gt;
&lt;td&gt;cocoapods-bin、Rugby&lt;/td&gt;
&lt;td&gt;高（版本号稳定）&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;hr&gt;
&lt;h2 id="clang-module-cache"&gt;Clang Module Cache&lt;/h2&gt;
&lt;h3 id="原理"&gt;原理&lt;/h3&gt;
&lt;p&gt;Clang 的 &lt;code&gt;@import&lt;/code&gt; / &lt;code&gt;@_exported import&lt;/code&gt; 会把外部模块预编译成 &lt;code&gt;.pcm&lt;/code&gt;，缓存到 &lt;code&gt;ModuleCachePath&lt;/code&gt;：&lt;/p&gt;</description></item><item><title>iOS APM 与 RUM 体系总览</title><link>https://amatsuzero.github.io/LastStand/posts/interview/ios-apm/apm/</link><pubDate>Thu, 07 May 2026 15:42:48 +0800</pubDate><guid>https://amatsuzero.github.io/LastStand/posts/interview/ios-apm/apm/</guid><description>&lt;p&gt;APM（Application Performance Monitoring / Management）是面向线上真实用户的性能稳定性观测与治理体系。对 iOS App 来说，它不是一个单纯的 Crash SDK，也不是一个“把指标画成图”的后台，而是一套贯穿 &lt;strong&gt;C 端真实用户体验、端侧采集 SDK、服务端数据平台、B 端研发治理平台&lt;/strong&gt; 的完整系统。&lt;/p&gt;
&lt;p&gt;RUM（Real User Monitoring）是 APM 在真实用户体验侧的核心模型：把用户的一次使用会话拆成 &lt;code&gt;Session / View / Action / Resource / Error / LongTask&lt;/code&gt; 等对象，用统一 ID 串联页面、交互、网络、错误和性能现场。没有 RUM 模型，APM 很容易退化成一堆孤立指标；有了 RUM 模型，平台才能回答“哪个真实用户在什么页面做了什么操作，随后发生了什么性能或稳定性问题”。&lt;/p&gt;
&lt;hr&gt;
&lt;h2 id="一重构后的系列结构"&gt;一、重构后的系列结构&lt;/h2&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;文章&lt;/th&gt;
&lt;th&gt;定位&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;a href="https://amatsuzero.github.io/LastStand/posts/interview/ios-apm/apm/"&gt;APM&lt;/a&gt;（本文）&lt;/td&gt;
&lt;td&gt;系列入口：APM/RUM 定义、B/C 端边界、技术分层、建设路线&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;a href="https://amatsuzero.github.io/LastStand/posts/interview/ios-apm/%E4%BA%A7%E5%93%81%E4%B8%8E%E6%9E%B6%E6%9E%84%E8%AE%BE%E8%AE%A1/"&gt;APM-产品与架构设计&lt;/a&gt;&lt;/td&gt;
&lt;td&gt;产品视角：C 端体验、B 端用户、角色视图、治理闭环&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;a href="https://amatsuzero.github.io/LastStand/posts/interview/ios-apm/%E6%8C%87%E6%A0%87%E4%BD%93%E7%B3%BB/"&gt;APM-指标体系&lt;/a&gt;&lt;/td&gt;
&lt;td&gt;指标口径：稳定性、流畅性、启动、资源、网络、业务、RUM 指标&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;a href="https://amatsuzero.github.io/LastStand/posts/interview/ios-apm/c%E7%AB%AFsdk%E6%9E%B6%E6%9E%84/"&gt;APM-C端SDK架构&lt;/a&gt;&lt;/td&gt;
&lt;td&gt;iOS SDK 架构：插件化、远程配置、采样、隐私、低开销、防自崩&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;a href="https://amatsuzero.github.io/LastStand/posts/interview/ios-apm/%E6%95%B0%E6%8D%AE%E9%87%87%E9%9B%86/"&gt;APM-数据采集&lt;/a&gt;&lt;/td&gt;
&lt;td&gt;采集技术：Crash、Watchdog、FOOM、卡顿、启动、网络、MetricKit、业务 Trace&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;a href="https://amatsuzero.github.io/LastStand/posts/interview/ios-apm/%E6%95%B0%E6%8D%AE%E6%A8%A1%E5%9E%8B%E4%B8%8E%E4%B8%8A%E6%8A%A5/"&gt;APM-数据模型与上报&lt;/a&gt;&lt;/td&gt;
&lt;td&gt;事件模型、RUM ID、协议、落盘、批量、重试、脱敏、采样&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;a href="https://amatsuzero.github.io/LastStand/posts/interview/ios-apm/%E6%9C%8D%E5%8A%A1%E7%AB%AF%E6%95%B0%E6%8D%AE%E6%9E%B6%E6%9E%84/"&gt;APM-服务端数据架构&lt;/a&gt;&lt;/td&gt;
&lt;td&gt;接入网关、消息队列、实时计算、存储、符号化、Issue 聚合、配置下发&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;a href="https://amatsuzero.github.io/LastStand/posts/interview/ios-apm/b%E7%AB%AF%E5%B9%B3%E5%8F%B0%E8%AE%BE%E8%AE%A1/"&gt;APM-B端平台设计&lt;/a&gt;&lt;/td&gt;
&lt;td&gt;Web 控制台：大盘、详情页、用户会话、告警、工单、发布防劣化&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;a href="https://amatsuzero.github.io/LastStand/posts/interview/ios-apm/%E4%B8%9A%E7%95%8C%E6%96%B9%E6%A1%88/"&gt;APM-业界方案&lt;/a&gt;&lt;/td&gt;
&lt;td&gt;MetricKit、Sentry、Firebase、Bugly、Matrix、Slardar、Hertz 等方案对比&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;重构后的主线是：&lt;/p&gt;</description></item><item><title>Objective-C底层原理 - NSObject</title><link>https://amatsuzero.github.io/LastStand/posts/interview/ios-basics/objective-c%E5%BA%95%E5%B1%82%E5%8E%9F%E7%90%86-nsobject/</link><pubDate>Sat, 02 May 2026 22:32:27 +0800</pubDate><guid>https://amatsuzero.github.io/LastStand/posts/interview/ios-basics/objective-c%E5%BA%95%E5%B1%82%E5%8E%9F%E7%90%86-nsobject/</guid><description>&lt;p&gt;本文将深入探讨&lt;code&gt;Objective-C&lt;/code&gt;中所有对象的基类&lt;code&gt;NSObject&lt;/code&gt;的底层实现原理，涵盖对象本质、isa指针机制、Tagged Pointer、引用计数、内存布局等核心概念。&lt;/p&gt;
&lt;h2 id="nsobject-的本质c-结构体"&gt;NSObject 的本质：C 结构体&lt;/h2&gt;
&lt;p&gt;在&lt;code&gt;Objective-C&lt;/code&gt;的底层实现中，&lt;code&gt;NSObject&lt;/code&gt;的本质是一个&lt;code&gt;C&lt;/code&gt;结构体。在苹果运行时源码中可以看到：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-c" data-lang="c"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;// 底层运行时定义
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;struct&lt;/span&gt; objc_object {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; Class isa; &lt;span style="color:#75715e"&gt;// 指向对象所属类的指针
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;};
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;// 类型别名定义
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;typedef&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;struct&lt;/span&gt; objc_object NSObject;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;这意味着，当我们通过&lt;code&gt;NSObject *obj = [[NSObject alloc] init];&lt;/code&gt;创建一个 NSObject 实例时，实际上在堆上分配了一个&lt;code&gt;struct objc_object&lt;/code&gt;结构体，而变量&lt;code&gt;obj&lt;/code&gt;只是一个指向该结构体的指针。&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-objc" data-lang="objc"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;// 这行代码在底层实际上做了类似下面的事情：
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;NSObject &lt;span style="color:#f92672"&gt;*&lt;/span&gt;obj &lt;span style="color:#f92672"&gt;=&lt;/span&gt; [[NSObject alloc] init];
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;// 等效的伪C代码:
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;// 1. 调用 alloc 类方法，其核心是调用 malloc 在堆上分配一块足够大的内存
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;// 大小至少是 sizeof(struct objc_object)，即一个isa指针的大小
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;NSObject &lt;span style="color:#f92672"&gt;*&lt;/span&gt;obj &lt;span style="color:#f92672"&gt;=&lt;/span&gt; (NSObject &lt;span style="color:#f92672"&gt;*&lt;/span&gt;)malloc(&lt;span style="color:#66d9ef"&gt;sizeof&lt;/span&gt;(&lt;span style="color:#66d9ef"&gt;struct&lt;/span&gt; objc_object));
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;// 2. 初始化这块内存，最重要的是设置 isa 指针，让它指向 NSObject 这个类
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;obj&lt;span style="color:#f92672"&gt;-&amp;gt;&lt;/span&gt;isa &lt;span style="color:#f92672"&gt;=&lt;/span&gt; [NSObject &lt;span style="color:#66d9ef"&gt;class&lt;/span&gt;]; &lt;span style="color:#75715e"&gt;// 实际过程更复杂，但本质如此
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;// 3. 其他初始化工作 (init)
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;那么这里提到的&lt;code&gt;isa&lt;/code&gt;指针是什么呢？&lt;/p&gt;</description></item><item><title>Texture源码导读</title><link>https://amatsuzero.github.io/LastStand/posts/interview/ios-source-analysis/texture%E6%BA%90%E7%A0%81%E5%AF%BC%E8%AF%BB/</link><pubDate>Sat, 02 May 2026 22:32:27 +0800</pubDate><guid>https://amatsuzero.github.io/LastStand/posts/interview/ios-source-analysis/texture%E6%BA%90%E7%A0%81%E5%AF%BC%E8%AF%BB/</guid><description>&lt;blockquote&gt;
&lt;p&gt;TODO: 待补充&lt;/p&gt;
&lt;/blockquote&gt;</description></item><item><title>启动优化</title><link>https://amatsuzero.github.io/LastStand/posts/interview/ios-performance/launch-%E5%90%AF%E5%8A%A8%E4%BC%98%E5%8C%96/</link><pubDate>Sat, 02 May 2026 22:32:27 +0800</pubDate><guid>https://amatsuzero.github.io/LastStand/posts/interview/ios-performance/launch-%E5%90%AF%E5%8A%A8%E4%BC%98%E5%8C%96/</guid><description>&lt;p&gt;iOS应用的启动时间是用户体验的关键指标之一。研究表明，应用性能直接影响用户留存：页面加载时间每增加1秒，用户流失率会显著上升。对于iOS应用，需要在20秒内完成启动，否则可能会被watchdog强制终止。&lt;/p&gt;
&lt;p&gt;本系列文章从启动流程的各个阶段入手，系统性地介绍iOS启动优化的方法和实践。&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;启动监控是 APM 的重要子系，线上 P50/P90/P99 的采集、冷/温/热启动判定、以及与业务秒开指标的关联，请参考 &lt;a href="https://amatsuzero.github.io/LastStand/posts/interview/ios-apm/apm/"&gt;APM 系列&lt;/a&gt;：&lt;a href="https://amatsuzero.github.io/LastStand/posts/interview/ios-apm/%E6%8C%87%E6%A0%87%E4%BD%93%E7%B3%BB/"&gt;指标体系&lt;/a&gt;、&lt;a href="https://amatsuzero.github.io/LastStand/posts/interview/ios-apm/%E6%95%B0%E6%8D%AE%E9%87%87%E9%9B%86/"&gt;数据采集&lt;/a&gt;。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;hr&gt;
&lt;h2 id="启动流程概述"&gt;启动流程概述&lt;/h2&gt;
&lt;p&gt;&lt;a href="https://amatsuzero.github.io/LastStand/posts/interview/ios-basics/app%E5%90%AF%E5%8A%A8%E6%B5%81%E7%A8%8B/"&gt;App的启动流程&lt;/a&gt;分为两个主要阶段：&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;阶段&lt;/th&gt;
&lt;th&gt;时间范围&lt;/th&gt;
&lt;th&gt;主要工作&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Pre-main&lt;/td&gt;
&lt;td&gt;进程创建 → main()函数&lt;/td&gt;
&lt;td&gt;加载可执行文件、加载动态库、Rebase/Bind、ObjC Runtime初始化、Swift Runtime元数据注册、+load方法、Initializers&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;main&lt;/td&gt;
&lt;td&gt;main()函数 → 首帧渲染&lt;/td&gt;
&lt;td&gt;UIApplicationMain、AppDelegate回调、首帧渲染&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;pre class="mermaid"&gt;flowchart TD
Start([App 冷启动]) --&gt; PreMain
subgraph PreMain["Pre-main 阶段"]
direction TB
A[加载可执行文件&lt;br/&gt;创建进程、mmap映射、签名验证] --&gt; B[加载动态库&lt;br/&gt;递归加载依赖、包括 Swift Runtime]
B --&gt; C[Rebase &amp; Bind&lt;br/&gt;指针修正、符号绑定]
C --&gt; D[ObjC Runtime 初始化&lt;br/&gt;类注册、Category 附加]
D --&gt; E[Swift Runtime 元数据注册&lt;br/&gt;类型元数据、协议遵循表]
E --&gt; F[调用 +load 方法]
F --&gt; G[执行 Initializers&lt;br/&gt;C++静态构造函数、__attribute__]
end
PreMain --&gt; MainPhase
subgraph MainPhase["main 阶段"]
direction TB
H[main函数] --&gt; I[UIApplicationMain&lt;br/&gt;创建UIApplication、AppDelegate、启动RunLoop]
I --&gt; J[AppDelegate回调&lt;br/&gt;willFinish、didFinishLaunching]
J --&gt; K[首帧渲染&lt;br/&gt;创建Window、RootViewController、首屏UI]
end
MainPhase --&gt; End([启动完成])
&lt;/pre&gt;
&lt;hr&gt;
&lt;h2 id="文章导航"&gt;文章导航&lt;/h2&gt;
&lt;p&gt;本系列包含以下文章，建议按顺序阅读：&lt;/p&gt;</description></item><item><title>插件化架构详解</title><link>https://amatsuzero.github.io/LastStand/posts/interview/ios-architecture/%E6%8F%92%E4%BB%B6%E5%8C%96/</link><pubDate>Sat, 02 May 2026 22:32:27 +0800</pubDate><guid>https://amatsuzero.github.io/LastStand/posts/interview/ios-architecture/%E6%8F%92%E4%BB%B6%E5%8C%96/</guid><description>&lt;h2 id="什么是插件化"&gt;什么是插件化&lt;/h2&gt;
&lt;p&gt;在iOS开发中，&lt;strong&gt;插件化&lt;/strong&gt;通常指的是&lt;strong&gt;编译期插件化&lt;/strong&gt;，即通过壳工程（Shell Project）按需装配不同的业务组件，生成不同功能的App。这与Android的运行时插件化（动态加载代码）有本质区别。&lt;/p&gt;
&lt;h3 id="ios插件化-vs-android插件化"&gt;iOS插件化 vs Android插件化&lt;/h3&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;特性&lt;/th&gt;
&lt;th&gt;Android插件化&lt;/th&gt;
&lt;th&gt;iOS插件化&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;实现方式&lt;/td&gt;
&lt;td&gt;运行时动态加载APK/DEX&lt;/td&gt;
&lt;td&gt;编译期按需集成组件&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;代码热更新&lt;/td&gt;
&lt;td&gt;支持&lt;/td&gt;
&lt;td&gt;不支持（App Store限制）&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;主要目的&lt;/td&gt;
&lt;td&gt;绕过包大小限制、热修复&lt;/td&gt;
&lt;td&gt;多App复用、编译提效&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;技术难度&lt;/td&gt;
&lt;td&gt;高（Hook系统API）&lt;/td&gt;
&lt;td&gt;中（工程配置）&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;iOS的&amp;quot;插件化&amp;quot;主要体现在：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;壳工程设计&lt;/strong&gt;：一套代码支撑多个App&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;配置驱动集成&lt;/strong&gt;：通过配置文件决定集成哪些组件&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;二进制化提效&lt;/strong&gt;：稳定组件编译为二进制，减少编译时间&lt;/li&gt;
&lt;/ol&gt;
&lt;pre class="mermaid"&gt;flowchart TB
subgraph 组件库["组件仓库"]
A[用户组件]
B[商城组件]
C[直播组件]
D[社区组件]
E[基础组件]
end
subgraph 壳工程["壳工程 (Shell Project)"]
Config["配置文件"]
Shell["壳工程代码"]
end
subgraph Apps["生成的App"]
App1["App A&lt;br/&gt;(用户+商城+基础)"]
App2["App B&lt;br/&gt;(用户+直播+基础)"]
App3["App C&lt;br/&gt;(全量组件)"]
end
A &amp; B &amp; C &amp; D &amp; E --&gt; Config
Config --&gt;|"按需装配"| App1
Config --&gt;|"按需装配"| App2
Config --&gt;|"按需装配"| App3
&lt;/pre&gt;
&lt;h2 id="两种插件化实现方式"&gt;两种插件化实现方式&lt;/h2&gt;
&lt;p&gt;根据组件间通信方案的不同，iOS插件化有两种主要实现方式，它们的核心区别在于&lt;strong&gt;是否强制要求编译期隔离&lt;/strong&gt;：&lt;/p&gt;</description></item><item><title>objc4：isa_t、nonpointer isa、引用计数与 SideTable</title><link>https://amatsuzero.github.io/LastStand/posts/ocsourcecodeanalysis/isa-refcount-explained/</link><pubDate>Mon, 01 Jun 2026 19:50:12 +0800</pubDate><guid>https://amatsuzero.github.io/LastStand/posts/ocsourcecodeanalysis/isa-refcount-explained/</guid><description>&lt;h1 id="isa_tnonpointer-isa引用计数与-sidetable"&gt;isa_t、nonpointer isa、引用计数与 SideTable&lt;/h1&gt;
&lt;p&gt;本文基于 objc4 仓库中的 runtime 源码和相关测试，解释 Objective-C 对象头里的 &lt;code&gt;isa_t&lt;/code&gt; 如何同时承载类信息、引用计数、弱引用/关联对象标记，以及这些信息何时转移到 &lt;code&gt;SideTable&lt;/code&gt;。&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href="#role"&gt;作用&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="#layout"&gt;实现原理与位布局&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="#structures"&gt;核心结构和关键字段方法&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="#flows"&gt;关键流程&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="#tests"&gt;测试如何约束行为&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="1-作用"&gt;1. 作用&lt;/h2&gt;
&lt;p&gt;传统 Objective-C 对象的第一个机器字是 &lt;code&gt;isa&lt;/code&gt;，直接保存类指针。objc4 在支持 &lt;code&gt;SUPPORT_NONPOINTER_ISA&lt;/code&gt; 的平台上把这个机器字扩展为 &lt;code&gt;isa_t&lt;/code&gt;： 低位和高位保存状态，中间区域保存类信息。这样一次对象头访问就能拿到类、内联引用计数、 是否有弱引用、是否有关联对象、是否可能有 C++ 析构等信息。&lt;/p&gt;
&lt;h3 id="为什么要-nonpointer-isa"&gt;为什么要 nonpointer isa&lt;/h3&gt;
&lt;p&gt;对象绝大多数时候引用计数很小，把计数放进 &lt;code&gt;isa&lt;/code&gt; 可让 retain/release 走原子 CAS 快路径，避免进入全局散列表和锁。&lt;/p&gt;
&lt;h3 id="为什么仍需要-sidetable"&gt;为什么仍需要 SideTable&lt;/h3&gt;
&lt;p&gt;&lt;code&gt;isa&lt;/code&gt; 空间有限。引用计数溢出、raw isa 对象、弱引用表，以及 deallocating 状态的兼容存储，都需要 &lt;code&gt;SideTable&lt;/code&gt;。&lt;/p&gt;
&lt;h3 id="raw-isa-的存在原因"&gt;raw isa 的存在原因&lt;/h3&gt;
&lt;p&gt;类对象始终使用 raw pointer isa；某些类通过 &lt;code&gt;instancesRequireRawIsa()&lt;/code&gt; 或 运行时配置禁用 nonpointer isa；测试 &lt;code&gt;rawisa.m&lt;/code&gt; 还覆盖了 &lt;code&gt;__DATA,__objc_rawisa&lt;/code&gt; 段禁用 nonpointer isa 的场景。&lt;/p&gt;</description></item><item><title>编译优化-观测</title><link>https://amatsuzero.github.io/LastStand/posts/interview/ios-build/%E8%A7%82%E6%B5%8B/</link><pubDate>Tue, 05 May 2026 00:41:41 +0800</pubDate><guid>https://amatsuzero.github.io/LastStand/posts/interview/ios-build/%E8%A7%82%E6%B5%8B/</guid><description>&lt;p&gt;&amp;ldquo;无法度量就无法优化&amp;rdquo;。在开始任何编译优化动作之前，必须先建立一套可重复、可对比的观测手段，否则改动的真实收益无从谈起。本文介绍 iOS 编译耗时观测的主要工具链和原理。&lt;/p&gt;
&lt;hr&gt;
&lt;h2 id="观测目标分层"&gt;观测目标分层&lt;/h2&gt;
&lt;p&gt;不同层次的观测工具回答不同的问题：&lt;/p&gt;
&lt;pre class="mermaid"&gt;flowchart TD
A[编译耗时观测] --&gt; B[整体耗时]
A --&gt; C[阶段耗时]
A --&gt; D[任务级耗时]
A --&gt; E[函数/表达式级]
B --&gt; B1[xcodebuild 总耗时]
C --&gt; C1[Build Timing Summary]
C --&gt; C2[Pod Install 阶段计时]
D --&gt; D1[Build Timeline]
D --&gt; D2[XCLogParser]
E --&gt; E1[-debug-time-compilation]
E --&gt; E2[-warn-long-expression]
&lt;/pre&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;观测层次&lt;/th&gt;
&lt;th&gt;典型问题&lt;/th&gt;
&lt;th&gt;工具&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;整体&lt;/td&gt;
&lt;td&gt;一次构建花了多久？&lt;/td&gt;
&lt;td&gt;&lt;code&gt;time xcodebuild&lt;/code&gt;、MetricKit&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;阶段&lt;/td&gt;
&lt;td&gt;哪个阶段最慢？&lt;/td&gt;
&lt;td&gt;&lt;code&gt;-showBuildTimingSummary&lt;/code&gt;、Build Timing Summary&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;任务&lt;/td&gt;
&lt;td&gt;哪个文件/目标最慢？&lt;/td&gt;
&lt;td&gt;Xcode Build Timeline、XCLogParser&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;函数级&lt;/td&gt;
&lt;td&gt;哪个函数/表达式让前端卡住？&lt;/td&gt;
&lt;td&gt;&lt;code&gt;-debug-time-function-bodies&lt;/code&gt;、&lt;code&gt;-warn-long-expression-type-checking&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;hr&gt;
&lt;h2 id="整体耗时"&gt;整体耗时&lt;/h2&gt;
&lt;h3 id="xcodebuild-命令行计时"&gt;xcodebuild 命令行计时&lt;/h3&gt;
&lt;p&gt;最简单也最稳定的方式是直接给 &lt;code&gt;xcodebuild&lt;/code&gt; 加 &lt;code&gt;time&lt;/code&gt;：&lt;/p&gt;</description></item><item><title>fishhook 源码导读</title><link>https://amatsuzero.github.io/LastStand/posts/interview/ios-source-analysis/fishhook%E6%BA%90%E7%A0%81%E5%AF%BC%E8%AF%BB/</link><pubDate>Sat, 02 May 2026 22:32:27 +0800</pubDate><guid>https://amatsuzero.github.io/LastStand/posts/interview/ios-source-analysis/fishhook%E6%BA%90%E7%A0%81%E5%AF%BC%E8%AF%BB/</guid><description>&lt;blockquote&gt;
&lt;p&gt;fishhook 由 Facebook 于 2013 年开源，用于在运行时动态重绑定（rebind）Mach-O 中被 dyld 绑定的 C 符号，是 iOS/macOS 逆向与底层埋点（malloc 追踪、双 close 检测、网络 socket 拦截、NSLog 重定向等）领域的&amp;quot;瑞士军刀&amp;quot;。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;hr&gt;
&lt;h2 id="一fishhook-是什么"&gt;一、fishhook 是什么&lt;/h2&gt;
&lt;p&gt;&lt;strong&gt;一句话定义&lt;/strong&gt;：fishhook 通过修改 Mach-O 镜像中 &lt;code&gt;__DATA(_CONST)&lt;/code&gt; 段里 &lt;code&gt;__la_symbol_ptr&lt;/code&gt; / &lt;code&gt;__nl_symbol_ptr&lt;/code&gt; 两个 Section 中的函数指针，把对外部 C 符号（如 &lt;code&gt;open&lt;/code&gt;、&lt;code&gt;close&lt;/code&gt;、&lt;code&gt;NSLog&lt;/code&gt;）的调用重定向到自定义的替换函数，同时保留原函数指针供回调使用。&lt;/p&gt;
&lt;p&gt;它提供的能力类似 macOS 上 &lt;code&gt;DYLD_INTERPOSE&lt;/code&gt; 宏（编译期 interpose），但：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;运行时生效&lt;/strong&gt;：不需要重新编译依赖库，随时可以在 App 启动后对系统库的 C 函数下钩子；&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;支持动态加载的 image&lt;/strong&gt;：注册后对后续 &lt;code&gt;dlopen&lt;/code&gt; 加载的 image 同样生效；&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;对业务零侵入&lt;/strong&gt;：不改 App 本身的代码段，也不破坏符号表，只是重写 GOT/stub 里的一个指针。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;但它也有非常明确的能力边界：&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;能力&lt;/th&gt;
&lt;th&gt;是否支持&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Hook 通过 &lt;code&gt;dyld&lt;/code&gt; 动态绑定的外部 C 函数（libSystem、CoreFoundation 里的 C API、&lt;code&gt;objc_msgSend&lt;/code&gt; 等）&lt;/td&gt;
&lt;td&gt;是&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Hook Objective-C 方法（&lt;code&gt;-[NSString length]&lt;/code&gt;）&lt;/td&gt;
&lt;td&gt;否（要用 Method Swizzling）&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Hook 当前 image 内部的 C 函数（静态链接、&lt;code&gt;static&lt;/code&gt;、内联）&lt;/td&gt;
&lt;td&gt;否（它不走 &lt;code&gt;__la_symbol_ptr&lt;/code&gt;，直接是段内相对寻址）&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Hook Swift 方法（除非显式 &lt;code&gt;@_cdecl&lt;/code&gt;）&lt;/td&gt;
&lt;td&gt;否&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Hook 已经解析并内联到寄存器里的符号（如 LTO 后消失的符号）&lt;/td&gt;
&lt;td&gt;否&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;记住这条原则：&lt;strong&gt;fishhook 的作用域 = 被 dyld 绑定为&amp;quot;间接符号&amp;quot;（Indirect Symbol）的 C 符号&lt;/strong&gt;。&lt;/p&gt;</description></item><item><title>SIL（Swift Intermediate Language）</title><link>https://amatsuzero.github.io/LastStand/posts/interview/ios-basics/sil/</link><pubDate>Sat, 02 May 2026 22:32:27 +0800</pubDate><guid>https://amatsuzero.github.io/LastStand/posts/interview/ios-basics/sil/</guid><description>&lt;p&gt;SIL（Swift Intermediate Language，Swift 中间语言）是 Swift 编译器在编译过程中生成的一种&lt;strong&gt;中间表示&lt;/strong&gt;（Intermediate Representation，IR）。它位于 Swift 源码与 LLVM IR 之间，是 Swift 编译器架构中至关重要的一层。&lt;/p&gt;
&lt;p&gt;SIL 的设计目标是：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;对 Swift 语言的&lt;strong&gt;高级语义&lt;/strong&gt;进行精确建模&lt;/li&gt;
&lt;li&gt;在&lt;strong&gt;高层抽象&lt;/strong&gt;的基础上执行强大的优化&lt;/li&gt;
&lt;li&gt;保留足够的类型信息，用于&lt;strong&gt;诊断&lt;/strong&gt;和&lt;strong&gt;安全检查&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;作为 Swift 特有优化的载体，弥补 LLVM IR 无法直接表达 Swift 语义的不足&lt;/li&gt;
&lt;/ul&gt;
&lt;blockquote&gt;
&lt;p&gt;SIL 并不是给开发者日常编写的语言，而是编译器的内部表示。理解它有助于深入理解 Swift 的编译过程、性能优化原理和内存管理机制。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h2 id="swift-编译流程概览"&gt;Swift 编译流程概览&lt;/h2&gt;
&lt;p&gt;在了解 SIL 之前，需要先理解 Swift 的整体编译流程：&lt;/p&gt;
&lt;pre class="mermaid"&gt;flowchart TD
A[Swift 源代码 .swift] --&gt; B[词法分析 Lexer]
B --&gt; C[语法分析 Parser]
C --&gt; D[语义分析 Sema]
D --&gt; E[SILGen: 生成 Raw SIL]
E --&gt; F[SIL 优化 Guaranteed Passes]
F --&gt; G[SIL 优化 General Passes]
G --&gt; H[IRGen: 生成 LLVM IR]
H --&gt; I[LLVM 优化]
I --&gt; J[机器码 .o]
J --&gt; K[链接器 Linker]
K --&gt; L[可执行文件 / 动态库]
&lt;/pre&gt;
&lt;h3 id="各阶段简述"&gt;各阶段简述&lt;/h3&gt;
&lt;h4 id="词法分析lexer"&gt;词法分析（Lexer）&lt;/h4&gt;
&lt;p&gt;编译的第一步。Lexer 逐字符扫描 &lt;code&gt;.swift&lt;/code&gt; 源文件，将其切分为一系列&lt;strong&gt;Token（词法单元）&lt;/strong&gt;，例如关键字 &lt;code&gt;func&lt;/code&gt;、标识符 &lt;code&gt;add&lt;/code&gt;、运算符 &lt;code&gt;+&lt;/code&gt;、字面量 &lt;code&gt;42&lt;/code&gt;、左右括号等。Token 是后续所有分析的最小输入单位。这一步会剥离注释和空白，但保留它们的位置信息以便后续生成精确的诊断信息（错误提示的行号和列号）。&lt;/p&gt;</description></item><item><title>组件化架构详解</title><link>https://amatsuzero.github.io/LastStand/posts/interview/ios-architecture/%E7%BB%84%E4%BB%B6%E5%8C%96/</link><pubDate>Sat, 02 May 2026 22:32:27 +0800</pubDate><guid>https://amatsuzero.github.io/LastStand/posts/interview/ios-architecture/%E7%BB%84%E4%BB%B6%E5%8C%96/</guid><description>&lt;h2 id="什么是组件化"&gt;什么是组件化&lt;/h2&gt;
&lt;p&gt;组件化是一种&lt;strong&gt;工程架构思想&lt;/strong&gt;，将一个大型App拆分为多个独立的业务组件（Module），每个组件可以独立开发、独立测试、独立编译，组件之间通过&lt;strong&gt;中间层&lt;/strong&gt;进行解耦通信。&lt;/p&gt;
&lt;h3 id="组件化解决的问题"&gt;组件化解决的问题&lt;/h3&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;问题&lt;/th&gt;
&lt;th&gt;未组件化&lt;/th&gt;
&lt;th&gt;组件化后&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;编译速度&lt;/td&gt;
&lt;td&gt;全量编译，耗时长&lt;/td&gt;
&lt;td&gt;只编译修改的组件，支持二进制化&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;团队协作&lt;/td&gt;
&lt;td&gt;代码冲突频繁&lt;/td&gt;
&lt;td&gt;独立仓库，减少冲突&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;代码复用&lt;/td&gt;
&lt;td&gt;复制粘贴，难以维护&lt;/td&gt;
&lt;td&gt;组件复用，统一维护&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;耦合度&lt;/td&gt;
&lt;td&gt;类之间直接依赖，牵一发动全身&lt;/td&gt;
&lt;td&gt;通过中间层通信，解耦&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;测试&lt;/td&gt;
&lt;td&gt;难以单元测试&lt;/td&gt;
&lt;td&gt;组件可独立测试&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;h3 id="组件化与页面架构的关系"&gt;组件化与页面架构的关系&lt;/h3&gt;
&lt;p&gt;组件化是&lt;strong&gt;工程架构&lt;/strong&gt;，关注的是App整体的模块划分和通信方式；而MVC、MVVM、TCA等是&lt;strong&gt;页面架构&lt;/strong&gt;，关注的是单个页面内的代码组织。&lt;/p&gt;
&lt;p&gt;两者并不冲突，在大型项目中通常会同时采用：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;工程层面&lt;/strong&gt;：使用组件化拆分业务模块&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;组件内部&lt;/strong&gt;：每个组件使用MVVM/TCA等页面架构&lt;/li&gt;
&lt;/ul&gt;
&lt;pre class="mermaid"&gt;flowchart TB
subgraph App["App壳工程"]
subgraph Module1["首页组件"]
M1V["View"]
M1VM["ViewModel"]
M1M["Model"]
end
subgraph Module2["商城组件"]
M2V["View"]
M2VM["ViewModel"]
M2M["Model"]
end
Router["路由/中间件"]
end
Module1 &lt;--&gt; Router
Module2 &lt;--&gt; Router
&lt;/pre&gt;
&lt;h2 id="组件化的分层架构"&gt;组件化的分层架构&lt;/h2&gt;
&lt;p&gt;典型的组件化架构采用三层结构：&lt;/p&gt;
&lt;pre class="mermaid"&gt;flowchart TB
subgraph 业务层["业务层 - Business Layer"]
A[首页组件]
B[商城组件]
C[用户组件]
D[消息组件]
end
subgraph 中间层["中间层 - Mediator Layer"]
E[路由Router]
F[服务Service]
end
subgraph 基础层["基础层 - Foundation Layer"]
G[网络库]
H[图片库]
I[数据库]
J[工具库]
end
A &amp; B &amp; C &amp; D --&gt; E &amp; F
E &amp; F --&gt; G &amp; H &amp; I &amp; J
&lt;/pre&gt;
&lt;h3 id="业务层business-layer"&gt;业务层（Business Layer）&lt;/h3&gt;
&lt;p&gt;业务层包含各个业务组件，每个组件是一个独立的业务单元：&lt;/p&gt;</description></item><item><title>耗电-CPU与后台优化</title><link>https://amatsuzero.github.io/LastStand/posts/interview/ios-performance/power-cpu%E4%B8%8E%E5%90%8E%E5%8F%B0%E4%BC%98%E5%8C%96/</link><pubDate>Sat, 02 May 2026 22:32:27 +0800</pubDate><guid>https://amatsuzero.github.io/LastStand/posts/interview/ios-performance/power-cpu%E4%B8%8E%E5%90%8E%E5%8F%B0%E4%BC%98%E5%8C%96/</guid><description>&lt;p&gt;CPU是App最容易&amp;quot;无意识&amp;quot;耗电的模块，而后台则是最容易&amp;quot;偷偷&amp;quot;耗电的场景。本文聚焦这两大问题域，给出具体的优化手段。&lt;/p&gt;
&lt;hr&gt;
&lt;h2 id="一cpu耗电的根本原因"&gt;一、CPU耗电的根本原因&lt;/h2&gt;
&lt;p&gt;根据 &lt;a href="https://amatsuzero.github.io/LastStand/posts/interview/ios-performance/power-%E5%8E%9F%E7%90%86/"&gt;耗电-原理&lt;/a&gt; 中的分析，CPU耗电由三部分构成：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;活跃时间&lt;/strong&gt;：CPU处于C0/P0的时间。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;瞬时功率&lt;/strong&gt;：和P-State频率相关。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;唤醒次数&lt;/strong&gt;：频繁从C-State唤醒无法进入深度休眠。&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;对应三条优化方向：&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;优化方向&lt;/th&gt;
&lt;th&gt;策略&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;减少活跃&lt;/td&gt;
&lt;td&gt;任务及时结束，该停就停&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;降低功率&lt;/td&gt;
&lt;td&gt;避免无谓的满核满频，使用合适的QoS&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;合并唤醒&lt;/td&gt;
&lt;td&gt;聚合Timer、聚合任务，让CPU能连续工作后进入深休眠&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;hr&gt;
&lt;h2 id="二识别cpu耗电热点"&gt;二、识别CPU耗电热点&lt;/h2&gt;
&lt;h3 id="从metrickit入手"&gt;从MetricKit入手&lt;/h3&gt;
&lt;p&gt;&lt;code&gt;cumulativeCPUTime&lt;/code&gt; 是线上最直接的CPU指标。对比同版本前后、同机型前后的CPU时长，能快速定位回归。&lt;/p&gt;
&lt;h3 id="time-profiler的使用技巧"&gt;Time Profiler的使用技巧&lt;/h3&gt;
&lt;p&gt;在Instruments中抓一份Time Profiler Trace后：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;按&amp;quot;Heavy Stack&amp;quot;视图查看耗时函数。&lt;/li&gt;
&lt;li&gt;关注&lt;strong&gt;后台&lt;/strong&gt;的采样（通过Xcode的生命周期切换复现）。&lt;/li&gt;
&lt;li&gt;查看&lt;strong&gt;线程调用频率&lt;/strong&gt;——单次耗时低但高频调用的函数，同样是耗电大头。&lt;/li&gt;
&lt;/ol&gt;
&lt;h3 id="代码层面的cpu异味"&gt;代码层面的CPU异味&lt;/h3&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-swift" data-lang="swift"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;// 1. 死循环轮询&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;while&lt;/span&gt; isWaitingForData {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;if&lt;/span&gt; dataReady { &lt;span style="color:#66d9ef"&gt;break&lt;/span&gt; }
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;// 2. 主线程sleep循环&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;DispatchQueue.global().async {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;while&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;true&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; checkStatus()
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; Thread.sleep(forTimeInterval: &lt;span style="color:#ae81ff"&gt;0.1&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; }
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;// 3. 密集Timer&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;Timer.scheduledTimer(withTimeInterval: &lt;span style="color:#ae81ff"&gt;0.016&lt;/span&gt;, repeats: &lt;span style="color:#66d9ef"&gt;true&lt;/span&gt;) { &lt;span style="color:#66d9ef"&gt;_&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;in&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;self&lt;/span&gt;.updateUI()
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;// 4. 无限制的CADisplayLink&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;displayLink = CADisplayLink(target: &lt;span style="color:#66d9ef"&gt;self&lt;/span&gt;, selector: &lt;span style="color:#66d9ef"&gt;#selector&lt;/span&gt;(tick))
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;displayLink.add(to: .main, forMode: .common)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;// 页面隐藏后忘记invalidate&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;这些代码在Time Profiler中都会显示出异常高的调用频率。&lt;/p&gt;</description></item><item><title>Objective-C weak 指针作用与实现原理</title><link>https://amatsuzero.github.io/LastStand/posts/ocsourcecodeanalysis/weak-pointer-explained/</link><pubDate>Mon, 01 Jun 2026 19:50:12 +0800</pubDate><guid>https://amatsuzero.github.io/LastStand/posts/ocsourcecodeanalysis/weak-pointer-explained/</guid><description>&lt;p&gt;objc4 runtime zeroing weak SideTable weak_table_t&lt;/p&gt;
&lt;h1 id="objective-c-weak-指针作用与实现原理"&gt;Objective-C weak 指针：作用与实现原理&lt;/h1&gt;
&lt;p&gt;&lt;code&gt;__weak&lt;/code&gt; 的核心价值是“引用对象但不拥有对象”：它不会增加引用计数；当对象开始销毁时，runtime 会把所有指向它的 weak 槽位自动写成 &lt;code&gt;nil&lt;/code&gt;，避免野指针。这一页按 objc4 源码中的真实路径解释它如何登记、读取、搬迁和清零。&lt;/p&gt;
&lt;p&gt;&lt;a id="role"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;h2 id="阅读顺序"&gt;阅读顺序&lt;/h2&gt;
&lt;ol&gt;
&lt;li&gt;&lt;a href="#role"&gt;weak 解决什么问题&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="#model"&gt;运行时数据模型&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="#api"&gt;核心类型、字段、方法&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="#flows"&gt;关键操作流程&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="#snippets"&gt;带注释源码片段&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="#summary"&gt;一遍记住&lt;/a&gt;&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;&lt;a id="model"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;h2 id="1-weak-的作用"&gt;1. weak 的作用&lt;/h2&gt;
&lt;p&gt;&lt;strong&gt;不拥有对象&lt;/strong&gt;&lt;code&gt;__weak id x = obj;&lt;/code&gt; 不会 retain &lt;code&gt;obj&lt;/code&gt;，所以不会延长对象生命周期。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;自动归零&lt;/strong&gt;对象销毁时，所有保存该对象地址的 weak 变量会被 runtime 写成 &lt;code&gt;nil&lt;/code&gt;。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;读时短暂保活&lt;/strong&gt;读取 weak 时，runtime 会先尝试 retain，再 autorelease，保证表达式使用期间对象不被并发释放。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;拒绝无效目标&lt;/strong&gt;目标正在 dealloc 或类不支持 weak 时，形成 weak 引用会失败或崩溃，取决于入口函数。&lt;/p&gt;
&lt;p&gt;**一句话模型：**strong 指针管“拥有关系”，weak 指针管“可观察关系”。delegate、反向引用、缓存回调对象通常适合 weak，因为它们不应该阻止真实所有者释放对象。&lt;/p&gt;
&lt;p&gt;&lt;a id="api"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;h2 id="2-运行时数据模型"&gt;2. 运行时数据模型&lt;/h2&gt;
&lt;p&gt;weak 表不是全局一把大表直接裸用，而是挂在分片的 &lt;code&gt;SideTable&lt;/code&gt; 上。runtime 用对象地址选择某个 &lt;code&gt;SideTable&lt;/code&gt;，在该表内维护引用计数辅助信息和 weak 表，并用同一把锁保护它们。&lt;/p&gt;</description></item><item><title>CocoaPods 源码导读：从下载到工程集成</title><link>https://amatsuzero.github.io/LastStand/posts/interview/ios-source-analysis/cocoapods-%E4%BB%8E%E4%B8%8B%E8%BD%BD%E5%88%B0%E5%B7%A5%E7%A8%8B%E9%9B%86%E6%88%90/</link><pubDate>Sat, 02 May 2026 22:32:27 +0800</pubDate><guid>https://amatsuzero.github.io/LastStand/posts/interview/ios-source-analysis/cocoapods-%E4%BB%8E%E4%B8%8B%E8%BD%BD%E5%88%B0%E5%B7%A5%E7%A8%8B%E9%9B%86%E6%88%90/</guid><description>&lt;blockquote&gt;
&lt;p&gt;本文是系列第三篇，基于 CocoaPods 1.16.2 源码。上一篇我们停在 &lt;code&gt;Analyzer&lt;/code&gt; 产出 &lt;code&gt;AnalysisResult&lt;/code&gt;，本文继续走完 &lt;code&gt;download_dependencies&lt;/code&gt; → &lt;code&gt;validate_targets&lt;/code&gt; → &lt;code&gt;generate_pods_project&lt;/code&gt; → &lt;code&gt;integrate_user_project&lt;/code&gt; → &lt;code&gt;write_lockfiles&lt;/code&gt; 这五个阶段。&lt;/p&gt;
&lt;p&gt;上一篇：&lt;a href="https://amatsuzero.github.io/LastStand/posts/interview/ios-source-analysis/cocoapods-%E4%BB%8E%E5%91%BD%E4%BB%A4%E5%88%B0%E4%BE%9D%E8%B5%96%E6%B1%82%E8%A7%A3/"&gt;从命令到依赖求解&lt;/a&gt; · 首篇：&lt;a href="https://amatsuzero.github.io/LastStand/posts/interview/ios-source-analysis/cocoapods-%E6%9E%B6%E6%9E%84%E6%80%BB%E8%A7%88/"&gt;架构总览&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;hr&gt;
&lt;h2 id="一全景从-spec-到可编译的工程"&gt;一、全景：从 spec 到可编译的工程&lt;/h2&gt;
&lt;p&gt;先把本文要走的流程重新放一遍，让你带着地图读代码：&lt;/p&gt;
&lt;pre class="mermaid"&gt;flowchart TB
A[AnalysisResult] --&gt; B[download_dependencies]
B --&gt;|per pod| B1[PodSourceDownloader]
B1 --&gt;|命中| C1[Downloader::Cache]
B1 --&gt;|未命中| C2[cocoapods-downloader&lt;br/&gt;Git/HTTP/SVN/...]
C2 --&gt; C3[rsync → Pods/&amp;lt;name&amp;gt;/]
B --&gt;|per pod| B2[PodSourceInstaller]
B2 --&gt; B3[PodSourcePreparer&lt;br/&gt;prepare_command]
B2 --&gt; B4[PodDirCleaner&lt;br/&gt;按 spec.source_files 裁剪]
B --&gt; D[validate_targets&lt;br/&gt;TargetValidator#validate!]
D --&gt; E[generate_pods_project]
E --&gt; E1[ProjectCacheAnalyzer&lt;br/&gt;增量识别要重生成的 target]
E --&gt; E2[SinglePodsProjectGenerator#generate!]
E2 --&gt; E21[FileReferencesInstaller]
E2 --&gt; E22[PodTargetInstaller]
E2 --&gt; E23[AggregateTargetInstaller]
E2 --&gt; E24[xcconfig / modulemap / umbrella / info.plist / dummy.m]
E --&gt; E3[PodsProjectWriter#write!&lt;br/&gt;写盘前触发 Podfile post_install]
E --&gt; F[integrate_user_project]
F --&gt; F1[create_workspace&lt;br/&gt;写 .xcworkspace]
F --&gt; F2[deintegrate_removed_targets]
F --&gt; F3[TargetIntegrator#integrate!&lt;br/&gt;xcconfig / frameworks / scripts]
F --&gt; G[write_lockfiles]
G --&gt; G1[Podfile.lock]
G --&gt; G2[Pods/Manifest.lock]
G --&gt; H[perform_post_install_actions&lt;br/&gt;plugin post_install hook]
&lt;/pre&gt;
&lt;p&gt;对应的 &lt;code&gt;Installer#install!&lt;/code&gt; 片段：&lt;/p&gt;</description></item><item><title>Swift中import详解</title><link>https://amatsuzero.github.io/LastStand/posts/interview/ios-basics/swift%E4%B8%ADimport%E8%AF%A6%E8%A7%A3/</link><pubDate>Sat, 02 May 2026 22:32:27 +0800</pubDate><guid>https://amatsuzero.github.io/LastStand/posts/interview/ios-basics/swift%E4%B8%ADimport%E8%AF%A6%E8%A7%A3/</guid><description>&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;源码版本说明&lt;/strong&gt;：本文涉及的源码基于 &lt;strong&gt;Swift 编译器&lt;/strong&gt; 开发版本（swift main分支，commit: &lt;code&gt;e0db5152d4d4&lt;/code&gt;，2026-01-19）。不同版本的实现细节可能略有差异，但核心机制保持一致。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;在前一篇文章&lt;a href="https://amatsuzero.github.io/LastStand/posts/interview/ios-basics/objective-c%E4%B8%ADimport%E8%AF%A6%E8%A7%A3/"&gt;Objective-C中import详解&lt;/a&gt;中，我们深入探讨了 Objective-C 中的 import 机制，包括 &lt;code&gt;#include&lt;/code&gt;、&lt;code&gt;#import&lt;/code&gt;、&lt;code&gt;@import&lt;/code&gt; 以及 Clang Modules 的工作原理。本文将继续从 Swift 编译器的角度，讲解 Swift 中 import 的语法、模块查找机制、底层实现原理以及与 Objective-C 的互操作。&lt;/p&gt;
&lt;h2 id="从-clang-module-到-swift-module"&gt;从 Clang Module 到 Swift Module&lt;/h2&gt;
&lt;p&gt;在深入 Swift 的 import 机制之前，让我们先回顾一下上一篇文章中 Clang Module 的核心概念。&lt;/p&gt;
&lt;h3 id="clang-module-核心概念回顾"&gt;Clang Module 核心概念回顾&lt;/h3&gt;
&lt;p&gt;在 Objective-C 文章中，我们学习了 Clang Module 的几个关键特性：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;module.modulemap&lt;/strong&gt;：定义模块结构的配置文件&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-gdscript3" data-lang="gdscript3"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;framework module Foundation {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; umbrella header &lt;span style="color:#e6db74"&gt;&amp;#34;Foundation.h&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;export&lt;/span&gt; &lt;span style="color:#f92672"&gt;*&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;预编译模块缓存（.pcm 文件）&lt;/strong&gt;：Clang 将模块编译为二进制格式，缓存以加速后续编译&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;懒加载机制&lt;/strong&gt;：只加载实际使用的声明，未使用的部分不会被解析&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;自动链接&lt;/strong&gt;：&lt;code&gt;@import&lt;/code&gt; 会自动链接对应的库，无需手动配置&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;模块查找路径&lt;/strong&gt;：通过 &lt;code&gt;-I&lt;/code&gt;、&lt;code&gt;-F&lt;/code&gt; 等参数指定搜索路径&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;h3 id="swift-如何继承-clang-module-的设计"&gt;Swift 如何继承 Clang Module 的设计&lt;/h3&gt;
&lt;p&gt;Swift 的模块系统并非从零开始设计，而是&lt;strong&gt;站在 Clang Module 的肩膀上&lt;/strong&gt;，继承了其核心优势，并针对 Swift 的特性进行了扩展：&lt;/p&gt;</description></item><item><title>编译优化-链接优化</title><link>https://amatsuzero.github.io/LastStand/posts/interview/ios-build/%E9%93%BE%E6%8E%A5%E4%BC%98%E5%8C%96/</link><pubDate>Sat, 02 May 2026 22:32:27 +0800</pubDate><guid>https://amatsuzero.github.io/LastStand/posts/interview/ios-build/%E9%93%BE%E6%8E%A5%E4%BC%98%E5%8C%96/</guid><description>&lt;p&gt;链接是 iOS 编译的最后一个阶段，也是大型工程里经常被忽略的瓶颈。Apple 在 WWDC22 的 &amp;ldquo;Link fast: Improve build and launch times&amp;rdquo; 演讲中公开：Xcode 14 新的 &lt;code&gt;ld-prime&lt;/code&gt; 链接器比 &lt;code&gt;ld64&lt;/code&gt; 快 &lt;strong&gt;2 倍&lt;/strong&gt;。随着 Xcode 17、ThinLTO、Mergeable Libraries 等改进，链接优化已经成为编译加速的重要一环。&lt;/p&gt;
&lt;hr&gt;
&lt;h2 id="链接器的职责"&gt;链接器的职责&lt;/h2&gt;
&lt;p&gt;链接器把多个 &lt;code&gt;.o&lt;/code&gt; 合并成最终可执行文件或库：&lt;/p&gt;
&lt;pre class="mermaid"&gt;flowchart TD
A[若干 .o] --&gt; L[链接器]
B[静态库 .a] --&gt; L
C[动态库 .dylib / framework] --&gt; L
L --&gt; D[符号解析]
D --&gt; E[dead_strip]
E --&gt; F[ObjC runtime fix-up]
F --&gt; G[生成 LC_* 加载命令]
G --&gt; H[写入 Mach-O]
&lt;/pre&gt;
&lt;p&gt;关键任务：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;符号解析&lt;/strong&gt;：所有 undefined symbol 必须在某个 .o / .a / .dylib 里找到&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;重定位&lt;/strong&gt;：把符号引用的偏移写入正确位置&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Dead Strip&lt;/strong&gt;：去掉未被使用的代码/数据&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;ObjC 元数据修复&lt;/strong&gt;：把分散的类、分类信息合并成 ObjC runtime 能识别的结构&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;生成 Mach-O&lt;/strong&gt;：写 Load Commands、&lt;code&gt;__LINKEDIT&lt;/code&gt; 等段&lt;/li&gt;
&lt;/ul&gt;
&lt;hr&gt;
&lt;h2 id="链接器对比"&gt;链接器对比&lt;/h2&gt;
&lt;h3 id="ld64经典"&gt;ld64（经典）&lt;/h3&gt;
&lt;p&gt;&lt;code&gt;ld64&lt;/code&gt; 是 Apple 长期使用的经典链接器，源代码在 &lt;a href="https://github.com/apple-oss-distributions/ld64"&gt;apple-oss-distributions/ld64&lt;/a&gt;。单线程为主，在大工程上明显偏慢。&lt;/p&gt;</description></item><item><title>耗电-原理</title><link>https://amatsuzero.github.io/LastStand/posts/interview/ios-performance/power-%E5%8E%9F%E7%90%86/</link><pubDate>Sat, 02 May 2026 22:32:27 +0800</pubDate><guid>https://amatsuzero.github.io/LastStand/posts/interview/ios-performance/power-%E5%8E%9F%E7%90%86/</guid><description>&lt;p&gt;本文从硬件功耗模型、iOS系统的能效调度机制、以及各个硬件模块的功耗特性三个维度，系统性地讲解iOS App耗电的底层原理。&lt;/p&gt;
&lt;hr&gt;
&lt;h2 id="功耗的基本概念"&gt;功耗的基本概念&lt;/h2&gt;
&lt;h3 id="功率能量与电量"&gt;功率、能量与电量&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;功率（Power）&lt;/strong&gt;：单位时间内消耗的能量，单位为瓦特（W）。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;能量（Energy）&lt;/strong&gt;：功率在时间上的积分，单位为焦耳（J）或毫瓦时（mWh）。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;电量（Battery Capacity）&lt;/strong&gt;：电池能存储的总能量，单位为毫安时（mAh）。&lt;/li&gt;
&lt;/ul&gt;
\[ Energy = \int P(t)\,dt \]&lt;p&gt;对于一段时间内近似恒定的功率，可以简化为 \( E = P \times t \)。这也是所有耗电优化的起点——要么降功率（P），要么降时间（t）。&lt;/p&gt;
&lt;h3 id="电池电压与电流"&gt;电池电压与电流&lt;/h3&gt;
&lt;p&gt;iPhone使用锂电池，标称电压约为3.7~3.8V。操作系统看到的电流则随着硬件负载实时变化。可以近似认为：&lt;/p&gt;
\[ P(t) = V \times I(t) \]&lt;p&gt;在App层面，我们无法直接测量V和I，但可以通过 &lt;code&gt;UIDevice.current.batteryLevel&lt;/code&gt; 观察电量百分比，通过 &lt;code&gt;IOKit&lt;/code&gt; 私有API读取更精细的电池状态（后面检测篇会详细讲）。&lt;/p&gt;
&lt;hr&gt;
&lt;h2 id="硬件功耗特性"&gt;硬件功耗特性&lt;/h2&gt;
&lt;p&gt;不同硬件模块的功耗曲线差异非常大。理解每个模块的特性，才能找到最有效的优化点。&lt;/p&gt;
&lt;h3 id="cpup-state与c-state"&gt;CPU：P-State与C-State&lt;/h3&gt;
&lt;p&gt;现代CPU（包括Apple Silicon）通过 &lt;strong&gt;动态电压频率调整（DVFS）&lt;/strong&gt; 来平衡性能与功耗。&lt;/p&gt;
&lt;h4 id="p-stateperformance-state"&gt;P-State（Performance State）&lt;/h4&gt;
&lt;p&gt;P-State描述CPU在工作时的电压/频率档位。以Apple A系列芯片为例，大核和小核都有多个P-State：&lt;/p&gt;
&lt;pre class="mermaid"&gt;flowchart LR
subgraph P-State
P0["P0&lt;br/&gt;最高频率&lt;br/&gt;功耗最大"]
P1["P1&lt;br/&gt;中高频率"]
P2["P2&lt;br/&gt;中低频率"]
P3["P3&lt;br/&gt;低频率&lt;br/&gt;功耗小"]
end
P0 -.-&gt;|负载下降| P1
P1 -.-&gt; P2
P2 -.-&gt; P3
P3 -.-&gt;|负载上升| P0
&lt;/pre&gt;
&lt;p&gt;CPU的功耗与频率大致呈 &lt;strong&gt;立方关系&lt;/strong&gt;（电压随频率升高，功耗 ≈ V² × f ≈ f³）。这意味着：&lt;/p&gt;</description></item><item><title>objc4 Autorelease 一页讲透</title><link>https://amatsuzero.github.io/LastStand/posts/ocsourcecodeanalysis/autorelease-explained/</link><pubDate>Mon, 01 Jun 2026 19:50:12 +0800</pubDate><guid>https://amatsuzero.github.io/LastStand/posts/ocsourcecodeanalysis/autorelease-explained/</guid><description>&lt;p&gt;objc4 runtime guide&lt;/p&gt;
&lt;h1 id="autorelease-的作用和实现原理"&gt;Autorelease 的作用和实现原理&lt;/h1&gt;
&lt;p&gt;一句话：autorelease 是“延迟一次 release”的机制。对象先被登记到当前线程的自动释放池中， 等池子 pop 时再统一发送 release，从而让返回值和临时对象可以跨过当前语句或当前函数继续存活一小段时间。&lt;/p&gt;
&lt;p&gt;核心文件：runtime/NSObject.mm 数据结构：AutoreleasePoolPage 线程隔离：TLS hot page 边界标记：POOL_BOUNDARY&lt;/p&gt;
&lt;h2 id="先建立正确心智模型"&gt;先建立正确心智模型&lt;/h2&gt;
&lt;p&gt;&lt;strong&gt;autorelease pool 不是一堆对象的容器类。&lt;/strong&gt; 在 objc4 里，它更像每个线程私有的一条栈。栈里放两类指针： 普通对象指针，以及表示池边界的 &lt;code&gt;POOL_BOUNDARY&lt;/code&gt;。每次 push 池，就压入一个边界并返回这个边界地址作为 token。 每次 autorelease 对象，就把对象指针压到 hot page 的 &lt;code&gt;next&lt;/code&gt; 位置。pop 时拿 token 找到边界， 把边界之上的对象按后进先出的顺序逐个 &lt;code&gt;objc_release&lt;/code&gt;。&lt;/p&gt;
&lt;h2 id="它解决什么问题"&gt;它解决什么问题&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;**返回 +0 对象：**被调用方可以返回一个“当前调用者可用，但不归调用者拥有”的对象。&lt;/li&gt;
&lt;li&gt;**批量释放临时对象：**循环、事件回调、线程入口可以用池边界控制临时对象峰值。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;兼容手动引用计数：&lt;/strong&gt;&lt;code&gt;retain&lt;/code&gt; 表示拿所有权，&lt;code&gt;release&lt;/code&gt; 表示交回所有权，&lt;code&gt;autorelease&lt;/code&gt; 表示稍后自动交回。&lt;/li&gt;
&lt;li&gt;**配合 ARC 优化：**运行时和编译器会尝试消除返回值中的多余 retain/autorelease。&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="一张图看懂栈变化"&gt;一张图看懂栈变化&lt;/h2&gt;
&lt;p&gt;假设外层池中 autorelease 了 A，又进入内层池 autorelease 了 B、C。内层 pop 只释放 B、C，不影响外层 A。&lt;/p&gt;
&lt;p&gt;push 外层&lt;/p&gt;</description></item><item><title>编译优化</title><link>https://amatsuzero.github.io/LastStand/posts/interview/ios-build/%E7%BC%96%E8%AF%91%E4%BC%98%E5%8C%96/</link><pubDate>Wed, 27 May 2026 22:24:03 +0800</pubDate><guid>https://amatsuzero.github.io/LastStand/posts/interview/ios-build/%E7%BC%96%E8%AF%91%E4%BC%98%E5%8C%96/</guid><description>&lt;p&gt;大型 iOS 工程的编译耗时往往是研发效能最突出的瓶颈之一。以抖音、今日头条、美团为代表的一线团队，工程代码量通常在数百万到千万行级，本地全量编译耗时 10 分钟以上、CI 上半小时起步已是常态。编译等待不仅直接压缩研发时间，还会打断心流、降低人均产出。&lt;/p&gt;
&lt;p&gt;本系列文章从 iOS 编译系统的原理出发，结合社区最新实践（Xcode 16/17 Explicit Modules、rules_xcodeproj、seer-optimize、cocoapods-hmap-prebuilt、Rugby 等），系统性介绍编译优化的各类手段与背后的原理。&lt;/p&gt;
&lt;hr&gt;
&lt;h2 id="编译流程概述"&gt;编译流程概述&lt;/h2&gt;
&lt;p&gt;理解&lt;a href="https://amatsuzero.github.io/LastStand/posts/interview/ios-basics/ios%E7%BC%96%E8%AF%91%E5%8E%9F%E7%90%86/"&gt;iOS编译原理&lt;/a&gt;是编译优化的前提。一次典型的 iOS 编译流程可以划分为以下阶段：&lt;/p&gt;
&lt;pre class="mermaid"&gt;flowchart TD
A[Parse Podfile / 生成工程] --&gt; B[Pod Install / 依赖解析]
B --&gt; C[Xcode Build System 调度]
C --&gt; D[Dependency Scan / 模块依赖扫描]
D --&gt; E[Swift/Clang 前端编译]
E --&gt; F[生成 .o / .swiftmodule / .pcm]
F --&gt; G[链接 ld64 / ld-prime / lld]
G --&gt; H[签名 / 打包 / 资源处理]
H --&gt; I[产出 .app / .ipa]
&lt;/pre&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;阶段&lt;/th&gt;
&lt;th&gt;主要工作&lt;/th&gt;
&lt;th&gt;常见瓶颈&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;依赖管理&lt;/td&gt;
&lt;td&gt;Pod Install、SPM 解析&lt;/td&gt;
&lt;td&gt;Source 更新慢、Specification 解析重复、沙盒拷贝&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;工程生成&lt;/td&gt;
&lt;td&gt;生成 Pods.xcodeproj、xcconfig、hmap&lt;/td&gt;
&lt;td&gt;Target 数量多、pbxproj 膨胀&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;构建调度&lt;/td&gt;
&lt;td&gt;Build System 解析任务图、并行调度&lt;/td&gt;
&lt;td&gt;依赖粒度过粗、并行度不足&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;模块扫描&lt;/td&gt;
&lt;td&gt;Clang/Swift 依赖扫描&lt;/td&gt;
&lt;td&gt;隐式模块重复编译&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;源码编译&lt;/td&gt;
&lt;td&gt;Swift/Clang 前端、类型检查、SIL/IR 生成&lt;/td&gt;
&lt;td&gt;类型推导爆炸、WMO 关闭、PCH 失效&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;链接&lt;/td&gt;
&lt;td&gt;符号解析、LTO、dead-strip&lt;/td&gt;
&lt;td&gt;链接参数过长、ThinLTO 串行&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;收尾&lt;/td&gt;
&lt;td&gt;签名、资源拷贝、dSYM&lt;/td&gt;
&lt;td&gt;串行脚本阻塞&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;hr&gt;
&lt;h2 id="优化思路全景"&gt;优化思路全景&lt;/h2&gt;
&lt;p&gt;编译优化的核心思路只有三条：&lt;strong&gt;减少需要做的工作&lt;/strong&gt;、&lt;strong&gt;让必须做的工作更快&lt;/strong&gt;、&lt;strong&gt;让做过的工作可复用&lt;/strong&gt;。所有社区实践都可以归入这三类。&lt;/p&gt;</description></item><item><title>CocoaPods 源码导读：从命令到依赖求解</title><link>https://amatsuzero.github.io/LastStand/posts/interview/ios-source-analysis/cocoapods-%E4%BB%8E%E5%91%BD%E4%BB%A4%E5%88%B0%E4%BE%9D%E8%B5%96%E6%B1%82%E8%A7%A3/</link><pubDate>Sat, 02 May 2026 22:32:27 +0800</pubDate><guid>https://amatsuzero.github.io/LastStand/posts/interview/ios-source-analysis/cocoapods-%E4%BB%8E%E5%91%BD%E4%BB%A4%E5%88%B0%E4%BE%9D%E8%B5%96%E6%B1%82%E8%A7%A3/</guid><description>&lt;blockquote&gt;
&lt;p&gt;本文是系列第二篇，基于 CocoaPods 1.16.2 源码。我们从 &lt;code&gt;bin/pod&lt;/code&gt; 进场，走完 CLAide 的命令分发、&lt;code&gt;Podfile&lt;/code&gt; 的 DSL 求值、&lt;code&gt;Analyzer&lt;/code&gt; 的七步分析、&lt;code&gt;Resolver + Molinillo&lt;/code&gt; 的回溯求解，最后交付 &lt;code&gt;AggregateTarget&lt;/code&gt;/&lt;code&gt;PodTarget&lt;/code&gt; 给下一篇讲的下载与集成。&lt;/p&gt;
&lt;p&gt;上一篇：&lt;a href="https://amatsuzero.github.io/LastStand/posts/interview/ios-source-analysis/cocoapods-%E6%9E%B6%E6%9E%84%E6%80%BB%E8%A7%88/"&gt;架构总览&lt;/a&gt; · 下一篇：&lt;a href="https://amatsuzero.github.io/LastStand/posts/interview/ios-source-analysis/cocoapods-%E4%BB%8E%E4%B8%8B%E8%BD%BD%E5%88%B0%E5%B7%A5%E7%A8%8B%E9%9B%86%E6%88%90/"&gt;从下载到工程集成&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;运行示例贯穿全文：&lt;code&gt;pod install --repo-update&lt;/code&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;hr&gt;
&lt;h2 id="一binpod16-行的入口"&gt;一、&lt;code&gt;bin/pod&lt;/code&gt;：16 行的入口&lt;/h2&gt;
&lt;p&gt;CocoaPods 的可执行文件非常薄，核心逻辑全在 &lt;code&gt;require 'cocoapods'&lt;/code&gt; 之后的 &lt;code&gt;Pod::Command.run&lt;/code&gt;：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-ruby" data-lang="ruby"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;# CocoaPods/bin/pod : 24&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;if&lt;/span&gt; $PROGRAM_NAME &lt;span style="color:#f92672"&gt;==&lt;/span&gt; __FILE__ &lt;span style="color:#f92672"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span style="color:#f92672"&gt;!&lt;/span&gt;&lt;span style="color:#66d9ef"&gt;ENV&lt;/span&gt;&lt;span style="color:#f92672"&gt;[&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#39;COCOAPODS_NO_BUNDLER&amp;#39;&lt;/span&gt;&lt;span style="color:#f92672"&gt;]&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;ENV&lt;/span&gt;&lt;span style="color:#f92672"&gt;[&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#39;BUNDLE_GEMFILE&amp;#39;&lt;/span&gt;&lt;span style="color:#f92672"&gt;]&lt;/span&gt; &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;File&lt;/span&gt;&lt;span style="color:#f92672"&gt;.&lt;/span&gt;expand_path(&lt;span style="color:#e6db74"&gt;&amp;#39;../../Gemfile&amp;#39;&lt;/span&gt;, __FILE__)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; require &lt;span style="color:#e6db74"&gt;&amp;#39;rubygems&amp;#39;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; require &lt;span style="color:#e6db74"&gt;&amp;#39;bundler/setup&amp;#39;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; $LOAD_PATH&lt;span style="color:#f92672"&gt;.&lt;/span&gt;unshift &lt;span style="color:#66d9ef"&gt;File&lt;/span&gt;&lt;span style="color:#f92672"&gt;.&lt;/span&gt;expand_path(&lt;span style="color:#e6db74"&gt;&amp;#39;../../lib&amp;#39;&lt;/span&gt;, __FILE__)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;elsif&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;ENV&lt;/span&gt;&lt;span style="color:#f92672"&gt;[&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#39;COCOAPODS_NO_BUNDLER&amp;#39;&lt;/span&gt;&lt;span style="color:#f92672"&gt;]&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; require &lt;span style="color:#e6db74"&gt;&amp;#39;rubygems&amp;#39;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; gem &lt;span style="color:#e6db74"&gt;&amp;#39;cocoapods&amp;#39;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;end&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;STDOUT&lt;/span&gt;&lt;span style="color:#f92672"&gt;.&lt;/span&gt;sync &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;true&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;if&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;ENV&lt;/span&gt;&lt;span style="color:#f92672"&gt;[&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#39;CP_STDOUT_SYNC&amp;#39;&lt;/span&gt;&lt;span style="color:#f92672"&gt;]&lt;/span&gt; &lt;span style="color:#f92672"&gt;==&lt;/span&gt; &lt;span style="color:#e6db74"&gt;&amp;#39;TRUE&amp;#39;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;require &lt;span style="color:#e6db74"&gt;&amp;#39;cocoapods&amp;#39;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;if&lt;/span&gt; profile_filename &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;ENV&lt;/span&gt;&lt;span style="color:#f92672"&gt;[&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#39;COCOAPODS_PROFILE&amp;#39;&lt;/span&gt;&lt;span style="color:#f92672"&gt;]&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#75715e"&gt;# 开 ruby-prof 做性能剖析&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#75715e"&gt;# ...&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; reporter&lt;span style="color:#f92672"&gt;.&lt;/span&gt;new(&lt;span style="color:#66d9ef"&gt;RubyProf&lt;/span&gt;&lt;span style="color:#f92672"&gt;.&lt;/span&gt;profile { &lt;span style="color:#66d9ef"&gt;Pod&lt;/span&gt;&lt;span style="color:#f92672"&gt;::&lt;/span&gt;&lt;span style="color:#66d9ef"&gt;Command&lt;/span&gt;&lt;span style="color:#f92672"&gt;.&lt;/span&gt;run(&lt;span style="color:#66d9ef"&gt;ARGV&lt;/span&gt;) })&lt;span style="color:#f92672"&gt;.&lt;/span&gt;print(io)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;else&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;Pod&lt;/span&gt;&lt;span style="color:#f92672"&gt;::&lt;/span&gt;&lt;span style="color:#66d9ef"&gt;Command&lt;/span&gt;&lt;span style="color:#f92672"&gt;.&lt;/span&gt;run(&lt;span style="color:#66d9ef"&gt;ARGV&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;end&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;这里有两个工程化细节值得留意：&lt;/p&gt;</description></item><item><title>Swift二进制兼容性</title><link>https://amatsuzero.github.io/LastStand/posts/interview/ios-basics/swift%E4%BA%8C%E8%BF%9B%E5%88%B6%E5%85%BC%E5%AE%B9%E6%80%A7/</link><pubDate>Sat, 02 May 2026 22:32:27 +0800</pubDate><guid>https://amatsuzero.github.io/LastStand/posts/interview/ios-basics/swift%E4%BA%8C%E8%BF%9B%E5%88%B6%E5%85%BC%E5%AE%B9%E6%80%A7/</guid><description>&lt;p&gt;Swift二进制兼容性是指Swift编译后的二进制代码能够跨版本、跨模块正确链接和运行的能力。它由三个核心机制组成：&lt;strong&gt;ABI稳定&lt;/strong&gt;（Swift 5.0）、&lt;strong&gt;模块稳定性&lt;/strong&gt;（Swift 5.1）和&lt;strong&gt;Library Evolution&lt;/strong&gt;。这三者共同使得Swift二进制框架的分发成为可能。&lt;/p&gt;
&lt;pre class="mermaid"&gt;graph TD
A[Swift二进制兼容性] --&gt; B[ABI稳定&lt;br/&gt;Swift 5.0]
A --&gt; C[模块稳定性&lt;br/&gt;Swift 5.1]
A --&gt; D[Library Evolution]
B --&gt; B1[统一运行时&lt;br/&gt;固定调用约定/内存布局]
C --&gt; C1[.swiftinterface&lt;br/&gt;跨编译器版本导入模块]
D --&gt; D1[运行时布局查询&lt;br/&gt;库可独立于客户端更新]
B1 --&gt; E[二进制框架分发]
C1 --&gt; E
D1 --&gt; E
&lt;/pre&gt;
&lt;h2 id="abi稳定"&gt;ABI稳定&lt;/h2&gt;
&lt;h3 id="什么是abi"&gt;什么是ABI&lt;/h3&gt;
&lt;p&gt;ABI（Application Binary Interface，应用程序二进制接口）定义了二进制层面的接口规范，包括：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;数据类型的大小和对齐方式&lt;/strong&gt;：如Int在64位系统上是8字节&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;函数调用约定&lt;/strong&gt;：参数如何传递、返回值如何获取&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;名称修饰（Name Mangling）规则&lt;/strong&gt;：函数和类型在二进制中的命名方式&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;内存布局&lt;/strong&gt;：对象在内存中的结构&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;异常处理机制&lt;/strong&gt;：错误如何在二进制层面传播&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;运行时元数据格式&lt;/strong&gt;：类型信息的存储方式&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id="abi-vs-api"&gt;ABI vs API&lt;/h3&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;特性&lt;/th&gt;
&lt;th&gt;API（源码接口）&lt;/th&gt;
&lt;th&gt;ABI（二进制接口）&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;层面&lt;/td&gt;
&lt;td&gt;源代码层面&lt;/td&gt;
&lt;td&gt;编译后的二进制层面&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;兼容性检查&lt;/td&gt;
&lt;td&gt;编译时&lt;/td&gt;
&lt;td&gt;链接时/运行时&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;关注点&lt;/td&gt;
&lt;td&gt;函数签名、类型定义&lt;/td&gt;
&lt;td&gt;内存布局、调用约定&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;变化影响&lt;/td&gt;
&lt;td&gt;需要重新编译&lt;/td&gt;
&lt;td&gt;需要重新链接或替换二进制&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;一个简单的例子：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-swift" data-lang="swift"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;// API层面：函数签名&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;func&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;calculate&lt;/span&gt;(value: Int) -&amp;gt; Int
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;// ABI层面关注的是：&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;// - Int在内存中占多少字节&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;// - value参数通过哪个寄存器传递&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;// - 返回值通过哪个寄存器返回&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;// - 函数在二进制中的符号名是什么&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h3 id="abi不稳定时期的问题"&gt;ABI不稳定时期的问题&lt;/h3&gt;
&lt;p&gt;在Swift 5.0之前，Swift的ABI是不稳定的。这意味着：&lt;/p&gt;</description></item><item><title>耗电-定位与传感器优化</title><link>https://amatsuzero.github.io/LastStand/posts/interview/ios-performance/power-%E5%AE%9A%E4%BD%8D%E4%B8%8E%E4%BC%A0%E6%84%9F%E5%99%A8%E4%BC%98%E5%8C%96/</link><pubDate>Sat, 02 May 2026 22:32:27 +0800</pubDate><guid>https://amatsuzero.github.io/LastStand/posts/interview/ios-performance/power-%E5%AE%9A%E4%BD%8D%E4%B8%8E%E4%BC%A0%E6%84%9F%E5%99%A8%E4%BC%98%E5%8C%96/</guid><description>&lt;p&gt;定位是iOS设备上公认的&amp;quot;耗电大户&amp;quot;，GPS冷启动一次动辄十几秒的高功耗；传感器（加速度计、陀螺仪等）虽然单次功耗不高，但高频采样会累积成可观的电量消耗；屏幕则是 &lt;strong&gt;持续&lt;/strong&gt; 耗电的模块，其功耗和亮度、刷新率、像素颜色都强相关。本文聚焦这三类问题，给出工程化的优化方案。&lt;/p&gt;
&lt;hr&gt;
&lt;h2 id="一定位精度与功耗的关系"&gt;一、定位精度与功耗的关系&lt;/h2&gt;
&lt;p&gt;iOS通过 &lt;code&gt;CLLocationManager&lt;/code&gt; 提供定位服务，底层融合了 &lt;strong&gt;GPS、蜂窝基站、WiFi、蓝牙信标&lt;/strong&gt; 等多源信号。精度越高，需要开启的硬件越多，功耗越高。&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;精度常量&lt;/th&gt;
&lt;th&gt;精度范围&lt;/th&gt;
&lt;th&gt;硬件使用&lt;/th&gt;
&lt;th&gt;典型功耗&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;kCLLocationAccuracyBestForNavigation&lt;/td&gt;
&lt;td&gt;&amp;lt;5m&lt;/td&gt;
&lt;td&gt;GPS + 传感器融合（需插电）&lt;/td&gt;
&lt;td&gt;极高&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;kCLLocationAccuracyBest&lt;/td&gt;
&lt;td&gt;~10m&lt;/td&gt;
&lt;td&gt;GPS持续&lt;/td&gt;
&lt;td&gt;高&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;kCLLocationAccuracyNearestTenMeters&lt;/td&gt;
&lt;td&gt;~10m&lt;/td&gt;
&lt;td&gt;GPS + WiFi&lt;/td&gt;
&lt;td&gt;高&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;kCLLocationAccuracyHundredMeters&lt;/td&gt;
&lt;td&gt;~100m&lt;/td&gt;
&lt;td&gt;WiFi + 基站&lt;/td&gt;
&lt;td&gt;中&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;kCLLocationAccuracyKilometer&lt;/td&gt;
&lt;td&gt;~1km&lt;/td&gt;
&lt;td&gt;WiFi + 基站（低频）&lt;/td&gt;
&lt;td&gt;低&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;kCLLocationAccuracyThreeKilometers&lt;/td&gt;
&lt;td&gt;~3km&lt;/td&gt;
&lt;td&gt;基站&lt;/td&gt;
&lt;td&gt;极低&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;blockquote&gt;
&lt;p&gt;注：iOS 14+ 引入的 &lt;strong&gt;ReducedAccuracy&lt;/strong&gt; 是用户授权层面的&amp;quot;粗略位置&amp;quot;，通过 &lt;code&gt;CLAccuracyAuthorization.reducedAccuracy&lt;/code&gt; 体现，而不是 &lt;code&gt;desiredAccuracy&lt;/code&gt; 常量。即使 App 申请了高精度，只要用户选择了&amp;quot;粗略位置&amp;quot;，系统就只会返回约5公里精度的数据，功耗也随之降到极低。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h3 id="不同业务场景的精度选择"&gt;不同业务场景的精度选择&lt;/h3&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;业务&lt;/th&gt;
&lt;th&gt;推荐精度&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;导航&lt;/td&gt;
&lt;td&gt;BestForNavigation（仅使用中 + 插电时）&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;打车、骑行记录&lt;/td&gt;
&lt;td&gt;Best&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;外卖、附近的人&lt;/td&gt;
&lt;td&gt;HundredMeters&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;天气、资讯推荐&lt;/td&gt;
&lt;td&gt;Kilometer 或 ThreeKilometers&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;反欺诈、粗粒度风控&lt;/td&gt;
&lt;td&gt;ReducedAccuracy（尊重隐私 + 省电）&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;h3 id="常见反例"&gt;常见反例&lt;/h3&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-swift" data-lang="swift"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;// Bad: 所有场景都用Best，页面打开就开，关闭不关&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;locationManager.desiredAccuracy = kCLLocationAccuracyBest
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;locationManager.startUpdatingLocation()
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;// Bad: distanceFilter用kCLDistanceFilterNone，每次都回调&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;locationManager.distanceFilter = kCLDistanceFilterNone
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h3 id="正确姿势按需精度--距离过滤"&gt;正确姿势：按需精度 + 距离过滤&lt;/h3&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-swift" data-lang="swift"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;class&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;WeatherLocationClient&lt;/span&gt;: NSObject, CLLocationManagerDelegate {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;private&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;let&lt;/span&gt; manager = CLLocationManager()
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;private&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;var&lt;/span&gt; completion: ((CLLocation) -&amp;gt; Void)?
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;override&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;init&lt;/span&gt;() {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;super&lt;/span&gt;.&lt;span style="color:#66d9ef"&gt;init&lt;/span&gt;()
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; manager.delegate = &lt;span style="color:#66d9ef"&gt;self&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; manager.desiredAccuracy = kCLLocationAccuracyKilometer
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; manager.distanceFilter = &lt;span style="color:#ae81ff"&gt;500&lt;/span&gt; &lt;span style="color:#75715e"&gt;// 500米才更新&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; }
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;func&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;requestOnce&lt;/span&gt;(&lt;span style="color:#66d9ef"&gt;_&lt;/span&gt; completion: @escaping (CLLocation) -&amp;gt; Void) {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;self&lt;/span&gt;.completion = completion
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; manager.requestLocation() &lt;span style="color:#75715e"&gt;// 一次性定位，完成后自动停止&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; }
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;func&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;locationManager&lt;/span&gt;(&lt;span style="color:#66d9ef"&gt;_&lt;/span&gt; manager: CLLocationManager, didUpdateLocations locs: [CLLocation]) {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;guard&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;let&lt;/span&gt; loc = locs.last &lt;span style="color:#66d9ef"&gt;else&lt;/span&gt; { &lt;span style="color:#66d9ef"&gt;return&lt;/span&gt; }
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; completion?(loc)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; completion = &lt;span style="color:#66d9ef"&gt;nil&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; }
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;func&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;locationManager&lt;/span&gt;(&lt;span style="color:#66d9ef"&gt;_&lt;/span&gt; manager: CLLocationManager, didFailWithError error: Error) {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; completion = &lt;span style="color:#66d9ef"&gt;nil&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; }
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;&lt;code&gt;requestLocation()&lt;/code&gt;（iOS 9+）是最省电的一次性定位入口，系统会在获取到满足精度的定位后自动停止硬件。&lt;/p&gt;</description></item><item><title>Objective-C 关联对象 Associated Objects 作用与实现原理</title><link>https://amatsuzero.github.io/LastStand/posts/ocsourcecodeanalysis/associated-objects-explained/</link><pubDate>Mon, 01 Jun 2026 19:50:12 +0800</pubDate><guid>https://amatsuzero.github.io/LastStand/posts/ocsourcecodeanalysis/associated-objects-explained/</guid><description>&lt;p&gt;objc4 runtime Associated Objects objc-references.mm&lt;/p&gt;
&lt;h1 id="关联对象-associated-objects-作用与实现原理"&gt;关联对象 Associated Objects 作用与实现原理&lt;/h1&gt;
&lt;p&gt;关联对象让调用方在不改类布局、不新增 ivar 的情况下，把一组 &lt;code&gt;key - value&lt;/code&gt; 挂到任意 Objective-C 对象上。 objc4 的实现不是把字段塞进对象内存，而是用一张运行时全局表保存“对象地址、key、关联值和内存管理策略”的映射。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;入口 API&lt;/strong&gt;&lt;code&gt;objc_setAssociatedObject&lt;/code&gt;&lt;br&gt;
&lt;code&gt;objc_getAssociatedObject&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;核心存储&lt;/strong&gt;&lt;code&gt;AssociationsHashMap&lt;/code&gt;&lt;br&gt;
&lt;code&gt;ObjectAssociationMap&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;值封装&lt;/strong&gt;&lt;code&gt;ObjcAssociation&lt;/code&gt;&lt;br&gt;
&lt;code&gt;policy + value&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;清理时机&lt;/strong&gt;&lt;code&gt;objc_destructInstance&lt;/code&gt;&lt;br&gt;
&lt;code&gt;objc_disposeClassPair&lt;/code&gt;&lt;/p&gt;
&lt;h2 id="目录"&gt;目录&lt;/h2&gt;
&lt;ol&gt;
&lt;li&gt;&lt;a href="#purpose"&gt;作用与使用边界&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="#api"&gt;公开 API 与 policy&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="#storage"&gt;核心结构与字段&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="#set-get-remove"&gt;set / get / remove 流程&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="#lifetime"&gt;对象销毁与特殊关联&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="#forbidden"&gt;禁止关联对象的场景&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="#tests"&gt;测试覆盖点&lt;/a&gt;&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;&lt;a id="purpose"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;h2 id="作用与使用边界"&gt;作用与使用边界&lt;/h2&gt;
&lt;p&gt;关联对象主要服务于分类、框架扩展、运行时补充状态等场景：调用方只有对象指针和一个稳定 key，就能为对象保存额外值。 这避免了修改类的 ivar 布局，也让分类可以模拟“存储属性”。&lt;/p&gt;
&lt;h3 id="适合做什么"&gt;适合做什么&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;给现有类或分类补充少量状态。&lt;/li&gt;
&lt;li&gt;把辅助对象、回调 block、缓存值挂到宿主对象。&lt;/li&gt;
&lt;li&gt;用唯一地址作为 key，避免和其他调用方冲突。&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id="不适合做什么"&gt;不适合做什么&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;高频读写的核心数据结构。&lt;/li&gt;
&lt;li&gt;需要类型系统和对象布局明确表达的状态。&lt;/li&gt;
&lt;li&gt;清空他人关联值，尤其是随意调用 &lt;code&gt;objc_removeAssociatedObjects&lt;/code&gt;。&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id="运行时代价"&gt;运行时代价&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;每次访问都需要全局关联表查询。&lt;/li&gt;
&lt;li&gt;set / get / remove 通过 &lt;code&gt;AssociationsManagerLock&lt;/code&gt; 串行保护表。&lt;/li&gt;
&lt;li&gt;对象析构时可能需要额外释放所有关联值。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;**关键结论：**关联对象是“外置 side table”，不是对象内的 ivar。对象只保存一个“可能有 associated objects”的快速标记，真正的 key/value 在全局表里。&lt;/p&gt;</description></item><item><title>耗电-检测</title><link>https://amatsuzero.github.io/LastStand/posts/interview/ios-performance/power-%E6%A3%80%E6%B5%8B/</link><pubDate>Fri, 08 May 2026 22:35:33 +0800</pubDate><guid>https://amatsuzero.github.io/LastStand/posts/interview/ios-performance/power-%E6%A3%80%E6%B5%8B/</guid><description>&lt;p&gt;本文介绍iOS耗电问题的检测手段，从开发阶段的本地工具，到线上的监控体系，帮助团队形成一套完整的耗电可观测能力。&lt;/p&gt;
&lt;hr&gt;
&lt;h2 id="检测手段全景"&gt;检测手段全景&lt;/h2&gt;
&lt;pre class="mermaid"&gt;flowchart TB
subgraph Dev["研发阶段"]
EG["Xcode Energy Gauge&lt;br/&gt;实时能效评分"]
Inst["Instruments&lt;br/&gt;Energy Log / Time Profiler"]
XCT["XCTest能效测试"]
end
subgraph Test["测试阶段"]
Thermal["热节流测试"]
Battery["真机电量消耗测试"]
IOKit["IOKit内部分析"]
LPM["低电量模式回归"]
end
subgraph Online["线上阶段"]
MK["MetricKit"]
Self["自建实时采集&lt;br/&gt;电量 / CPU / Thermal / 生命周期"]
Report["埋点上报&lt;br/&gt;数据看板"]
end
Dev --&gt; Test --&gt; Online
&lt;/pre&gt;
&lt;hr&gt;
&lt;h2 id="一xcode-energy-gauge"&gt;一、Xcode Energy Gauge&lt;/h2&gt;
&lt;p&gt;Xcode在真机调试时，&amp;ldquo;Debug Navigator → Energy Impact&amp;quot;提供了实时能效评估。&lt;/p&gt;
&lt;h3 id="能效评分energy-impact"&gt;能效评分（Energy Impact）&lt;/h3&gt;
&lt;p&gt;Xcode将功耗分为5档：&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;等级&lt;/th&gt;
&lt;th&gt;含义&lt;/th&gt;
&lt;th&gt;典型值&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Very Low / Low&lt;/td&gt;
&lt;td&gt;正常使用&lt;/td&gt;
&lt;td&gt;0&lt;del&gt;3 / 4&lt;/del&gt;8&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;High&lt;/td&gt;
&lt;td&gt;偏高，需要关注&lt;/td&gt;
&lt;td&gt;9~16&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Very High&lt;/td&gt;
&lt;td&gt;严重，必须优化&lt;/td&gt;
&lt;td&gt;17~20&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;评分由以下几个因素构成：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;CPU&lt;/strong&gt;：平均CPU使用率。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Network&lt;/strong&gt;：网络活跃时间与流量。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Location&lt;/strong&gt;：定位活跃时间与精度。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;GPU&lt;/strong&gt;：GPU活跃时间。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Background&lt;/strong&gt;：后台活跃时间。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Overhead&lt;/strong&gt;：系统唤醒代价。&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id="典型使用流程"&gt;典型使用流程&lt;/h3&gt;
&lt;ol&gt;
&lt;li&gt;Xcode连接真机（模拟器的数据不准确）。&lt;/li&gt;
&lt;li&gt;运行App，选择Debug Navigator → Energy Impact。&lt;/li&gt;
&lt;li&gt;进行典型操作（刷Feed、看视频、聊天等），观察评分。&lt;/li&gt;
&lt;li&gt;如果出现High/Very High，使用Instruments进一步定位。&lt;/li&gt;
&lt;/ol&gt;
&lt;hr&gt;
&lt;h2 id="二instruments-energy-log"&gt;二、Instruments Energy Log&lt;/h2&gt;
&lt;p&gt;Instruments中有多个和能效相关的工具：&lt;/p&gt;</description></item><item><title>Swift 宏</title><link>https://amatsuzero.github.io/LastStand/posts/interview/ios-basics/swift%E5%AE%8F/</link><pubDate>Mon, 04 May 2026 00:38:29 +0800</pubDate><guid>https://amatsuzero.github.io/LastStand/posts/interview/ios-basics/swift%E5%AE%8F/</guid><description>&lt;p&gt;Swift 5.9（WWDC 2023）引入的&lt;strong&gt;宏（Macro）&lt;strong&gt;是近几年语言层最大的一次能力扩展。它让 Swift 第一次具备了&lt;/strong&gt;编译期代码生成&lt;/strong&gt;的官方机制——你可以在源码层面写一段&amp;quot;能生成代码的代码&amp;quot;，编译器会在类型检查前把它展开成真正的 Swift 源码，再走正常的编译流程。SwiftUI 的 &lt;code&gt;#Preview&lt;/code&gt;、Observation 框架的 &lt;code&gt;@Observable&lt;/code&gt;、SwiftData 的 &lt;code&gt;@Model&lt;/code&gt;、Swift Testing 的 &lt;code&gt;@Test&lt;/code&gt; / &lt;code&gt;#expect&lt;/code&gt;、FoundationModels 的 &lt;code&gt;@Generable&lt;/code&gt; / &lt;code&gt;@Tool&lt;/code&gt;，全都是宏。&lt;/p&gt;
&lt;h2 id="一为什么要有宏"&gt;一、为什么要有宏&lt;/h2&gt;
&lt;h3 id="11-swift-之前能做什么又差在哪"&gt;1.1 Swift 之前能做什么，又差在哪&lt;/h3&gt;
&lt;p&gt;在宏之前，Swift 已经有一整套&amp;quot;元编程&amp;quot;手段，但每一种都有明显的边界：&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;机制&lt;/th&gt;
&lt;th&gt;做什么&lt;/th&gt;
&lt;th&gt;局限&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;@propertyWrapper&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;给属性注入行为（如 &lt;code&gt;@Published&lt;/code&gt;、&lt;code&gt;@State&lt;/code&gt;）&lt;/td&gt;
&lt;td&gt;只能包属性，不能生成方法、不能生成类型、不能访问其他成员&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;@resultBuilder&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;把一段 DSL 收集成表达式（如 SwiftUI 的 &lt;code&gt;ViewBuilder&lt;/code&gt;）&lt;/td&gt;
&lt;td&gt;只作用于闭包里，无法改类型定义&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;KeyPath + Mirror&lt;/td&gt;
&lt;td&gt;运行时反射读写属性&lt;/td&gt;
&lt;td&gt;只能读，类型安全差，性能差（见 &lt;a href="https://amatsuzero.github.io/LastStand/posts/interview/ios-basics/ios%E5%8F%8D%E5%B0%84/"&gt;iOS反射&lt;/a&gt;）&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Codable 等编译器魔法&lt;/td&gt;
&lt;td&gt;自动合成 &lt;code&gt;init(from:)&lt;/code&gt; / &lt;code&gt;encode(to:)&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;只有编译器内部能写，开发者写不出同等能力的东西&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Sourcery / SwiftGen&lt;/td&gt;
&lt;td&gt;文本级代码生成&lt;/td&gt;
&lt;td&gt;游离于编译器之外，无类型信息、无法访问 AST&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Objective-C &lt;code&gt;#define&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;纯文本替换&lt;/td&gt;
&lt;td&gt;没有作用域、没有类型、没有卫生（hygiene），对调试器和 IDE 极不友好&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;&lt;strong&gt;宏&lt;/strong&gt;就是要一次性补齐这块能力：在保留类型安全与 IDE 体验的前提下，把&amp;quot;只有 Swift 编译器团队能写的代码生成&amp;quot;开放给所有开发者。&lt;/p&gt;</description></item><item><title>CocoaPods 源码导读：架构总览</title><link>https://amatsuzero.github.io/LastStand/posts/interview/ios-source-analysis/cocoapods-%E6%9E%B6%E6%9E%84%E6%80%BB%E8%A7%88/</link><pubDate>Sat, 02 May 2026 22:32:27 +0800</pubDate><guid>https://amatsuzero.github.io/LastStand/posts/interview/ios-source-analysis/cocoapods-%E6%9E%B6%E6%9E%84%E6%80%BB%E8%A7%88/</guid><description>&lt;blockquote&gt;
&lt;p&gt;本系列基于 &lt;strong&gt;CocoaPods 1.16.2&lt;/strong&gt;（2026 年 4 月）源码进行分析。源码仓库由 15 个 Ruby Gem 组成，本文先从整体架构与职责拆分讲起，再以 &lt;code&gt;pod install --repo-update&lt;/code&gt; 为主线绘制全景执行图，串起后续两篇专题的切入点。&lt;/p&gt;
&lt;p&gt;系列目录：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;架构总览&lt;/strong&gt;（本文）&lt;/li&gt;
&lt;li&gt;&lt;a href="https://amatsuzero.github.io/LastStand/posts/interview/ios-source-analysis/cocoapods-%E4%BB%8E%E5%91%BD%E4%BB%A4%E5%88%B0%E4%BE%9D%E8%B5%96%E6%B1%82%E8%A7%A3/"&gt;从命令到依赖求解&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://amatsuzero.github.io/LastStand/posts/interview/ios-source-analysis/cocoapods-%E4%BB%8E%E4%B8%8B%E8%BD%BD%E5%88%B0%E5%B7%A5%E7%A8%8B%E9%9B%86%E6%88%90/"&gt;从下载到工程集成&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/blockquote&gt;
&lt;hr&gt;
&lt;h2 id="一cocoapods-不是单一仓库"&gt;一、CocoaPods 不是单一仓库&lt;/h2&gt;
&lt;p&gt;很多人以为 CocoaPods 就是一个 Ruby 项目，其实官方仓库 &lt;code&gt;CocoaPods/CocoaPods&lt;/code&gt; 只是入口，真正的能力被拆成 15 个独立 gem，每个 gem 只做一件事。用 &lt;code&gt;gem dependency cocoapods&lt;/code&gt; 会看到这样的依赖拓扑：&lt;/p&gt;
&lt;pre class="mermaid"&gt;graph TB
subgraph "入口"
A["bin/pod&lt;br/&gt;(CocoaPods gem)"]
end
subgraph "命令行框架"
B["CLAide&lt;br/&gt;Command/Arg/Option DSL"]
end
subgraph "领域模型"
C["Core&lt;br/&gt;Podfile/Podspec/Source/Lockfile"]
end
subgraph "依赖求解"
D["Molinillo&lt;br/&gt;回溯式 SAT 求解器"]
end
subgraph "下载"
E["cocoapods-downloader&lt;br/&gt;Git/HTTP/SVN/Hg/SCP"]
end
subgraph "Xcode 工程读写"
F["Xcodeproj&lt;br/&gt;pbxproj/xcconfig/workspace"]
G["Nanaimo&lt;br/&gt;ASCII plist 解析"]
end
subgraph "插件与子命令"
H["cocoapods-plugins"]
I["cocoapods-trunk&lt;br/&gt;cocoapods-search&lt;br/&gt;cocoapods-try&lt;br/&gt;cocoapods-deintegrate"]
end
subgraph "辅助"
J["cork&lt;br/&gt;彩色输出"]
K["nap&lt;br/&gt;轻量 HTTP 客户端"]
end
A --&gt; B
A --&gt; C
A --&gt; D
A --&gt; E
A --&gt; F
F --&gt; G
A -.加载.-&gt; H
H -.调用.-&gt; I
A --&gt; J
I --&gt; K
&lt;/pre&gt;
&lt;p&gt;各 gem 的一句话职责：&lt;/p&gt;</description></item><item><title>Objective-C KVC 作用与实现原理</title><link>https://amatsuzero.github.io/LastStand/posts/ocsourcecodeanalysis/kvc-explained/</link><pubDate>Mon, 01 Jun 2026 19:50:12 +0800</pubDate><guid>https://amatsuzero.github.io/LastStand/posts/ocsourcecodeanalysis/kvc-explained/</guid><description>&lt;p&gt;Key-Value Coding / Foundation behavior with objc4 runtime support&lt;/p&gt;
&lt;h1 id="objective-c-kvc从字符串-key-到对象读写"&gt;Objective-C KVC：从字符串 key 到对象读写&lt;/h1&gt;
&lt;p&gt;KVC 的核心价值是：把“访问某个属性或实例变量”抽象成 &lt;code&gt;valueForKey:&lt;/code&gt;、&lt;code&gt;setValue:forKey:&lt;/code&gt; 这样的字符串协议。 读完这一页，你应该能说清楚它解决什么问题、Foundation 大致怎样查找成员， 以及 objc4 runtime 在消息发送、元数据查询、ivar 直写和内存管理上提供了哪些支撑。&lt;/p&gt;
&lt;p&gt;适合第一次系统理解 KVC 标注 objc4 / Foundation 边界 含关键流程和注释代码&lt;/p&gt;
&lt;h2 id="目录"&gt;目录&lt;/h2&gt;
&lt;ol&gt;
&lt;li&gt;&lt;a href="#why"&gt;KVC 到底有什么用&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="#boundary"&gt;本仓库能看到什么&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="#lookup"&gt;读写 key 的查找顺序&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="#runtime"&gt;objc4 提供的底层能力&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="#classes"&gt;核心类、方法和关键属性&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="#flows"&gt;关键操作流程&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="#pitfalls"&gt;常见坑与记忆模型&lt;/a&gt;&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;&lt;a id="why"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;h2 id="1-kvc-到底有什么用"&gt;1. KVC 到底有什么用&lt;/h2&gt;
&lt;p&gt;平时你写 &lt;code&gt;person.name&lt;/code&gt; 或 &lt;code&gt;[person name]&lt;/code&gt;，访问目标在编译期就固定了。 KVC 允许你在运行时才决定要访问哪个成员：&lt;code&gt;[person valueForKey:@&amp;quot;name&amp;quot;]&lt;/code&gt;。 这使得对象、字典、表单、序列化、绑定和调试工具可以用同一套字符串 key 访问模型对象。&lt;/p&gt;
&lt;h3 id="动态访问"&gt;动态访问&lt;/h3&gt;
&lt;p&gt;&lt;strong&gt;运行时才知道字段名&lt;/strong&gt;时，用字符串 key 读取或写入对象。&lt;/p&gt;
&lt;h3 id="统一映射"&gt;统一映射&lt;/h3&gt;
&lt;p&gt;JSON、表单、数据库行、UI 绑定都可以映射到对象属性。&lt;/p&gt;
&lt;h3 id="批量和路径"&gt;批量和路径&lt;/h3&gt;
&lt;p&gt;&lt;code&gt;valueForKeyPath:&lt;/code&gt; 能沿着 &lt;code&gt;department.manager.name&lt;/code&gt; 连续取值。&lt;/p&gt;</description></item><item><title>耗电-治理</title><link>https://amatsuzero.github.io/LastStand/posts/interview/ios-performance/power-%E6%B2%BB%E7%90%86/</link><pubDate>Thu, 07 May 2026 15:42:48 +0800</pubDate><guid>https://amatsuzero.github.io/LastStand/posts/interview/ios-performance/power-%E6%B2%BB%E7%90%86/</guid><description>&lt;p&gt;前面几篇分别讲了耗电的原理、检测、以及CPU/网络/定位/屏幕的具体优化手段。本文把这些内容整合起来，给出一套面向工程团队的 &lt;strong&gt;耗电治理体系&lt;/strong&gt;：从研发规范、线上监控、问题排查到常态化运营。&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;耗电治理是 APM 资源子系的一部分，与稳定性、流畅性、启动指标共用同一套监控与告警基础设施。完整的 APM 建设方案见 &lt;a href="https://amatsuzero.github.io/LastStand/posts/interview/ios-apm/apm/"&gt;APM 系列&lt;/a&gt;：&lt;a href="https://amatsuzero.github.io/LastStand/posts/interview/ios-apm/%E6%95%B0%E6%8D%AE%E9%87%87%E9%9B%86/"&gt;数据采集&lt;/a&gt;、&lt;a href="https://amatsuzero.github.io/LastStand/posts/interview/ios-apm/b%E7%AB%AF%E5%B9%B3%E5%8F%B0%E8%AE%BE%E8%AE%A1/"&gt;B端平台设计&lt;/a&gt;。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;hr&gt;
&lt;h2 id="一治理体系全景"&gt;一、治理体系全景&lt;/h2&gt;
&lt;p&gt;一个成熟的iOS耗电治理体系通常由四个闭环组成：&lt;/p&gt;
&lt;pre class="mermaid"&gt;flowchart TB
subgraph Dev["研发侧"]
R1["能效规范"]
R2["架构层能效约束"]
R3["Code Review清单"]
end
subgraph Test["测试侧"]
T1["XCTest能效基线"]
T2["真机续航测试"]
T3["极端场景矩阵"]
end
subgraph Online["线上侧"]
O1["MetricKit接入"]
O2["自建CPU/电量采样"]
O3["场景化埋点"]
O4["大盘 + 告警"]
end
subgraph Gov["运营侧"]
G1["版本耗电报告"]
G2["Top问题跟进"]
G3["复盘与规范迭代"]
end
Dev --&gt; Test --&gt; Online --&gt; Gov --&gt; Dev
&lt;/pre&gt;
&lt;hr&gt;
&lt;h2 id="二研发阶段的能效规范"&gt;二、研发阶段的能效规范&lt;/h2&gt;
&lt;h3 id="模块准入清单"&gt;模块准入清单&lt;/h3&gt;
&lt;p&gt;每个新增模块在接入主App前，必须回答以下问题：&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;维度&lt;/th&gt;
&lt;th&gt;问题&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;CPU&lt;/td&gt;
&lt;td&gt;是否有常驻Timer？是否有轮询？是否在不可见时暂停？&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;网络&lt;/td&gt;
&lt;td&gt;请求频率？是否合并？是否支持后台取消？&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;定位&lt;/td&gt;
&lt;td&gt;是否申请定位？精度多少？后台策略？&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;传感器&lt;/td&gt;
&lt;td&gt;是否开启传感器？采样率？视图生命周期？&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;后台能力&lt;/td&gt;
&lt;td&gt;是否申请Background Mode？如何收敛？&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;动画/渲染&lt;/td&gt;
&lt;td&gt;是否有长驻动画？是否适配ProMotion？&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Low Power&lt;/td&gt;
&lt;td&gt;低电量模式下的降级策略？&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;权限&lt;/td&gt;
&lt;td&gt;涉及的用户权限？是否遵守最小权限原则？&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;h3 id="架构层面的能效约束"&gt;架构层面的能效约束&lt;/h3&gt;
&lt;p&gt;一些通用能力可以在架构层统一管控，避免各业务重复踩坑：&lt;/p&gt;</description></item><item><title>Swift底层原理-结构体、类和协议</title><link>https://amatsuzero.github.io/LastStand/posts/interview/ios-basics/swift%E5%BA%95%E5%B1%82%E5%8E%9F%E7%90%86-%E7%BB%93%E6%9E%84%E4%BD%93-%E7%B1%BB%E5%92%8C%E5%8D%8F%E8%AE%AE/</link><pubDate>Wed, 06 May 2026 22:05:01 +0800</pubDate><guid>https://amatsuzero.github.io/LastStand/posts/interview/ios-basics/swift%E5%BA%95%E5%B1%82%E5%8E%9F%E7%90%86-%E7%BB%93%E6%9E%84%E4%BD%93-%E7%B1%BB%E5%92%8C%E5%8D%8F%E8%AE%AE/</guid><description>&lt;p&gt;在&lt;a href="https://amatsuzero.github.io/LastStand/posts/interview/ios-basics/objective-c%E5%BA%95%E5%B1%82%E5%8E%9F%E7%90%86-nsobject/"&gt;Objective-C底层原理-NSObject&lt;/a&gt;文章中，我们深入了解了Objective-C对象的底层实现。本文将探讨Swift中类和结构体的底层原理。&lt;/p&gt;
&lt;h2 id="swift数据结构的分类"&gt;Swift数据结构的分类&lt;/h2&gt;
&lt;p&gt;Swift中的类根据是否继承自NSObject，在底层实现上存在显著差异：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;继承自NSObject的Swift类&lt;/strong&gt;：兼容Objective-C运行时，支持完整的Objective-C特性&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;纯Swift类&lt;/strong&gt;：使用Swift原生运行时，性能更优但Objective-C互操作性受限&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Swift中结构体是值类型，具有以下核心特征：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;栈上分配内存（&lt;a href="https://amatsuzero.github.io/LastStand/posts/interview/ios-basics/%E5%80%BC%E7%B1%BB%E5%9E%8B%E5%92%8C%E5%BC%95%E7%94%A8%E7%B1%BB%E5%9E%8B%E7%9A%84%E5%8C%BA%E5%88%AB/#%E5%80%BC%E7%B1%BB%E5%9E%8B%E7%9A%84%E9%80%83%E9%80%B8"&gt;非逃逸&lt;/a&gt;情况）&lt;/li&gt;
&lt;li&gt;值语义和完整拷贝&lt;/li&gt;
&lt;li&gt;&lt;a href="https://amatsuzero.github.io/LastStand/posts/interview/ios-basics/%E5%80%BC%E7%B1%BB%E5%9E%8B%E5%92%8C%E5%BC%95%E7%94%A8%E7%B1%BB%E5%9E%8B%E7%9A%84%E5%8C%BA%E5%88%AB/#%E5%86%99%E6%97%B6%E6%8B%B7%E8%B4%9Dcopy-on-write"&gt;写时拷贝&lt;/a&gt;优化（COW）&lt;/li&gt;
&lt;li&gt;静态方法派发&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="swift类的底层实现"&gt;Swift类的底层实现&lt;/h2&gt;
&lt;h3 id="继承自nsobject的swift类"&gt;继承自NSObject的Swift类&lt;/h3&gt;
&lt;p&gt;当Swift类继承自NSObject时，必须兼容Objective-C的运行时系统，其底层实现与Objective-C对象高度一致。&lt;/p&gt;
&lt;h4 id="内存布局"&gt;内存布局&lt;/h4&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-swift" data-lang="swift"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;class&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;Class&lt;/span&gt;: NSObject {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;var&lt;/span&gt; name: String
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;var&lt;/span&gt; isMale: Bool
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;var&lt;/span&gt; age: Int
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;init&lt;/span&gt;(name: String, isMale: Bool, age: Int) {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;self&lt;/span&gt;.name = name
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;self&lt;/span&gt;.isMale = isMale
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;self&lt;/span&gt;.age = age
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;super&lt;/span&gt;.&lt;span style="color:#66d9ef"&gt;init&lt;/span&gt;()
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; }
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;实例内存布局：&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;偏移量&lt;/th&gt;
&lt;th&gt;内容&lt;/th&gt;
&lt;th&gt;大小&lt;/th&gt;
&lt;th&gt;说明&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;0x0-0x7&lt;/td&gt;
&lt;td&gt;isa_t isa&lt;/td&gt;
&lt;td&gt;8字节&lt;/td&gt;
&lt;td&gt;指向类对象，包含优化的位域信息&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;0x8-0x17&lt;/td&gt;
&lt;td&gt;String name&lt;/td&gt;
&lt;td&gt;16字节&lt;/td&gt;
&lt;td&gt;Swift String结构（64位系统）&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;0x18&lt;/td&gt;
&lt;td&gt;Bool isMale&lt;/td&gt;
&lt;td&gt;1字节&lt;/td&gt;
&lt;td&gt;布尔值&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;0x19-0x1F&lt;/td&gt;
&lt;td&gt;(padding)&lt;/td&gt;
&lt;td&gt;7字节&lt;/td&gt;
&lt;td&gt;Swift编译器根据下一个字段（Int，8字节对齐要求）自动插入填充，确保Int字段从8的倍数地址开始&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;0x20-0x27&lt;/td&gt;
&lt;td&gt;Int age&lt;/td&gt;
&lt;td&gt;8字节&lt;/td&gt;
&lt;td&gt;64位整数&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;0x28-0x2F&lt;/td&gt;
&lt;td&gt;(padding)&lt;/td&gt;
&lt;td&gt;8字节&lt;/td&gt;
&lt;td&gt;最终内存对齐填充&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;&lt;strong&gt;关键特性：&lt;/strong&gt;&lt;/p&gt;</description></item><item><title>Objective-C KVO 作用与实现原理</title><link>https://amatsuzero.github.io/LastStand/posts/ocsourcecodeanalysis/kvo-explained/</link><pubDate>Mon, 01 Jun 2026 19:50:12 +0800</pubDate><guid>https://amatsuzero.github.io/LastStand/posts/ocsourcecodeanalysis/kvo-explained/</guid><description>&lt;p&gt;objc4 runtime reading note&lt;/p&gt;
&lt;h1 id="kvo从属性变化通知到-runtime-动态子类"&gt;KVO：从“属性变化通知”到 runtime 动态子类&lt;/h1&gt;
&lt;p&gt;KVO（Key-Value Observing）让一个对象在另一个对象的某个 key path 变化时收到回调。 在这个 objc4 仓库里，Foundation 的 KVO 主体代码不在源码中；但 runtime 暴露了 KVO 需要的关键能力： 复制类、切换对象的 isa、判断 ivar 内存语义，并保证这些操作在初始化、弱引用和并发加载场景下安全。&lt;/p&gt;
&lt;p&gt;入口：addObserver 核心：动态子类 通知：will/didChange 底层：objc_duplicateClass&lt;/p&gt;
&lt;p&gt;&lt;a id="what"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;h2 id="阅读路线"&gt;阅读路线&lt;/h2&gt;
&lt;ol&gt;
&lt;li&gt;&lt;a href="#what"&gt;KVO 解决什么问题&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="#principle"&gt;实现原理总览&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="#runtime"&gt;objc4 中的关键支撑&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="#classes"&gt;核心类和关键方法&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="#flows"&gt;关键流程&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="#snippets"&gt;带注释代码片段&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="#pitfalls"&gt;使用边界和排错&lt;/a&gt;&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;&lt;a id="principle"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;h2 id="1-kvo-的作用把状态变化变成可订阅事件"&gt;1. KVO 的作用：把“状态变化”变成可订阅事件&lt;/h2&gt;
&lt;p&gt;普通属性赋值只改变对象内部状态，调用者不知道“谁关心这个变化”。KVO 把某个 key path 的变化包装成标准事件： 被观察对象负责发出变化，观察者在 &lt;code&gt;observeValueForKeyPath:ofObject:change:context:&lt;/code&gt; 中接收。&lt;/p&gt;
&lt;h3 id="解耦"&gt;解耦&lt;/h3&gt;
&lt;p&gt;观察者不需要改写被观察对象的业务代码，只注册感兴趣的 key path。&lt;/p&gt;
&lt;h3 id="统一格式"&gt;统一格式&lt;/h3&gt;
&lt;p&gt;变化以 &lt;code&gt;change&lt;/code&gt; 字典传递，可包含旧值、新值、变化类型等。&lt;/p&gt;
&lt;h3 id="自动拦截"&gt;自动拦截&lt;/h3&gt;
&lt;p&gt;对 KVC/KVO 兼容的 setter，Foundation 可自动在 setter 前后发通知。&lt;/p&gt;
&lt;h3 id="手动通知"&gt;手动通知&lt;/h3&gt;
&lt;p&gt;复杂派生属性或批量变化可用 &lt;code&gt;willChangeValueForKey:&lt;/code&gt; 和 &lt;code&gt;didChangeValueForKey:&lt;/code&gt; 明确包围。&lt;/p&gt;</description></item><item><title>iOS 定时器的注意事项</title><link>https://amatsuzero.github.io/LastStand/posts/interview/ios-basics/timer%E7%9A%84%E6%B3%A8%E6%84%8F%E4%BA%8B%E9%A1%B9/</link><pubDate>Sat, 02 May 2026 22:32:27 +0800</pubDate><guid>https://amatsuzero.github.io/LastStand/posts/interview/ios-basics/timer%E7%9A%84%E6%B3%A8%E6%84%8F%E4%BA%8B%E9%A1%B9/</guid><description>&lt;p&gt;iOS 开发中常用的定时器有 NSTimer、CADisplayLink 和 GCD Timer。它们各有特点，但在使用时都有一些需要注意的问题。&lt;/p&gt;
&lt;h2 id="常见定时器类型"&gt;常见定时器类型&lt;/h2&gt;
&lt;h3 id="1-nstimer"&gt;1. NSTimer&lt;/h3&gt;
&lt;p&gt;最常用的定时器，基于 RunLoop 实现：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-objc" data-lang="objc"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;// 自动添加到当前 RunLoop 的 DefaultMode
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;NSTimer &lt;span style="color:#f92672"&gt;*&lt;/span&gt;timer &lt;span style="color:#f92672"&gt;=&lt;/span&gt; [NSTimer scheduledTimerWithTimeInterval:&lt;span style="color:#ae81ff"&gt;1.0&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; target:self
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; selector:&lt;span style="color:#66d9ef"&gt;@selector&lt;/span&gt;(timerFired)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; userInfo:nil
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; repeats:YES];
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;// 手动创建，需要手动添加到 RunLoop
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;NSTimer &lt;span style="color:#f92672"&gt;*&lt;/span&gt;timer &lt;span style="color:#f92672"&gt;=&lt;/span&gt; [NSTimer timerWithTimeInterval:&lt;span style="color:#ae81ff"&gt;1.0&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; target:self
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; selector:&lt;span style="color:#66d9ef"&gt;@selector&lt;/span&gt;(timerFired)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; userInfo:nil
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; repeats:YES];
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;[[NSRunLoop currentRunLoop] addTimer:timer forMode:NSDefaultRunLoopMode];
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h3 id="2-cadisplaylink"&gt;2. CADisplayLink&lt;/h3&gt;
&lt;p&gt;与屏幕刷新率同步的定时器，适合做动画：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-objc" data-lang="objc"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;CADisplayLink &lt;span style="color:#f92672"&gt;*&lt;/span&gt;displayLink &lt;span style="color:#f92672"&gt;=&lt;/span&gt; [CADisplayLink displayLinkWithTarget:self
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; selector:&lt;span style="color:#66d9ef"&gt;@selector&lt;/span&gt;(update)];
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;[displayLink addToRunLoop:[NSRunLoop currentRunLoop] forMode:NSDefaultRunLoopMode];
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h3 id="3-gcd-timer"&gt;3. GCD Timer&lt;/h3&gt;
&lt;p&gt;不依赖 RunLoop，精度更高：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-objc" data-lang="objc"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;dispatch_source_t timer &lt;span style="color:#f92672"&gt;=&lt;/span&gt; dispatch_source_create(DISPATCH_SOURCE_TYPE_TIMER, &lt;span style="color:#ae81ff"&gt;0&lt;/span&gt;, &lt;span style="color:#ae81ff"&gt;0&lt;/span&gt;, dispatch_get_main_queue());
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;dispatch_source_set_timer(timer, DISPATCH_TIME_NOW, &lt;span style="color:#ae81ff"&gt;1.0&lt;/span&gt; &lt;span style="color:#f92672"&gt;*&lt;/span&gt; NSEC_PER_SEC, &lt;span style="color:#ae81ff"&gt;0&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;dispatch_source_set_event_handler(timer, &lt;span style="color:#f92672"&gt;^&lt;/span&gt;{
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; NSLog(&lt;span style="color:#e6db74"&gt;@&amp;#34;GCD Timer fired&amp;#34;&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;});
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;dispatch_resume(timer);
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h2 id="注意事项一循环引用问题"&gt;注意事项一：循环引用问题&lt;/h2&gt;
&lt;h3 id="问题描述"&gt;问题描述&lt;/h3&gt;
&lt;p&gt;NSTimer 和 CADisplayLink 在使用 target-action 模式时，会强引用 target。如果 target 又持有定时器，就会形成循环引用：&lt;/p&gt;</description></item><item><title>耗电-网络优化</title><link>https://amatsuzero.github.io/LastStand/posts/interview/ios-performance/power-%E7%BD%91%E7%BB%9C%E4%BC%98%E5%8C%96/</link><pubDate>Sat, 02 May 2026 22:32:27 +0800</pubDate><guid>https://amatsuzero.github.io/LastStand/posts/interview/ios-performance/power-%E7%BD%91%E7%BB%9C%E4%BC%98%E5%8C%96/</guid><description>&lt;p&gt;网络是iOS设备上仅次于屏幕的耗电大户。和其他模块不同，网络耗电的&amp;quot;坑&amp;quot;非常隐蔽——请求本身只持续几十毫秒，但无线电（Radio）会有10~20秒的&amp;quot;尾能耗&amp;quot;。本文从无线电能效模型出发，给出具体的网络优化手段。&lt;/p&gt;
&lt;hr&gt;
&lt;h2 id="一无线电能效模型回顾"&gt;一、无线电能效模型回顾&lt;/h2&gt;
&lt;h3 id="rrc状态机再看一眼"&gt;RRC状态机再看一眼&lt;/h3&gt;
&lt;p&gt;无线电不是&amp;quot;开就费电、关就不费电&amp;quot;这么简单。它在连接和空闲之间存在中间状态：&lt;/p&gt;
&lt;pre class="mermaid"&gt;stateDiagram-v2
[*] --&gt; Idle: 初始/长时间空闲
Idle --&gt; Connected: 发送/接收
Connected --&gt; ShortDRX: 空闲~1秒
ShortDRX --&gt; LongDRX: 空闲~5秒
LongDRX --&gt; Idle: 空闲~10秒
Connected --&gt; Connected: 持续通信
ShortDRX --&gt; Connected: 新请求
LongDRX --&gt; Connected: 新请求
&lt;/pre&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;状态&lt;/th&gt;
&lt;th&gt;功耗&lt;/th&gt;
&lt;th&gt;说明&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Connected&lt;/td&gt;
&lt;td&gt;最高（&lt;del&gt;1&lt;/del&gt;2W）&lt;/td&gt;
&lt;td&gt;数据传输中&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Short DRX&lt;/td&gt;
&lt;td&gt;中等&lt;/td&gt;
&lt;td&gt;周期性监听页 paging，仍持有连接&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Long DRX&lt;/td&gt;
&lt;td&gt;低&lt;/td&gt;
&lt;td&gt;周期变长，仍在空中接口&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Idle&lt;/td&gt;
&lt;td&gt;极低（~几mW）&lt;/td&gt;
&lt;td&gt;完全释放&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;一次请求从发起到彻底回到Idle大约 &lt;strong&gt;12~20秒&lt;/strong&gt;。这个尾巴就是&amp;quot;Tail Energy&amp;quot;。&lt;/p&gt;
&lt;h3 id="能效启示"&gt;能效启示&lt;/h3&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-fallback" data-lang="fallback"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;10次请求，每次间隔2秒：
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;- Radio持续处于Connected/DRX状态 ≈ 30秒
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;- 实际传输时间可能只有几百ms
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;10次请求合并成1次:
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;- Radio活跃时间 ≈ 15秒（主要是尾巴）
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;- 节省约50%~70%的Radio能耗
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;&lt;strong&gt;结论：网络能效的核心就是&amp;quot;减少Radio醒来的次数&amp;quot;。&lt;/strong&gt;&lt;/p&gt;</description></item><item><title>runtime/hashtable2.mm 作用与实现原理</title><link>https://amatsuzero.github.io/LastStand/posts/ocsourcecodeanalysis/hashtable2-explained/</link><pubDate>Mon, 01 Jun 2026 19:50:12 +0800</pubDate><guid>https://amatsuzero.github.io/LastStand/posts/ocsourcecodeanalysis/hashtable2-explained/</guid><description>&lt;p&gt;objc4 runtime NXHashTable 集合结构&lt;/p&gt;
&lt;h1 id="runtimehashtable2mm-作用与实现原理"&gt;runtime/hashtable2.mm 作用与实现原理&lt;/h1&gt;
&lt;p&gt;这个文件实现了旧 NeXT/Objective-C runtime 暴露的 &lt;code&gt;NXHashTable&lt;/code&gt;：一个可存放任意指针或整数数据的哈希集合。它不保存 key-value 对；需要映射关系时，runtime 另用 &lt;code&gt;maptable.mm&lt;/code&gt; 的 &lt;code&gt;NXMapTable&lt;/code&gt;。&lt;/p&gt;
&lt;h2 id="一遍读懂"&gt;一遍读懂&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;它用 callback 决定“怎么 hash、怎么判等、怎么释放”。&lt;/li&gt;
&lt;li&gt;每个 bucket 是一条很短的冲突链。&lt;/li&gt;
&lt;li&gt;bucket 中只有 1 个元素时直接存指针，避免额外分配。&lt;/li&gt;
&lt;li&gt;元素数超过 bucket 数时扩容并重算位置。&lt;/li&gt;
&lt;li&gt;删除会把 2 个元素的 bucket 收缩回单指针形态。&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="1-它解决什么问题"&gt;1. 它解决什么问题&lt;/h2&gt;
&lt;p&gt;&lt;code&gt;NXHashTable&lt;/code&gt; 是 runtime 内部和兼容 API 使用的通用集合容器。调用者传入一组 &lt;code&gt;NXHashTablePrototype&lt;/code&gt;，告诉表如何处理元素：&lt;code&gt;hash(info, data)&lt;/code&gt; 计算哈希，&lt;code&gt;isEqual(info, a, b)&lt;/code&gt; 判断相等，&lt;code&gt;free(info, data)&lt;/code&gt; 在销毁或 reset 时释放元素。这样同一套表结构可以存指针、字符串，或“结构体首字段作为 key”的对象。&lt;/p&gt;
&lt;p&gt;**关键不变量：**如果两个元素被 &lt;code&gt;isEqual&lt;/code&gt; 判为相等，它们的 &lt;code&gt;hash&lt;/code&gt; 必须一致；而且参与 hash 的内容不能在入表后变化。否则扩容重排后会找不到元素。&lt;/p&gt;
&lt;h2 id="2-数据结构一层数组--小冲突链"&gt;2. 数据结构：一层数组 + 小冲突链&lt;/h2&gt;
&lt;p&gt;&lt;strong&gt;NXHashTable&lt;/strong&gt;保存 prototype、元素总数、bucket 数组和可透传给 callback 的 &lt;code&gt;info&lt;/code&gt;。&lt;/p&gt;</description></item><item><title>耗电</title><link>https://amatsuzero.github.io/LastStand/posts/interview/ios-performance/power-%E8%80%97%E7%94%B5/</link><pubDate>Fri, 08 May 2026 22:35:33 +0800</pubDate><guid>https://amatsuzero.github.io/LastStand/posts/interview/ios-performance/power-%E8%80%97%E7%94%B5/</guid><description>&lt;p&gt;耗电（Energy Consumption）是移动应用质量的重要指标之一。一款耗电过快的App会直接影响用户的续航体验，轻则被用户吐槽，重则被系统标记为&amp;quot;耗电大户&amp;quot;（在iOS的&amp;quot;设置 → 电池&amp;quot;中显示），最终被用户卸载。&lt;/p&gt;
&lt;p&gt;本系列文章从iOS功耗模型入手，系统性地介绍耗电问题的原理、检测、优化与治理。&lt;/p&gt;
&lt;hr&gt;
&lt;h2 id="为什么要关注耗电"&gt;为什么要关注耗电&lt;/h2&gt;
&lt;p&gt;iOS设备的电池容量有限（iPhone通常在3000~5000mAh），而应用的功耗会直接影响续航时间。苹果在iOS 8之后提供了&amp;quot;电池用量&amp;quot;统计入口，用户可以清楚地看到每个App消耗的电量比例。&lt;/p&gt;
&lt;p&gt;常见的耗电投诉场景：&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;场景&lt;/th&gt;
&lt;th&gt;用户感知&lt;/th&gt;
&lt;th&gt;典型原因&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;后台待机一晚电量掉20%&lt;/td&gt;
&lt;td&gt;手机放着不用也掉电&lt;/td&gt;
&lt;td&gt;后台定位、后台音频、后台Fetch未合理释放&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;App使用1小时电量掉30%&lt;/td&gt;
&lt;td&gt;使用过程电量下降过快&lt;/td&gt;
&lt;td&gt;CPU长时间高占用、高频网络请求、GPU密集渲染&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;手机发烫&lt;/td&gt;
&lt;td&gt;设备温度异常升高&lt;/td&gt;
&lt;td&gt;CPU/GPU长期满载、持续定位、频繁屏幕唤醒&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;被系统标记为&amp;quot;后台活动&amp;quot;过高&lt;/td&gt;
&lt;td&gt;系统提示&amp;quot;此App正在消耗大量电池&amp;quot;&lt;/td&gt;
&lt;td&gt;后台任务未合理调度，违反能效规则&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;苹果对&amp;quot;耗电&amp;quot;非常敏感——从iOS 9开始引入低电量模式（Low Power Mode），从iOS 13开始加强后台任务的能效审查（BackgroundTasks框架），从iOS 15开始通过MetricKit将功耗数据开放给开发者。&lt;/p&gt;
&lt;hr&gt;
&lt;h2 id="ios功耗模型概述"&gt;iOS功耗模型概述&lt;/h2&gt;
&lt;p&gt;iOS设备的功耗来源可以分为以下几大类：&lt;/p&gt;
&lt;pre class="mermaid"&gt;flowchart TB
Battery["电池总功耗"]
Battery --&gt; CPU["CPU&lt;br/&gt;计算、编解码"]
Battery --&gt; GPU["GPU&lt;br/&gt;渲染、图层合成"]
Battery --&gt; Screen["屏幕&lt;br/&gt;显示、亮度、刷新率"]
Battery --&gt; Network["网络&lt;br/&gt;蜂窝、WiFi、BLE"]
Battery --&gt; Location["定位&lt;br/&gt;GPS、基站、WiFi定位"]
Battery --&gt; Sensor["传感器&lt;br/&gt;加速度计、陀螺仪、气压计"]
Battery --&gt; Audio["音视频&lt;br/&gt;录制、播放、相机"]
Battery --&gt; Storage["存储&lt;br/&gt;磁盘IO"]
Battery --&gt; IO["外设&lt;br/&gt;蓝牙、NFC、UWB"]
&lt;/pre&gt;
&lt;p&gt;不同硬件模块的功耗量级差异很大。参考苹果WWDC的数据，定位和蜂窝数据通常是&amp;quot;耗电大户&amp;quot;，屏幕是&amp;quot;持续耗电大户&amp;quot;，而CPU/GPU在计算密集时瞬时功耗最高。&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;模块&lt;/th&gt;
&lt;th&gt;典型功耗等级&lt;/th&gt;
&lt;th&gt;特点&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;屏幕&lt;/td&gt;
&lt;td&gt;持续高&lt;/td&gt;
&lt;td&gt;只要亮屏就持续耗电&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;蜂窝数据&lt;/td&gt;
&lt;td&gt;高&lt;/td&gt;
&lt;td&gt;搜索基站、维持连接都耗电&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;GPS定位&lt;/td&gt;
&lt;td&gt;高&lt;/td&gt;
&lt;td&gt;冷启动搜星耗电特别明显&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;CPU/GPU&lt;/td&gt;
&lt;td&gt;中~高&lt;/td&gt;
&lt;td&gt;计算量决定功耗&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;WiFi&lt;/td&gt;
&lt;td&gt;中&lt;/td&gt;
&lt;td&gt;比蜂窝省电&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;蓝牙（BLE）&lt;/td&gt;
&lt;td&gt;低&lt;/td&gt;
&lt;td&gt;低功耗蓝牙专为续航优化&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;传感器&lt;/td&gt;
&lt;td&gt;低~中&lt;/td&gt;
&lt;td&gt;高频采样会显著增加功耗&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;hr&gt;
&lt;h2 id="耗电问题的本质"&gt;耗电问题的本质&lt;/h2&gt;
&lt;p&gt;耗电问题的本质可以用一个简单的公式表示：&lt;/p&gt;</description></item><item><title>iOS中的内存管理</title><link>https://amatsuzero.github.io/LastStand/posts/interview/ios-basics/ios%E4%B8%AD%E7%9A%84%E5%86%85%E5%AD%98%E7%AE%A1%E7%90%86/</link><pubDate>Sat, 02 May 2026 22:32:27 +0800</pubDate><guid>https://amatsuzero.github.io/LastStand/posts/interview/ios-basics/ios%E4%B8%AD%E7%9A%84%E5%86%85%E5%AD%98%E7%AE%A1%E7%90%86/</guid><description>&lt;p&gt;本文将系统介绍iOS中的内存管理机制，从程序内存布局、引用计数原理、ARC机制到系统级内存管理，帮助你建立完整的iOS内存管理知识体系。&lt;/p&gt;
&lt;h2 id="一程序内存布局"&gt;一、程序内存布局&lt;/h2&gt;
&lt;h3 id="内存区域划分"&gt;内存区域划分&lt;/h3&gt;
&lt;p&gt;在iOS应用程序中，内存按照用途和管理方式分为以下几个区域：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-fallback" data-lang="fallback"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;高地址
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;┌─────────────────────────────────────┐
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;│ 栈区 (Stack) │ ↓ 向低地址增长
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;│ 局部变量、函数参数、返回地址 │
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;├─────────────────────────────────────┤
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;│ ↕ │
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;│ 动态分配区 │
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;│ ↕ │
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;├─────────────────────────────────────┤
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;│ 堆区 (Heap) │ ↑ 向高地址增长
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;│ 动态分配的对象实例 │
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;├─────────────────────────────────────┤
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;│ 全局/静态区 (BSS) │
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;│ 未初始化的全局变量和静态变量 │
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;├─────────────────────────────────────┤
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;│ 数据区 (Data) │
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;│ 已初始化的全局变量和静态变量 │
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;├─────────────────────────────────────┤
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;│ 常量区 (Rodata) │
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;│ 字符串常量等 │
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;├─────────────────────────────────────┤
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;│ 代码区 (Text) │
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;│ 编译后的代码 │
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;└─────────────────────────────────────┘
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;低地址
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;各区域的特点：&lt;/p&gt;</description></item><item><title>runtime/maptable.h 作用与实现原理</title><link>https://amatsuzero.github.io/LastStand/posts/ocsourcecodeanalysis/maptable-explained/</link><pubDate>Mon, 01 Jun 2026 19:50:12 +0800</pubDate><guid>https://amatsuzero.github.io/LastStand/posts/ocsourcecodeanalysis/maptable-explained/</guid><description>&lt;p&gt;objc4 runtime NXMapTable 开放寻址哈希表 runtime/maptable.h&lt;/p&gt;
&lt;h1 id="runtimemaptableh-作用与实现原理"&gt;runtime/maptable.h 作用与实现原理&lt;/h1&gt;
&lt;p&gt;&lt;code&gt;runtime/maptable.h&lt;/code&gt; 定义了 Objective-C runtime 里旧 NeXT 风格的 &lt;code&gt;NXMapTable&lt;/code&gt;：一个通用的 &lt;strong&gt;key - value 指针映射表&lt;/strong&gt;。 它不拥有业务对象，只负责把指针或整数形式的 key 映射到指针或整数形式的 value， 并通过回调把“怎么 hash、怎么比较、释放时怎么处理”交给调用方决定。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;存储模型&lt;/strong&gt;连续桶数组，每个桶是 &lt;code&gt;{key, value}&lt;/code&gt;。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;冲突处理&lt;/strong&gt;开放寻址 + 线性探测。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;扩容阈值&lt;/strong&gt;元素数超过桶数的 75% 后翻倍重哈希。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;runtime 用途&lt;/strong&gt;类名表、协议表、future class 表、少量 meta 到 non-meta 映射。&lt;/p&gt;
&lt;p&gt;&lt;a id="role"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;h2 id="阅读路径"&gt;阅读路径&lt;/h2&gt;
&lt;ol&gt;
&lt;li&gt;&lt;a href="#role"&gt;它解决什么问题&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="#hash-vs-map"&gt;和 hashtable2 的区别&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="#shape"&gt;核心数据结构&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="#prototype"&gt;Prototype 回调机制&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="#algorithm"&gt;查找、插入、删除、扩容流程&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="#code"&gt;带注释核心代码&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="#runtime-use"&gt;runtime 中的实际使用&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="#rules"&gt;必须记住的约束&lt;/a&gt;&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;&lt;a id="hash-vs-map"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;h2 id="1-它解决什么问题"&gt;1. 它解决什么问题&lt;/h2&gt;
&lt;p&gt;runtime 需要维护很多“名字到结构体指针”“元类到类”“未来会出现的类名到占位 Class”的映射。 这些映射发生在启动、加载镜像、注册类、查找协议等低层路径上，不能依赖 Objective-C 容器对象。 &lt;code&gt;NXMapTable&lt;/code&gt; 就是一个 C 接口的轻量哈希表。&lt;/p&gt;
&lt;h3 id="它是什么"&gt;它是什么&lt;/h3&gt;
&lt;p&gt;一个 &lt;code&gt;void *&lt;/code&gt; key 到 &lt;code&gt;void *&lt;/code&gt; value 的映射表。key 和 value 可以是指针，也可以把整数强转成指针使用。&lt;/p&gt;</description></item><item><title>JetsamEvent 日志解读</title><link>https://amatsuzero.github.io/LastStand/posts/interview/ios-performance/crash-jetsamevent%E6%97%A5%E5%BF%97%E8%A7%A3%E8%AF%BB/</link><pubDate>Sun, 03 May 2026 23:11:47 +0800</pubDate><guid>https://amatsuzero.github.io/LastStand/posts/interview/ios-performance/crash-jetsamevent%E6%97%A5%E5%BF%97%E8%A7%A3%E8%AF%BB/</guid><description>&lt;p&gt;JetsamEvent 是 iOS 唯一由系统官方生成、且专门记录&amp;quot;因内存原因终止进程&amp;quot;的日志。它不记录线程堆栈，却完整刻画了&lt;strong&gt;发生强杀那一刻&lt;/strong&gt;整机的内存分布——这使它成为 OOM 归因、阈值建模、后台生命周期治理最权威的数据源。&lt;/p&gt;
&lt;p&gt;本文聚焦 JetsamEvent 日志本身：存放位置、文件结构、字段含义、&lt;code&gt;reason&lt;/code&gt; 类型、案例解读、自动化批量解析脚本，以及机型内存上限/iOS 版本差异等实战要点。OOM 监控治理的整体方法论见 &lt;a href="https://amatsuzero.github.io/LastStand/posts/interview/ios-performance/crash-%E6%B2%BB%E7%90%86/#8-oomout-of-memory%E5%B4%A9%E6%BA%83"&gt;崩溃-治理&lt;/a&gt;。&lt;/p&gt;
&lt;hr&gt;
&lt;h2 id="1-jetsam-与-jetsamevent-是什么"&gt;1. Jetsam 与 JetsamEvent 是什么&lt;/h2&gt;
&lt;p&gt;iOS 通过 XNU 内核的 &lt;code&gt;memorystatus&lt;/code&gt; 子系统（俗称 Jetsam）做整机内存管理：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;前台/后台进程按 Jetsam 优先级排序；&lt;/li&gt;
&lt;li&gt;当系统整体可用物理页（&lt;code&gt;vm_page_free_count&lt;/code&gt;）或单个进程 &lt;code&gt;phys_footprint&lt;/code&gt; 触发阈值时，按优先级杀掉进程；&lt;/li&gt;
&lt;li&gt;被杀时，内核在 &lt;code&gt;/var/mobile/Library/Logs/CrashReporter/&lt;/code&gt; 生成 &lt;code&gt;JetsamEvent-yyyy-MM-dd-HHmmss.ips&lt;/code&gt; 文件，并通过 &lt;code&gt;DiagnosticsReporting&lt;/code&gt; 暴露给 &lt;em&gt;设置 → 隐私与安全性 → 分析与改进 → 分析数据&lt;/em&gt;。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;需要理解两个关键结论：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;JetsamEvent 不是单个进程的崩溃日志，而是整机一次 Jetsam 事件的快照。&lt;/strong&gt; 一个文件里往往包含几十个进程条目，只有其中一个（或少数）被真正杀掉；其余进程是作为&amp;quot;当时整机内存画像&amp;quot;被附带记录。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;JetsamEvent 不含线程堆栈。&lt;/strong&gt; 它的价值在于告诉你&amp;quot;谁占用了多少内存&amp;quot;和&amp;quot;为什么被杀&amp;quot;，而不是&amp;quot;在哪一行代码被杀&amp;quot;。堆栈需要由 App 自己的 Memory Dump / MetricKit 补齐。&lt;/li&gt;
&lt;/ol&gt;
&lt;hr&gt;
&lt;h2 id="2-获取方式"&gt;2. 获取方式&lt;/h2&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;场景&lt;/th&gt;
&lt;th&gt;路径&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;真机设置页查看&lt;/td&gt;
&lt;td&gt;设置 → 隐私与安全性 → 分析与改进 → 分析数据，文件名 &lt;code&gt;JetsamEvent-*.ips&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Xcode 连接真机&lt;/td&gt;
&lt;td&gt;Window → Devices and Simulators → 选中设备 → View Device Logs&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;sysdiagnose 包&lt;/td&gt;
&lt;td&gt;解压后位于 &lt;code&gt;crashes_and_spins/*.ips&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;越狱设备&lt;/td&gt;
&lt;td&gt;&lt;code&gt;/var/mobile/Library/Logs/CrashReporter/JetsamEvent-*.ips&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;自动上报&lt;/td&gt;
&lt;td&gt;App 下次启动时扫描沙盒外的 Apple 日志目录不可行，只能依赖 &lt;code&gt;MetricKit&lt;/code&gt; 的 &lt;code&gt;MXCrashDiagnostic&lt;/code&gt;/&lt;code&gt;MXAppExitMetric&lt;/code&gt;（iOS 14+）&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;blockquote&gt;
&lt;p&gt;⚠️ iOS 沙盒下 App 无法直接读取 &lt;code&gt;/var/mobile/Library/Logs/&lt;/code&gt; 的原始 ips 文件，线上规模化采集必须走 MetricKit。JetsamEvent 原始日志主要用于研发期抓真机、或用户反馈场景的手工分析。&lt;/p&gt;</description></item><item><title>iOS中的数据库</title><link>https://amatsuzero.github.io/LastStand/posts/interview/ios-basics/ios%E4%B8%AD%E7%9A%84%E6%95%B0%E6%8D%AE%E5%BA%93/</link><pubDate>Sat, 02 May 2026 22:32:27 +0800</pubDate><guid>https://amatsuzero.github.io/LastStand/posts/interview/ios-basics/ios%E4%B8%AD%E7%9A%84%E6%95%B0%E6%8D%AE%E5%BA%93/</guid><description>&lt;p&gt;数据持久化是移动端开发的核心能力之一。iOS提供了从轻量级KV存储到完整关系数据库的多层次方案。本文将从底层存储原理出发，系统性地梳理iOS中各类数据库与持久化技术的设计思想、实现机制和适用场景。&lt;/p&gt;
&lt;h2 id="一ios数据持久化方案全景"&gt;一、iOS数据持久化方案全景&lt;/h2&gt;
&lt;p&gt;iOS中常见的数据持久化方案，按数据复杂度和使用场景可分为以下几层：&lt;/p&gt;
&lt;pre class="mermaid"&gt;graph TD
subgraph KV["轻量级KV存储"]
A["UserDefaults&lt;br/&gt;plist序列化"]
B["Keychain&lt;br/&gt;加密存储"]
C["MMKV&lt;br/&gt;mmap + protobuf"]
end
subgraph FILE["文件存储"]
D["plist / JSON"]
E["NSCoding / Codable&lt;br/&gt;归档"]
end
subgraph SQL["关系数据库"]
F["SQLite&lt;br/&gt;C语言API"]
G["FMDB&lt;br/&gt;OC封装"]
H["WCDB&lt;br/&gt;ORM + 加密"]
end
subgraph ORM["ORM框架"]
I["Core Data&lt;br/&gt;Apple官方"]
J["Realm&lt;br/&gt;零拷贝"]
K["SwiftData&lt;br/&gt;Swift原生"]
end
KV --&gt; |"数据结构更复杂"| FILE
FILE --&gt; |"需要结构化查询"| SQL
SQL --&gt; |"需要对象映射"| ORM
&lt;/pre&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;方案&lt;/th&gt;
&lt;th&gt;数据模型&lt;/th&gt;
&lt;th&gt;查询能力&lt;/th&gt;
&lt;th&gt;线程安全&lt;/th&gt;
&lt;th&gt;加密&lt;/th&gt;
&lt;th&gt;适用场景&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;UserDefaults&lt;/td&gt;
&lt;td&gt;KV (plist类型)&lt;/td&gt;
&lt;td&gt;Key查找&lt;/td&gt;
&lt;td&gt;线程安全&lt;/td&gt;
&lt;td&gt;无&lt;/td&gt;
&lt;td&gt;用户偏好、简单配置&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Keychain&lt;/td&gt;
&lt;td&gt;KV (Data)&lt;/td&gt;
&lt;td&gt;Key查找&lt;/td&gt;
&lt;td&gt;线程安全&lt;/td&gt;
&lt;td&gt;系统加密&lt;/td&gt;
&lt;td&gt;密码、Token、证书&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;MMKV&lt;/td&gt;
&lt;td&gt;KV (protobuf)&lt;/td&gt;
&lt;td&gt;Key查找&lt;/td&gt;
&lt;td&gt;线程安全&lt;/td&gt;
&lt;td&gt;可选AES&lt;/td&gt;
&lt;td&gt;高频读写的KV数据&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;plist/JSON文件&lt;/td&gt;
&lt;td&gt;字典/数组&lt;/td&gt;
&lt;td&gt;无&lt;/td&gt;
&lt;td&gt;不安全&lt;/td&gt;
&lt;td&gt;无&lt;/td&gt;
&lt;td&gt;静态配置、缓存&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;NSCoding/Codable&lt;/td&gt;
&lt;td&gt;对象图&lt;/td&gt;
&lt;td&gt;无&lt;/td&gt;
&lt;td&gt;不安全&lt;/td&gt;
&lt;td&gt;无&lt;/td&gt;
&lt;td&gt;对象序列化&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;SQLite&lt;/td&gt;
&lt;td&gt;关系表&lt;/td&gt;
&lt;td&gt;SQL&lt;/td&gt;
&lt;td&gt;需手动处理&lt;/td&gt;
&lt;td&gt;可选(SQLCipher)&lt;/td&gt;
&lt;td&gt;结构化数据、复杂查询&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;FMDB&lt;/td&gt;
&lt;td&gt;关系表&lt;/td&gt;
&lt;td&gt;SQL&lt;/td&gt;
&lt;td&gt;FMDatabaseQueue&lt;/td&gt;
&lt;td&gt;可选&lt;/td&gt;
&lt;td&gt;SQLite的OC封装&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;WCDB&lt;/td&gt;
&lt;td&gt;关系表+ORM&lt;/td&gt;
&lt;td&gt;SQL+ORM&lt;/td&gt;
&lt;td&gt;自动管理&lt;/td&gt;
&lt;td&gt;内置&lt;/td&gt;
&lt;td&gt;高性能结构化存储&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Core Data&lt;/td&gt;
&lt;td&gt;对象图&lt;/td&gt;
&lt;td&gt;NSPredicate&lt;/td&gt;
&lt;td&gt;NSManagedObjectContext&lt;/td&gt;
&lt;td&gt;无&lt;/td&gt;
&lt;td&gt;复杂对象关系&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Realm&lt;/td&gt;
&lt;td&gt;对象&lt;/td&gt;
&lt;td&gt;类型安全查询&lt;/td&gt;
&lt;td&gt;对象冻结&lt;/td&gt;
&lt;td&gt;可选AES&lt;/td&gt;
&lt;td&gt;高性能对象存储&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;SwiftData&lt;/td&gt;
&lt;td&gt;Swift对象&lt;/td&gt;
&lt;td&gt;#Predicate宏&lt;/td&gt;
&lt;td&gt;ModelContext&lt;/td&gt;
&lt;td&gt;无&lt;/td&gt;
&lt;td&gt;Swift原生数据持久化&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;h2 id="二轻量级kv存储"&gt;二、轻量级KV存储&lt;/h2&gt;
&lt;h3 id="21-userdefaults"&gt;2.1 UserDefaults&lt;/h3&gt;
&lt;p&gt;UserDefaults是iOS最常用的轻量级存储方案，底层将数据以plist格式序列化到磁盘。&lt;/p&gt;</description></item><item><title>崩溃-Mach异常</title><link>https://amatsuzero.github.io/LastStand/posts/interview/ios-performance/crash-mach%E5%BC%82%E5%B8%B8/</link><pubDate>Sun, 03 May 2026 23:11:47 +0800</pubDate><guid>https://amatsuzero.github.io/LastStand/posts/interview/ios-performance/crash-mach%E5%BC%82%E5%B8%B8/</guid><description>&lt;p&gt;本文深入介绍Mach异常的底层实现细节，包括端口操作、消息机制以及如何实现自定义的Mach异常处理器。&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;关于Mach异常的基础概念（Task、Thread、Port、Message）和异常端口的查找顺序，请参考 &lt;a href="https://amatsuzero.github.io/LastStand/posts/interview/ios-performance/crash-%E5%8E%9F%E7%90%86/"&gt;崩溃-原理&lt;/a&gt;。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;hr&gt;
&lt;h2 id="mach端口详解"&gt;Mach端口详解&lt;/h2&gt;
&lt;h3 id="端口权限"&gt;端口权限&lt;/h3&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-plaintext" data-lang="plaintext"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;端口权限类型：
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;┌─────────────────────────────────────────────────────────────┐
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;│ 端口权限 │
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;├─────────────────────────────────────────────────────────────┤
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;│ │
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;│ MACH_PORT_RIGHT_SEND │
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;│ ├── 发送权限 │
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;│ ├── 可以向端口发送消息 │
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;│ └── 可以复制给其他任务 │
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;│ │
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;│ MACH_PORT_RIGHT_RECEIVE │
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;│ ├── 接收权限 │
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;│ ├── 可以从端口接收消息 │
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;│ ├── 只能有一个持有者 │
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;│ └── 持有者销毁时端口销毁 │
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;│ │
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;│ MACH_PORT_RIGHT_SEND_ONCE │
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;│ ├── 一次性发送权限 │
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;│ └── 发送一次后自动失效 │
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;│ │
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;│ MACH_PORT_RIGHT_PORT_SET │
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;│ ├── 端口集合权限 │
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;│ └── 可以同时监听多个端口 │
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;│ │
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;│ MACH_PORT_RIGHT_DEAD_NAME │
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;│ ├── 死名权限 │
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;│ └── 端口已销毁但名字仍存在 │
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;│ │
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;└─────────────────────────────────────────────────────────────┘
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h3 id="端口操作"&gt;端口操作&lt;/h3&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-c" data-lang="c"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;#include&lt;/span&gt; &lt;span style="color:#75715e"&gt;&amp;lt;mach/mach.h&amp;gt;&lt;/span&gt;&lt;span style="color:#75715e"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;// 分配新端口
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;mach_port_t&lt;/span&gt; port;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;kern_return_t&lt;/span&gt; kr &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;mach_port_allocate&lt;/span&gt;(
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;mach_task_self&lt;/span&gt;(), &lt;span style="color:#75715e"&gt;// 当前任务
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; MACH_PORT_RIGHT_RECEIVE, &lt;span style="color:#75715e"&gt;// 接收权限
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;&amp;amp;&lt;/span&gt;port &lt;span style="color:#75715e"&gt;// 输出端口名
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;// 添加发送权限
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;kr &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;mach_port_insert_right&lt;/span&gt;(
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;mach_task_self&lt;/span&gt;(),
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; port,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; port,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; MACH_MSG_TYPE_MAKE_SEND &lt;span style="color:#75715e"&gt;// 创建发送权限
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;// 销毁端口
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;kr &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;mach_port_destroy&lt;/span&gt;(&lt;span style="color:#a6e22e"&gt;mach_task_self&lt;/span&gt;(), port);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;// 释放端口权限
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;kr &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;mach_port_deallocate&lt;/span&gt;(&lt;span style="color:#a6e22e"&gt;mach_task_self&lt;/span&gt;(), port);
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;hr&gt;
&lt;h2 id="mach消息"&gt;Mach消息&lt;/h2&gt;
&lt;h3 id="消息结构"&gt;消息结构&lt;/h3&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-c" data-lang="c"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;// 消息头部
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;typedef&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;struct&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;mach_msg_bits_t&lt;/span&gt; msgh_bits; &lt;span style="color:#75715e"&gt;// 消息类型和权限
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;mach_msg_size_t&lt;/span&gt; msgh_size; &lt;span style="color:#75715e"&gt;// 消息大小
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;mach_port_t&lt;/span&gt; msgh_remote_port; &lt;span style="color:#75715e"&gt;// 目标端口
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;mach_port_t&lt;/span&gt; msgh_local_port; &lt;span style="color:#75715e"&gt;// 本地端口（用于回复）
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;mach_port_name_t&lt;/span&gt; msgh_voucher_port;&lt;span style="color:#75715e"&gt;// 凭证端口
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;mach_msg_id_t&lt;/span&gt; msgh_id; &lt;span style="color:#75715e"&gt;// 消息ID
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;} &lt;span style="color:#66d9ef"&gt;mach_msg_header_t&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;// 完整消息示例
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;typedef&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;struct&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;mach_msg_header_t&lt;/span&gt; header;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#75715e"&gt;// 可选的消息体
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;mach_msg_body_t&lt;/span&gt; body;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#75715e"&gt;// 可选的端口描述符
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;mach_msg_port_descriptor_t&lt;/span&gt; port;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#75715e"&gt;// 可选的数据
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;char&lt;/span&gt; data[&lt;span style="color:#ae81ff"&gt;256&lt;/span&gt;];
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;} MyMessage;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h3 id="消息发送与接收"&gt;消息发送与接收&lt;/h3&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-c" data-lang="c"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;// 发送消息
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;kern_return_t&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;send_message&lt;/span&gt;(&lt;span style="color:#66d9ef"&gt;mach_port_t&lt;/span&gt; port, &lt;span style="color:#66d9ef"&gt;const&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;char&lt;/span&gt; &lt;span style="color:#f92672"&gt;*&lt;/span&gt;data, &lt;span style="color:#66d9ef"&gt;size_t&lt;/span&gt; len) {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;struct&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;mach_msg_header_t&lt;/span&gt; header;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;char&lt;/span&gt; data[&lt;span style="color:#ae81ff"&gt;256&lt;/span&gt;];
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; } message;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; message.header.msgh_bits &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;MACH_MSGH_BITS&lt;/span&gt;(MACH_MSG_TYPE_COPY_SEND, &lt;span style="color:#ae81ff"&gt;0&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; message.header.msgh_size &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;sizeof&lt;/span&gt;(message);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; message.header.msgh_remote_port &lt;span style="color:#f92672"&gt;=&lt;/span&gt; port;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; message.header.msgh_local_port &lt;span style="color:#f92672"&gt;=&lt;/span&gt; MACH_PORT_NULL;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; message.header.msgh_id &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;0&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;size_t&lt;/span&gt; copy_len &lt;span style="color:#f92672"&gt;=&lt;/span&gt; len &lt;span style="color:#f92672"&gt;&amp;lt;&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;sizeof&lt;/span&gt;(message.data) &lt;span style="color:#f92672"&gt;?&lt;/span&gt; len : &lt;span style="color:#66d9ef"&gt;sizeof&lt;/span&gt;(message.data);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;memcpy&lt;/span&gt;(message.data, data, copy_len);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;return&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;mach_msg&lt;/span&gt;(
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;&amp;amp;&lt;/span&gt;message.header,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; MACH_SEND_MSG, &lt;span style="color:#75715e"&gt;// 发送
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;sizeof&lt;/span&gt;(message), &lt;span style="color:#75715e"&gt;// 发送大小
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#ae81ff"&gt;0&lt;/span&gt;, &lt;span style="color:#75715e"&gt;// 接收大小
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; MACH_PORT_NULL, &lt;span style="color:#75715e"&gt;// 接收端口
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; MACH_MSG_TIMEOUT_NONE, &lt;span style="color:#75715e"&gt;// 超时
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; MACH_PORT_NULL &lt;span style="color:#75715e"&gt;// 通知端口
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; );
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;// 接收消息
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;kern_return_t&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;receive_message&lt;/span&gt;(&lt;span style="color:#66d9ef"&gt;mach_port_t&lt;/span&gt; port) {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;struct&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;mach_msg_header_t&lt;/span&gt; header;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;char&lt;/span&gt; data[&lt;span style="color:#ae81ff"&gt;256&lt;/span&gt;];
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; } message;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;kern_return_t&lt;/span&gt; kr &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;mach_msg&lt;/span&gt;(
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;&amp;amp;&lt;/span&gt;message.header,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; MACH_RCV_MSG, &lt;span style="color:#75715e"&gt;// 接收
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#ae81ff"&gt;0&lt;/span&gt;, &lt;span style="color:#75715e"&gt;// 发送大小
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;sizeof&lt;/span&gt;(message), &lt;span style="color:#75715e"&gt;// 接收大小
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; port, &lt;span style="color:#75715e"&gt;// 接收端口
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; MACH_MSG_TIMEOUT_NONE, &lt;span style="color:#75715e"&gt;// 超时
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; MACH_PORT_NULL &lt;span style="color:#75715e"&gt;// 通知端口
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; );
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;if&lt;/span&gt; (kr &lt;span style="color:#f92672"&gt;==&lt;/span&gt; MACH_MSG_SUCCESS) {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#75715e"&gt;// 处理消息
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;printf&lt;/span&gt;(&lt;span style="color:#e6db74"&gt;&amp;#34;Received: %s&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;\n&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#34;&lt;/span&gt;, message.data);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; }
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;return&lt;/span&gt; kr;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;hr&gt;
&lt;h2 id="异常端口操作"&gt;异常端口操作&lt;/h2&gt;
&lt;h3 id="设置异常端口"&gt;设置异常端口&lt;/h3&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-c" data-lang="c"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;#include&lt;/span&gt; &lt;span style="color:#75715e"&gt;&amp;lt;mach/mach.h&amp;gt;&lt;/span&gt;&lt;span style="color:#75715e"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;// 设置任务级异常端口
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;kern_return_t&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;setup_task_exception_port&lt;/span&gt;(&lt;span style="color:#66d9ef"&gt;mach_port_t&lt;/span&gt; exception_port) {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#75715e"&gt;// 异常类型掩码
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;exception_mask_t&lt;/span&gt; mask &lt;span style="color:#f92672"&gt;=&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; EXC_MASK_BAD_ACCESS &lt;span style="color:#f92672"&gt;|&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; EXC_MASK_BAD_INSTRUCTION &lt;span style="color:#f92672"&gt;|&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; EXC_MASK_ARITHMETIC &lt;span style="color:#f92672"&gt;|&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; EXC_MASK_BREAKPOINT &lt;span style="color:#f92672"&gt;|&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; EXC_MASK_SOFTWARE;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;return&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;task_set_exception_ports&lt;/span&gt;(
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;mach_task_self&lt;/span&gt;(),
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; mask,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; exception_port,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; EXCEPTION_DEFAULT &lt;span style="color:#f92672"&gt;|&lt;/span&gt; MACH_EXCEPTION_CODES,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; THREAD_STATE_NONE
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; );
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;// 获取当前异常端口
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;kern_return_t&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;get_exception_ports&lt;/span&gt;(&lt;span style="color:#66d9ef"&gt;void&lt;/span&gt;) {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;exception_mask_t&lt;/span&gt; masks[EXC_TYPES_COUNT];
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;mach_msg_type_number_t&lt;/span&gt; count &lt;span style="color:#f92672"&gt;=&lt;/span&gt; EXC_TYPES_COUNT;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;mach_port_t&lt;/span&gt; ports[EXC_TYPES_COUNT];
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;exception_behavior_t&lt;/span&gt; behaviors[EXC_TYPES_COUNT];
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;thread_state_flavor_t&lt;/span&gt; flavors[EXC_TYPES_COUNT];
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;return&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;task_get_exception_ports&lt;/span&gt;(
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;mach_task_self&lt;/span&gt;(),
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; EXC_MASK_ALL,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; masks,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;&amp;amp;&lt;/span&gt;count,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; ports,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; behaviors,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; flavors
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; );
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;hr&gt;
&lt;h2 id="异常处理流程"&gt;异常处理流程&lt;/h2&gt;
&lt;h3 id="完整的异常处理流程"&gt;完整的异常处理流程&lt;/h3&gt;
&lt;pre class="mermaid"&gt;flowchart TD
A["1. 硬件检测到异常&lt;br/&gt;CPU执行非法操作，触发硬件中断"] --&gt; B["2. 陷入内核&lt;br/&gt;CPU切换到内核态，执行异常处理程序"]
B --&gt; C["3. 内核构造异常消息&lt;br/&gt;创建包含异常信息的Mach消息"]
C --&gt; D["4. 发送到异常端口&lt;br/&gt;按照 Thread → Task → Host 顺序查找端口"]
D --&gt; E["5. 等待回复&lt;br/&gt;内核暂停线程，等待异常处理程序的回复"]
E --&gt; F{"6. 处理回复"}
F --&gt;|KERN_SUCCESS| G["恢复线程执行"]
F --&gt;|其他| H["转换为Unix信号或终止进程"]
&lt;/pre&gt;
&lt;h3 id="异常消息格式"&gt;异常消息格式&lt;/h3&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-c" data-lang="c"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;// 异常消息结构
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;typedef&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;struct&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;mach_msg_header_t&lt;/span&gt; Head;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#75715e"&gt;// 消息体
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;mach_msg_body_t&lt;/span&gt; msgh_body;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;mach_msg_port_descriptor_t&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;thread&lt;/span&gt;; &lt;span style="color:#75715e"&gt;// 发生异常的线程
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;mach_msg_port_descriptor_t&lt;/span&gt; task; &lt;span style="color:#75715e"&gt;// 发生异常的任务
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#75715e"&gt;// 异常信息
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; NDR_record_t NDR;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;exception_type_t&lt;/span&gt; exception; &lt;span style="color:#75715e"&gt;// 异常类型
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;mach_msg_type_number_t&lt;/span&gt; codeCnt; &lt;span style="color:#75715e"&gt;// 代码数量
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;int64_t&lt;/span&gt; code[&lt;span style="color:#ae81ff"&gt;2&lt;/span&gt;]; &lt;span style="color:#75715e"&gt;// 异常代码
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;} __Request__mach_exception_raise_t;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;// 异常回复消息
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;typedef&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;struct&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;mach_msg_header_t&lt;/span&gt; Head;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; NDR_record_t NDR;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;kern_return_t&lt;/span&gt; RetCode; &lt;span style="color:#75715e"&gt;// 返回码
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;} __Reply__mach_exception_raise_t;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;hr&gt;
&lt;h2 id="实现mach异常处理器"&gt;实现Mach异常处理器&lt;/h2&gt;
&lt;h3 id="完整示例"&gt;完整示例&lt;/h3&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-c" data-lang="c"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;#include&lt;/span&gt; &lt;span style="color:#75715e"&gt;&amp;lt;mach/mach.h&amp;gt;&lt;/span&gt;&lt;span style="color:#75715e"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;#include&lt;/span&gt; &lt;span style="color:#75715e"&gt;&amp;lt;pthread.h&amp;gt;&lt;/span&gt;&lt;span style="color:#75715e"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;// 异常处理线程
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;static&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;pthread_t&lt;/span&gt; exception_thread;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;static&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;mach_port_t&lt;/span&gt; exception_port;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;// 保存原始异常端口
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;static&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;mach_port_t&lt;/span&gt; original_exception_port;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;static&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;exception_behavior_t&lt;/span&gt; original_behavior;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;static&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;thread_state_flavor_t&lt;/span&gt; original_flavor;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;// 异常处理函数
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;static&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;kern_return_t&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;handle_exception&lt;/span&gt;(
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;mach_port_t&lt;/span&gt; exception_port,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;mach_port_t&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;thread&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;mach_port_t&lt;/span&gt; task,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;exception_type_t&lt;/span&gt; exception,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;mach_exception_data_t&lt;/span&gt; code,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;mach_msg_type_number_t&lt;/span&gt; code_count
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;) {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#75715e"&gt;// 获取线程状态（ARM64架构）
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#75715e"&gt;// 注意：如需支持x86_64模拟器，需要使用x86_thread_state64_t和X86_THREAD_STATE64
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;#if defined(__arm64__)
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;arm_thread_state64_t&lt;/span&gt; state;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;mach_msg_type_number_t&lt;/span&gt; state_count &lt;span style="color:#f92672"&gt;=&lt;/span&gt; ARM_THREAD_STATE64_COUNT;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;thread_get_state&lt;/span&gt;(&lt;span style="color:#66d9ef"&gt;thread&lt;/span&gt;, ARM_THREAD_STATE64,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; (&lt;span style="color:#66d9ef"&gt;thread_state_t&lt;/span&gt;)&lt;span style="color:#f92672"&gt;&amp;amp;&lt;/span&gt;state, &lt;span style="color:#f92672"&gt;&amp;amp;&lt;/span&gt;state_count);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#75715e"&gt;// 记录崩溃信息
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;printf&lt;/span&gt;(&lt;span style="color:#e6db74"&gt;&amp;#34;Exception: %d&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;\n&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#34;&lt;/span&gt;, exception);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;printf&lt;/span&gt;(&lt;span style="color:#e6db74"&gt;&amp;#34;Code: 0x%llx, 0x%llx&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;\n&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#34;&lt;/span&gt;, code[&lt;span style="color:#ae81ff"&gt;0&lt;/span&gt;], code[&lt;span style="color:#ae81ff"&gt;1&lt;/span&gt;]);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;printf&lt;/span&gt;(&lt;span style="color:#e6db74"&gt;&amp;#34;PC: 0x%llx&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;\n&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#34;&lt;/span&gt;, (&lt;span style="color:#66d9ef"&gt;unsigned&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;long&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;long&lt;/span&gt;)state.__pc);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;printf&lt;/span&gt;(&lt;span style="color:#e6db74"&gt;&amp;#34;LR: 0x%llx&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;\n&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#34;&lt;/span&gt;, (&lt;span style="color:#66d9ef"&gt;unsigned&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;long&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;long&lt;/span&gt;)state.__lr);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;#endif
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#75715e"&gt;// 采集堆栈（需要自行实现）
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#75715e"&gt;// collect_backtrace(thread);
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#75715e"&gt;// 保存崩溃日志（需要自行实现）
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#75715e"&gt;// save_crash_log();
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#75715e"&gt;// 返回失败，让系统继续处理（转换为信号）
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;return&lt;/span&gt; KERN_FAILURE;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;// 异常处理线程主函数
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;static&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;void&lt;/span&gt; &lt;span style="color:#f92672"&gt;*&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;exception_handler_thread&lt;/span&gt;(&lt;span style="color:#66d9ef"&gt;void&lt;/span&gt; &lt;span style="color:#f92672"&gt;*&lt;/span&gt;arg) {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;kern_return_t&lt;/span&gt; kr;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;while&lt;/span&gt; (&lt;span style="color:#ae81ff"&gt;1&lt;/span&gt;) {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#75715e"&gt;// 接收异常消息
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;struct&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;mach_msg_header_t&lt;/span&gt; head;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;mach_msg_body_t&lt;/span&gt; body;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;mach_msg_port_descriptor_t&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;thread&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;mach_msg_port_descriptor_t&lt;/span&gt; task;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; NDR_record_t NDR;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;exception_type_t&lt;/span&gt; exception;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;mach_msg_type_number_t&lt;/span&gt; code_count;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;int64_t&lt;/span&gt; code[&lt;span style="color:#ae81ff"&gt;2&lt;/span&gt;];
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;int&lt;/span&gt; flavor;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;mach_msg_type_number_t&lt;/span&gt; state_count;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;natural_t&lt;/span&gt; state[&lt;span style="color:#ae81ff"&gt;224&lt;/span&gt;];
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; } request;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;struct&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;mach_msg_header_t&lt;/span&gt; head;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; NDR_record_t NDR;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;kern_return_t&lt;/span&gt; ret_code;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; } reply;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#75715e"&gt;// 接收消息
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; kr &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;mach_msg&lt;/span&gt;(
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;&amp;amp;&lt;/span&gt;request.head,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; MACH_RCV_MSG &lt;span style="color:#f92672"&gt;|&lt;/span&gt; MACH_RCV_LARGE,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#ae81ff"&gt;0&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;sizeof&lt;/span&gt;(request),
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; exception_port,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; MACH_MSG_TIMEOUT_NONE,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; MACH_PORT_NULL
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; );
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;if&lt;/span&gt; (kr &lt;span style="color:#f92672"&gt;!=&lt;/span&gt; MACH_MSG_SUCCESS) {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;continue&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; }
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#75715e"&gt;// 处理异常
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; kr &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;handle_exception&lt;/span&gt;(
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; exception_port,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; request.&lt;span style="color:#66d9ef"&gt;thread&lt;/span&gt;.name,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; request.task.name,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; request.exception,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; request.code,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; request.code_count
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; );
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#75715e"&gt;// 发送回复
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; reply.head.msgh_bits &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;MACH_MSGH_BITS&lt;/span&gt;(MACH_MSG_TYPE_MOVE_SEND_ONCE, &lt;span style="color:#ae81ff"&gt;0&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; reply.head.msgh_size &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;sizeof&lt;/span&gt;(reply);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; reply.head.msgh_remote_port &lt;span style="color:#f92672"&gt;=&lt;/span&gt; request.head.msgh_remote_port;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; reply.head.msgh_local_port &lt;span style="color:#f92672"&gt;=&lt;/span&gt; MACH_PORT_NULL;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#75715e"&gt;// Mach IPC惯例：回复消息ID = 请求消息ID + 100
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; reply.head.msgh_id &lt;span style="color:#f92672"&gt;=&lt;/span&gt; request.head.msgh_id &lt;span style="color:#f92672"&gt;+&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;100&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; reply.NDR &lt;span style="color:#f92672"&gt;=&lt;/span&gt; NDR_record;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; reply.ret_code &lt;span style="color:#f92672"&gt;=&lt;/span&gt; kr;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;mach_msg&lt;/span&gt;(
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;&amp;amp;&lt;/span&gt;reply.head,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; MACH_SEND_MSG,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;sizeof&lt;/span&gt;(reply),
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#ae81ff"&gt;0&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; MACH_PORT_NULL,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; MACH_MSG_TIMEOUT_NONE,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; MACH_PORT_NULL
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; );
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; }
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;return&lt;/span&gt; NULL;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;// 安装异常处理器
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;kern_return_t&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;install_exception_handler&lt;/span&gt;(&lt;span style="color:#66d9ef"&gt;void&lt;/span&gt;) {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;kern_return_t&lt;/span&gt; kr;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#75715e"&gt;// 创建异常端口
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; kr &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;mach_port_allocate&lt;/span&gt;(
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;mach_task_self&lt;/span&gt;(),
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; MACH_PORT_RIGHT_RECEIVE,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;&amp;amp;&lt;/span&gt;exception_port
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; );
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;if&lt;/span&gt; (kr &lt;span style="color:#f92672"&gt;!=&lt;/span&gt; KERN_SUCCESS) &lt;span style="color:#66d9ef"&gt;return&lt;/span&gt; kr;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#75715e"&gt;// 添加发送权限
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; kr &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;mach_port_insert_right&lt;/span&gt;(
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;mach_task_self&lt;/span&gt;(),
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; exception_port,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; exception_port,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; MACH_MSG_TYPE_MAKE_SEND
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; );
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;if&lt;/span&gt; (kr &lt;span style="color:#f92672"&gt;!=&lt;/span&gt; KERN_SUCCESS) &lt;span style="color:#66d9ef"&gt;return&lt;/span&gt; kr;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#75715e"&gt;// 保存原始异常端口
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;exception_mask_t&lt;/span&gt; mask &lt;span style="color:#f92672"&gt;=&lt;/span&gt; EXC_MASK_BAD_ACCESS &lt;span style="color:#f92672"&gt;|&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; EXC_MASK_BAD_INSTRUCTION &lt;span style="color:#f92672"&gt;|&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; EXC_MASK_ARITHMETIC &lt;span style="color:#f92672"&gt;|&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; EXC_MASK_BREAKPOINT;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#75715e"&gt;// 用于接收查询结果的数组
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;exception_mask_t&lt;/span&gt; masks_out[EXC_TYPES_COUNT];
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;mach_port_t&lt;/span&gt; ports_out[EXC_TYPES_COUNT];
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;exception_behavior_t&lt;/span&gt; behaviors_out[EXC_TYPES_COUNT];
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;thread_state_flavor_t&lt;/span&gt; flavors_out[EXC_TYPES_COUNT];
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;mach_msg_type_number_t&lt;/span&gt; count &lt;span style="color:#f92672"&gt;=&lt;/span&gt; EXC_TYPES_COUNT;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; kr &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;task_get_exception_ports&lt;/span&gt;(
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;mach_task_self&lt;/span&gt;(),
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; mask, &lt;span style="color:#75715e"&gt;// 输入：要查询的异常类型掩码
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; masks_out, &lt;span style="color:#75715e"&gt;// 输出：实际的掩码数组
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;&amp;amp;&lt;/span&gt;count, &lt;span style="color:#75715e"&gt;// 输入输出：数组大小
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; ports_out, &lt;span style="color:#75715e"&gt;// 输出：端口数组
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; behaviors_out, &lt;span style="color:#75715e"&gt;// 输出：行为数组
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; flavors_out &lt;span style="color:#75715e"&gt;// 输出：flavor数组
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; );
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#75715e"&gt;// 保存第一个有效的原始端口（简化处理）
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;if&lt;/span&gt; (count &lt;span style="color:#f92672"&gt;&amp;gt;&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;0&lt;/span&gt;) {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; original_exception_port &lt;span style="color:#f92672"&gt;=&lt;/span&gt; ports_out[&lt;span style="color:#ae81ff"&gt;0&lt;/span&gt;];
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; original_behavior &lt;span style="color:#f92672"&gt;=&lt;/span&gt; behaviors_out[&lt;span style="color:#ae81ff"&gt;0&lt;/span&gt;];
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; original_flavor &lt;span style="color:#f92672"&gt;=&lt;/span&gt; flavors_out[&lt;span style="color:#ae81ff"&gt;0&lt;/span&gt;];
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; }
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#75715e"&gt;// 设置新的异常端口
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; kr &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;task_set_exception_ports&lt;/span&gt;(
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;mach_task_self&lt;/span&gt;(),
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; mask,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; exception_port,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; EXCEPTION_DEFAULT &lt;span style="color:#f92672"&gt;|&lt;/span&gt; MACH_EXCEPTION_CODES,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; THREAD_STATE_NONE
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; );
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;if&lt;/span&gt; (kr &lt;span style="color:#f92672"&gt;!=&lt;/span&gt; KERN_SUCCESS) &lt;span style="color:#66d9ef"&gt;return&lt;/span&gt; kr;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#75715e"&gt;// 创建异常处理线程
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;pthread_create&lt;/span&gt;(&lt;span style="color:#f92672"&gt;&amp;amp;&lt;/span&gt;exception_thread, NULL,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; exception_handler_thread, NULL);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;return&lt;/span&gt; KERN_SUCCESS;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;hr&gt;
&lt;h2 id="调试器检测"&gt;调试器检测&lt;/h2&gt;
&lt;p&gt;调试器（如LLDB）通过在Task（任务/进程）级别注册异常端口来优先拦截异常。了解这一机制有助于理解为什么调试时某些崩溃行为会有所不同。&lt;/p&gt;</description></item><item><title>iOS反射</title><link>https://amatsuzero.github.io/LastStand/posts/interview/ios-basics/ios%E5%8F%8D%E5%B0%84/</link><pubDate>Sat, 02 May 2026 22:32:27 +0800</pubDate><guid>https://amatsuzero.github.io/LastStand/posts/interview/ios-basics/ios%E5%8F%8D%E5%B0%84/</guid><description>&lt;p&gt;反射（Reflection）是指程序在运行时检查、访问和修改自身结构（类型、属性、方法等）的能力。在 iOS 开发中，Objective-C 和 Swift 分别提供了不同层次的反射支持：OC 依赖 Runtime 提供完整的动态反射能力，Swift 则通过 Mirror 提供只读的内省能力。&lt;/p&gt;
&lt;h2 id="objective-c-的反射能力"&gt;Objective-C 的反射能力&lt;/h2&gt;
&lt;p&gt;Objective-C 的反射能力完全建立在 Runtime 之上。Runtime 在运行时维护了完整的类型元数据（类对象、元类对象、方法列表、属性列表、成员变量列表、协议列表等），并通过一系列 C 函数 API 暴露给开发者，使得程序可以在运行时动态地查询和修改几乎所有类型信息。&lt;/p&gt;
&lt;p&gt;关于 Runtime 的消息发送、消息转发、Method Swizzling、关联对象等核心能力，请参考 &lt;a href="https://amatsuzero.github.io/LastStand/posts/interview/ios-basics/runtime/"&gt;runtime&lt;/a&gt;。本节聚焦于 Runtime 中与&amp;quot;反射&amp;quot;直接相关的能力——即运行时的类型内省和动态操作。&lt;/p&gt;
&lt;h3 id="类型内省"&gt;类型内省&lt;/h3&gt;
&lt;p&gt;类型内省（Introspection）是反射中最基础的能力——在运行时查询一个对象的类型信息。&lt;/p&gt;
&lt;h4 id="nsobject-提供的内省方法"&gt;NSObject 提供的内省方法&lt;/h4&gt;
&lt;p&gt;&lt;code&gt;NSObject&lt;/code&gt; 定义了一组内省方法，这些方法底层都依赖 Runtime 的 isa 指针和类型元数据来实现：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-objc" data-lang="objc"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;id&lt;/span&gt; obj &lt;span style="color:#f92672"&gt;=&lt;/span&gt; [[NSMutableArray alloc] init];
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;// 类型判断
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;[obj isKindOfClass:[NSArray &lt;span style="color:#66d9ef"&gt;class&lt;/span&gt;]]; &lt;span style="color:#75715e"&gt;// YES — 判断是否是某个类或其子类的实例
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;[obj isMemberOfClass:[NSMutableArray &lt;span style="color:#66d9ef"&gt;class&lt;/span&gt;]]; &lt;span style="color:#75715e"&gt;// YES — 判断是否是某个类的直接实例
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;[obj conformsToProtocol:@protocol(NSCoding)]; &lt;span style="color:#75715e"&gt;// YES — 判断是否遵循某个协议
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;// 方法响应检查
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;[obj respondsToSelector:&lt;span style="color:#66d9ef"&gt;@selector&lt;/span&gt;(addObject:)]; &lt;span style="color:#75715e"&gt;// YES — 判断是否能响应某个消息
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;// 获取类型信息
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;NSStringFromClass([obj &lt;span style="color:#66d9ef"&gt;class&lt;/span&gt;]); &lt;span style="color:#75715e"&gt;// @&amp;#34;__NSArrayM&amp;#34;（真实的私有子类名）
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;NSStringFromSelector(&lt;span style="color:#66d9ef"&gt;@selector&lt;/span&gt;(count)); &lt;span style="color:#75715e"&gt;// @&amp;#34;count&amp;#34;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;需要注意 &lt;code&gt;isKindOfClass:&lt;/code&gt; 和 &lt;code&gt;isMemberOfClass:&lt;/code&gt; 的区别：前者沿继承链向上查找，后者只比较当前类。另外，&lt;code&gt;[obj class]&lt;/code&gt; 返回的可能是私有子类（如类簇 &lt;code&gt;NSArray&lt;/code&gt; 的实际类是 &lt;code&gt;__NSArrayI&lt;/code&gt; 或 &lt;code&gt;__NSArrayM&lt;/code&gt;），而 &lt;code&gt;object_getClass(obj)&lt;/code&gt; 能获取真正的 isa 指向的类（KVO 场景下会是 &lt;code&gt;NSKVONotifying_&lt;/code&gt; 前缀的子类）。&lt;/p&gt;</description></item><item><title>iOS编译原理</title><link>https://amatsuzero.github.io/LastStand/posts/interview/ios-basics/ios%E7%BC%96%E8%AF%91%E5%8E%9F%E7%90%86/</link><pubDate>Sat, 02 May 2026 22:32:27 +0800</pubDate><guid>https://amatsuzero.github.io/LastStand/posts/interview/ios-basics/ios%E7%BC%96%E8%AF%91%E5%8E%9F%E7%90%86/</guid><description>&lt;h2 id="编译器架构llvm-与-clang"&gt;编译器架构：LLVM 与 Clang&lt;/h2&gt;
&lt;p&gt;iOS 开发中的两种主要语言 Objective-C 和 Swift 都基于 LLVM 编译器基础设施。理解 LLVM 的架构是理解 iOS 编译原理的基础。&lt;/p&gt;
&lt;h3 id="llvm-的三段式架构"&gt;LLVM 的三段式架构&lt;/h3&gt;
&lt;p&gt;LLVM 采用经典的&lt;strong&gt;前端-中间表示-后端&lt;/strong&gt;三段式设计，将编译过程解耦为三个独立的阶段：&lt;/p&gt;
&lt;pre class="mermaid"&gt;flowchart LR
subgraph Frontend["前端（Frontend）"]
direction TB
A1["Clang（OC/C/C++）"]
A2["Swift 前端"]
end
subgraph Middle["中间表示"]
direction TB
B1["LLVM IR"]
end
subgraph Backend["后端（Backend）"]
direction TB
C1["arm64（iOS真机）"]
C2["x86_64（模拟器）"]
end
A1 --&gt; B1
A2 --&gt; B1
B1 --&gt; C1
B1 --&gt; C2
&lt;/pre&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;阶段&lt;/th&gt;
&lt;th&gt;职责&lt;/th&gt;
&lt;th&gt;iOS 中的实现&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;前端（Frontend）&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;词法分析、语法分析、语义分析，将源码转换为中间表示&lt;/td&gt;
&lt;td&gt;Clang（OC/C/C++）、Swift 前端&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;中间表示（IR）&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;与语言无关、与平台无关的中间形式，承载优化&lt;/td&gt;
&lt;td&gt;LLVM IR（Swift 还有额外的 SIL 层）&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;后端（Backend）&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;将 IR 转换为目标平台的机器码&lt;/td&gt;
&lt;td&gt;arm64（真机）、x86_64（Intel 模拟器）&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;三段式架构的核心优势是&lt;strong&gt;解耦&lt;/strong&gt;：新增一门语言只需实现一个前端，新增一个目标平台只需实现一个后端，所有语言和平台共享同一套优化基础设施。这正是 Apple 能同时支持 OC 和 Swift 两种语言、多种架构（arm64、x86_64）的技术基础。&lt;/p&gt;</description></item><item><title>崩溃-信号处理</title><link>https://amatsuzero.github.io/LastStand/posts/interview/ios-performance/crash-%E4%BF%A1%E5%8F%B7%E5%A4%84%E7%90%86/</link><pubDate>Sat, 02 May 2026 22:32:27 +0800</pubDate><guid>https://amatsuzero.github.io/LastStand/posts/interview/ios-performance/crash-%E4%BF%A1%E5%8F%B7%E5%A4%84%E7%90%86/</guid><description>&lt;p&gt;Unix信号是进程间通信和异常通知的重要机制。本文详细介绍Unix信号的基础知识、常见崩溃信号以及Signal Handler的正确实现方式。&lt;/p&gt;
&lt;hr&gt;
&lt;h2 id="unix信号基础"&gt;Unix信号基础&lt;/h2&gt;
&lt;h3 id="什么是信号"&gt;什么是信号&lt;/h3&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-plaintext" data-lang="plaintext"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;信号的本质：
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;┌─────────────────────────────────────────────────────────────┐
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;│ Unix信号 │
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;├─────────────────────────────────────────────────────────────┤
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;│ │
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;│ 信号是一种软件中断机制： │
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;│ • 用于通知进程发生了某个事件 │
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;│ • 可以由内核、其他进程或进程自身发送 │
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;│ • 进程可以选择处理、忽略或使用默认行为 │
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;│ │
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;│ 信号的来源： │
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;│ • 硬件异常（如除零、非法内存访问） │
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;│ • 用户输入（如Ctrl+C） │
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;│ • 系统调用（如kill） │
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;│ • 软件条件（如定时器到期） │
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;│ │
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;└─────────────────────────────────────────────────────────────┘
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h3 id="信号的生命周期"&gt;信号的生命周期&lt;/h3&gt;
&lt;pre class="mermaid"&gt;flowchart TD
A["1. 信号产生（Generation）&lt;br/&gt;某个事件触发信号的产生"]
--&gt; B["2. 信号投递（Delivery）&lt;br/&gt;信号被投递到目标进程&lt;br/&gt;此时信号处于pending状态"]
--&gt; C["3. 信号处理（Handling）&lt;br/&gt;进程响应信号，执行以下之一"]
C --&gt; D["执行默认动作"]
C --&gt; E["执行自定义处理函数"]
C --&gt; F["忽略信号"]
&lt;/pre&gt;
&lt;hr&gt;
&lt;h2 id="常见信号类型"&gt;常见信号类型&lt;/h2&gt;
&lt;h3 id="崩溃相关信号"&gt;崩溃相关信号&lt;/h3&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;信号&lt;/th&gt;
&lt;th&gt;编号(macOS/iOS)&lt;/th&gt;
&lt;th&gt;默认动作&lt;/th&gt;
&lt;th&gt;说明&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;SIGABRT&lt;/td&gt;
&lt;td&gt;6&lt;/td&gt;
&lt;td&gt;终止+core&lt;/td&gt;
&lt;td&gt;调用abort()产生&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;SIGBUS&lt;/td&gt;
&lt;td&gt;10&lt;/td&gt;
&lt;td&gt;终止+core&lt;/td&gt;
&lt;td&gt;总线错误&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;SIGFPE&lt;/td&gt;
&lt;td&gt;8&lt;/td&gt;
&lt;td&gt;终止+core&lt;/td&gt;
&lt;td&gt;算术异常&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;SIGILL&lt;/td&gt;
&lt;td&gt;4&lt;/td&gt;
&lt;td&gt;终止+core&lt;/td&gt;
&lt;td&gt;非法指令&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;SIGSEGV&lt;/td&gt;
&lt;td&gt;11&lt;/td&gt;
&lt;td&gt;终止+core&lt;/td&gt;
&lt;td&gt;段错误&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;SIGTRAP&lt;/td&gt;
&lt;td&gt;5&lt;/td&gt;
&lt;td&gt;终止+core&lt;/td&gt;
&lt;td&gt;断点陷阱&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;SIGSYS&lt;/td&gt;
&lt;td&gt;12&lt;/td&gt;
&lt;td&gt;终止+core&lt;/td&gt;
&lt;td&gt;非法系统调用&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;h3 id="其他重要信号"&gt;其他重要信号&lt;/h3&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;信号&lt;/th&gt;
&lt;th&gt;编号&lt;/th&gt;
&lt;th&gt;默认动作&lt;/th&gt;
&lt;th&gt;说明&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;SIGKILL&lt;/td&gt;
&lt;td&gt;9&lt;/td&gt;
&lt;td&gt;终止&lt;/td&gt;
&lt;td&gt;强制终止（不可捕获）&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;SIGTERM&lt;/td&gt;
&lt;td&gt;15&lt;/td&gt;
&lt;td&gt;终止&lt;/td&gt;
&lt;td&gt;请求终止&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;SIGINT&lt;/td&gt;
&lt;td&gt;2&lt;/td&gt;
&lt;td&gt;终止&lt;/td&gt;
&lt;td&gt;中断（Ctrl+C）&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;SIGQUIT&lt;/td&gt;
&lt;td&gt;3&lt;/td&gt;
&lt;td&gt;终止+core&lt;/td&gt;
&lt;td&gt;退出（Ctrl+\）&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;SIGPIPE&lt;/td&gt;
&lt;td&gt;13&lt;/td&gt;
&lt;td&gt;终止&lt;/td&gt;
&lt;td&gt;管道破裂&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;SIGALRM&lt;/td&gt;
&lt;td&gt;14&lt;/td&gt;
&lt;td&gt;终止&lt;/td&gt;
&lt;td&gt;定时器到期&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;h3 id="信号详解"&gt;信号详解&lt;/h3&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-plaintext" data-lang="plaintext"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;SIGABRT (6)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;────────────────────────────────────────
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;触发条件：
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;• 调用abort()函数
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;• 未捕获的NSException
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;• C++ exception未处理
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;• assert失败（某些情况）
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;特点：
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;• 可以捕获和处理
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;• 通常表示程序主动终止
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;SIGSEGV (11)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;────────────────────────────────────────
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;触发条件：
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;• 访问无效内存地址
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;• 空指针解引用
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;• 栈溢出
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;• 访问已释放的内存
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;对应Mach异常：
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;• EXC_BAD_ACCESS (KERN_INVALID_ADDRESS)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;• EXC_BAD_ACCESS (KERN_PROTECTION_FAILURE)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;SIGBUS (10)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;────────────────────────────────────────
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;触发条件：
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;• 内存对齐错误
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;• 访问不存在的物理地址
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;• mmap映射失效
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;与SIGSEGV的区别：
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;• SIGSEGV: 虚拟地址层面的问题（地址未映射或权限不足）
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;• SIGBUS: 物理地址层面的问题（对齐错误、硬件问题等）
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;SIGILL (4)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;────────────────────────────────────────
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;触发条件：
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;• 执行非法指令
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;• Swift强制解包nil
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;• 代码段损坏
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;对应Mach异常：
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;• EXC_BAD_INSTRUCTION
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;SIGFPE (8)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;────────────────────────────────────────
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;触发条件：
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;• 整数除零
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;• 浮点异常
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;• 算术溢出
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;对应Mach异常：
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;• EXC_ARITHMETIC
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;SIGTRAP (5)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;────────────────────────────────────────
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;触发条件：
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;• 断点指令
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;• Swift的fatalError
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;• precondition失败
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;• 调试器断点
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;对应Mach异常：
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;• EXC_BREAKPOINT
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;hr&gt;
&lt;h2 id="signal-handler"&gt;Signal Handler&lt;/h2&gt;
&lt;h3 id="基本用法"&gt;基本用法&lt;/h3&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-c" data-lang="c"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;#include&lt;/span&gt; &lt;span style="color:#75715e"&gt;&amp;lt;signal.h&amp;gt;&lt;/span&gt;&lt;span style="color:#75715e"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;// 简单的信号处理函数
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;void&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;simple_handler&lt;/span&gt;(&lt;span style="color:#66d9ef"&gt;int&lt;/span&gt; sig) {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#75715e"&gt;// 处理信号
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#75715e"&gt;// 注意：这里只能调用异步信号安全的函数
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;// 注册信号处理函数
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;void&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;setup_simple_handler&lt;/span&gt;(&lt;span style="color:#66d9ef"&gt;void&lt;/span&gt;) {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;signal&lt;/span&gt;(SIGSEGV, simple_handler);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;signal&lt;/span&gt;(SIGABRT, simple_handler);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h3 id="使用sigaction推荐"&gt;使用sigaction（推荐）&lt;/h3&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-c" data-lang="c"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;#include&lt;/span&gt; &lt;span style="color:#75715e"&gt;&amp;lt;signal.h&amp;gt;&lt;/span&gt;&lt;span style="color:#75715e"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;// 带详细信息的信号处理函数
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;void&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;detailed_handler&lt;/span&gt;(&lt;span style="color:#66d9ef"&gt;int&lt;/span&gt; sig, &lt;span style="color:#66d9ef"&gt;siginfo_t&lt;/span&gt; &lt;span style="color:#f92672"&gt;*&lt;/span&gt;info, &lt;span style="color:#66d9ef"&gt;void&lt;/span&gt; &lt;span style="color:#f92672"&gt;*&lt;/span&gt;context) {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#75715e"&gt;// sig: 信号编号
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#75715e"&gt;// info: 信号详细信息
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#75715e"&gt;// context: 上下文（包含寄存器状态）
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;// 使用sigaction注册
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;void&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;setup_sigaction_handler&lt;/span&gt;(&lt;span style="color:#66d9ef"&gt;void&lt;/span&gt;) {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;struct&lt;/span&gt; sigaction action;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#75715e"&gt;// 清零结构体
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;memset&lt;/span&gt;(&lt;span style="color:#f92672"&gt;&amp;amp;&lt;/span&gt;action, &lt;span style="color:#ae81ff"&gt;0&lt;/span&gt;, &lt;span style="color:#66d9ef"&gt;sizeof&lt;/span&gt;(action));
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#75715e"&gt;// 设置处理函数
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; action.sa_sigaction &lt;span style="color:#f92672"&gt;=&lt;/span&gt; detailed_handler;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#75715e"&gt;// 设置标志
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; action.sa_flags &lt;span style="color:#f92672"&gt;=&lt;/span&gt; SA_SIGINFO &lt;span style="color:#75715e"&gt;// 使用sa_sigaction而非sa_handler
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;|&lt;/span&gt; SA_ONSTACK; &lt;span style="color:#75715e"&gt;// 使用备用栈
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#75715e"&gt;// 清空信号掩码
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;sigemptyset&lt;/span&gt;(&lt;span style="color:#f92672"&gt;&amp;amp;&lt;/span&gt;action.sa_mask);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#75715e"&gt;// 注册信号处理器
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;sigaction&lt;/span&gt;(SIGSEGV, &lt;span style="color:#f92672"&gt;&amp;amp;&lt;/span&gt;action, NULL);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;sigaction&lt;/span&gt;(SIGABRT, &lt;span style="color:#f92672"&gt;&amp;amp;&lt;/span&gt;action, NULL);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;sigaction&lt;/span&gt;(SIGBUS, &lt;span style="color:#f92672"&gt;&amp;amp;&lt;/span&gt;action, NULL);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;sigaction&lt;/span&gt;(SIGFPE, &lt;span style="color:#f92672"&gt;&amp;amp;&lt;/span&gt;action, NULL);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;sigaction&lt;/span&gt;(SIGILL, &lt;span style="color:#f92672"&gt;&amp;amp;&lt;/span&gt;action, NULL);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;sigaction&lt;/span&gt;(SIGTRAP, &lt;span style="color:#f92672"&gt;&amp;amp;&lt;/span&gt;action, NULL);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h3 id="siginfo_t结构"&gt;siginfo_t结构&lt;/h3&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-c" data-lang="c"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;typedef&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;struct&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;int&lt;/span&gt; si_signo; &lt;span style="color:#75715e"&gt;// 信号编号
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;int&lt;/span&gt; si_errno; &lt;span style="color:#75715e"&gt;// 错误码
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;int&lt;/span&gt; si_code; &lt;span style="color:#75715e"&gt;// 信号代码（更详细的原因）
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;pid_t&lt;/span&gt; si_pid; &lt;span style="color:#75715e"&gt;// 发送信号的进程ID
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;uid_t&lt;/span&gt; si_uid; &lt;span style="color:#75715e"&gt;// 发送信号的用户ID
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;void&lt;/span&gt; &lt;span style="color:#f92672"&gt;*&lt;/span&gt;si_addr; &lt;span style="color:#75715e"&gt;// 故障地址（SIGSEGV/SIGBUS）
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;int&lt;/span&gt; si_status; &lt;span style="color:#75715e"&gt;// 退出状态
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#75715e"&gt;// ... 其他字段
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;} &lt;span style="color:#66d9ef"&gt;siginfo_t&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;// 解析siginfo
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;void&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;parse_siginfo&lt;/span&gt;(&lt;span style="color:#66d9ef"&gt;int&lt;/span&gt; sig, &lt;span style="color:#66d9ef"&gt;siginfo_t&lt;/span&gt; &lt;span style="color:#f92672"&gt;*&lt;/span&gt;info) {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;printf&lt;/span&gt;(&lt;span style="color:#e6db74"&gt;&amp;#34;Signal: %d (%s)&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;\n&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#34;&lt;/span&gt;, sig, &lt;span style="color:#a6e22e"&gt;strsignal&lt;/span&gt;(sig));
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;printf&lt;/span&gt;(&lt;span style="color:#e6db74"&gt;&amp;#34;Code: %d&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;\n&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#34;&lt;/span&gt;, info&lt;span style="color:#f92672"&gt;-&amp;gt;&lt;/span&gt;si_code);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;if&lt;/span&gt; (sig &lt;span style="color:#f92672"&gt;==&lt;/span&gt; SIGSEGV &lt;span style="color:#f92672"&gt;||&lt;/span&gt; sig &lt;span style="color:#f92672"&gt;==&lt;/span&gt; SIGBUS) {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;printf&lt;/span&gt;(&lt;span style="color:#e6db74"&gt;&amp;#34;Fault address: %p&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;\n&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#34;&lt;/span&gt;, info&lt;span style="color:#f92672"&gt;-&amp;gt;&lt;/span&gt;si_addr);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; }
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#75715e"&gt;// 解析信号代码
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;switch&lt;/span&gt; (sig) {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;case&lt;/span&gt; SIGSEGV:
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;switch&lt;/span&gt; (info&lt;span style="color:#f92672"&gt;-&amp;gt;&lt;/span&gt;si_code) {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;case&lt;/span&gt; SEGV_MAPERR:
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;printf&lt;/span&gt;(&lt;span style="color:#e6db74"&gt;&amp;#34;Address not mapped&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;\n&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#34;&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;break&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;case&lt;/span&gt; SEGV_ACCERR:
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;printf&lt;/span&gt;(&lt;span style="color:#e6db74"&gt;&amp;#34;Invalid permissions&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;\n&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#34;&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;break&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; }
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;break&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;case&lt;/span&gt; SIGBUS:
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;switch&lt;/span&gt; (info&lt;span style="color:#f92672"&gt;-&amp;gt;&lt;/span&gt;si_code) {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;case&lt;/span&gt; BUS_ADRALN:
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;printf&lt;/span&gt;(&lt;span style="color:#e6db74"&gt;&amp;#34;Invalid address alignment&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;\n&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#34;&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;break&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;case&lt;/span&gt; BUS_ADRERR:
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;printf&lt;/span&gt;(&lt;span style="color:#e6db74"&gt;&amp;#34;Nonexistent physical address&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;\n&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#34;&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;break&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; }
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;break&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#75715e"&gt;// ... 其他信号
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; }
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;hr&gt;
&lt;h2 id="备用信号栈"&gt;备用信号栈&lt;/h2&gt;
&lt;h3 id="为什么需要备用栈"&gt;为什么需要备用栈&lt;/h3&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-plaintext" data-lang="plaintext"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;问题场景：
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;当栈溢出时：
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;1. 栈空间已耗尽
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;2. 系统发送SIGSEGV信号
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;3. 信号处理函数需要栈空间来执行
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;4. 但是栈已经溢出了！
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;5. 信号处理函数无法执行
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;解决方案：
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;使用备用信号栈（Alternate Signal Stack）
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h3 id="设置备用栈"&gt;设置备用栈&lt;/h3&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-c" data-lang="c"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;#include&lt;/span&gt; &lt;span style="color:#75715e"&gt;&amp;lt;signal.h&amp;gt;&lt;/span&gt;&lt;span style="color:#75715e"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;#include&lt;/span&gt; &lt;span style="color:#75715e"&gt;&amp;lt;stdlib.h&amp;gt;&lt;/span&gt;&lt;span style="color:#75715e"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;// 设置备用信号栈
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;void&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;setup_alternate_stack&lt;/span&gt;(&lt;span style="color:#66d9ef"&gt;void&lt;/span&gt;) {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#75715e"&gt;// 分配栈空间
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;void&lt;/span&gt; &lt;span style="color:#f92672"&gt;*&lt;/span&gt;stack &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;malloc&lt;/span&gt;(SIGSTKSZ);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;if&lt;/span&gt; (stack &lt;span style="color:#f92672"&gt;==&lt;/span&gt; NULL) {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;return&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; }
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#75715e"&gt;// 配置备用栈
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;stack_t&lt;/span&gt; ss;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; ss.ss_sp &lt;span style="color:#f92672"&gt;=&lt;/span&gt; stack;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; ss.ss_size &lt;span style="color:#f92672"&gt;=&lt;/span&gt; SIGSTKSZ;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; ss.ss_flags &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;0&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#75715e"&gt;// 设置备用栈
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;if&lt;/span&gt; (&lt;span style="color:#a6e22e"&gt;sigaltstack&lt;/span&gt;(&lt;span style="color:#f92672"&gt;&amp;amp;&lt;/span&gt;ss, NULL) &lt;span style="color:#f92672"&gt;!=&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;0&lt;/span&gt;) {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;free&lt;/span&gt;(stack);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;return&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; }
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#75715e"&gt;// 注册信号处理器时使用SA_ONSTACK标志
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;struct&lt;/span&gt; sigaction action;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; action.sa_sigaction &lt;span style="color:#f92672"&gt;=&lt;/span&gt; signal_handler;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; action.sa_flags &lt;span style="color:#f92672"&gt;=&lt;/span&gt; SA_SIGINFO &lt;span style="color:#f92672"&gt;|&lt;/span&gt; SA_ONSTACK;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;sigemptyset&lt;/span&gt;(&lt;span style="color:#f92672"&gt;&amp;amp;&lt;/span&gt;action.sa_mask);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;sigaction&lt;/span&gt;(SIGSEGV, &lt;span style="color:#f92672"&gt;&amp;amp;&lt;/span&gt;action, NULL);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;hr&gt;
&lt;h2 id="异步信号安全"&gt;异步信号安全&lt;/h2&gt;
&lt;h3 id="什么是异步信号安全"&gt;什么是异步信号安全&lt;/h3&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-plaintext" data-lang="plaintext"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;异步信号安全（Async-Signal-Safe）：
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;信号可能在任何时刻打断正常执行：
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;• 可能在malloc中间被打断
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;• 可能在printf中间被打断
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;• 可能持有某个锁时被打断
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;如果信号处理函数调用了相同的函数：
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;• 可能导致死锁（重复获取锁）
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;• 可能导致数据损坏（数据结构不一致）
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;• 可能导致未定义行为
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;因此，信号处理函数只能调用&amp;#34;异步信号安全&amp;#34;的函数
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h3 id="异步信号安全函数列表"&gt;异步信号安全函数列表&lt;/h3&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-c" data-lang="c"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;// 可以在信号处理函数中安全调用的函数（部分）：
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;// 文件操作
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#a6e22e"&gt;write&lt;/span&gt;()
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#a6e22e"&gt;read&lt;/span&gt;()
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#a6e22e"&gt;open&lt;/span&gt;()
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#a6e22e"&gt;close&lt;/span&gt;()
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#a6e22e"&gt;fsync&lt;/span&gt;()
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;// 进程控制
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#a6e22e"&gt;_exit&lt;/span&gt;()
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#a6e22e"&gt;_Exit&lt;/span&gt;()
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#a6e22e"&gt;abort&lt;/span&gt;()
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#a6e22e"&gt;raise&lt;/span&gt;()
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#a6e22e"&gt;kill&lt;/span&gt;()
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#a6e22e"&gt;getpid&lt;/span&gt;()
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;// 信号相关
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#a6e22e"&gt;signal&lt;/span&gt;()
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#a6e22e"&gt;sigaction&lt;/span&gt;()
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#a6e22e"&gt;sigprocmask&lt;/span&gt;()
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#a6e22e"&gt;sigemptyset&lt;/span&gt;()
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#a6e22e"&gt;sigfillset&lt;/span&gt;()
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#a6e22e"&gt;sigaddset&lt;/span&gt;()
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#a6e22e"&gt;sigdelset&lt;/span&gt;()
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;// 其他（注意：以下函数不在POSIX异步信号安全列表中，但大多数实现是安全的）
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#a6e22e"&gt;strlen&lt;/span&gt;() &lt;span style="color:#75715e"&gt;// 大多数实现安全，但非POSIX标准
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#a6e22e"&gt;memcpy&lt;/span&gt;() &lt;span style="color:#75715e"&gt;// 大多数实现安全，但非POSIX标准
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h3 id="不安全的函数"&gt;不安全的函数&lt;/h3&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-c" data-lang="c"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;// 不能在信号处理函数中调用的函数：
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;// 内存分配
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#a6e22e"&gt;malloc&lt;/span&gt;()
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#a6e22e"&gt;free&lt;/span&gt;()
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#a6e22e"&gt;realloc&lt;/span&gt;()
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;new &lt;span style="color:#f92672"&gt;/&lt;/span&gt; delete
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;// 标准I/O
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#a6e22e"&gt;printf&lt;/span&gt;()
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#a6e22e"&gt;fprintf&lt;/span&gt;()
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#a6e22e"&gt;fopen&lt;/span&gt;()
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#a6e22e"&gt;fclose&lt;/span&gt;()
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;// Objective-C
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#a6e22e"&gt;objc_msgSend&lt;/span&gt;()
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#a6e22e"&gt;NSLog&lt;/span&gt;()
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#960050;background-color:#1e0010"&gt;任何&lt;/span&gt;OC方法调用
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;// C++
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#960050;background-color:#1e0010"&gt;大多数&lt;/span&gt;C&lt;span style="color:#f92672"&gt;++&lt;/span&gt;&lt;span style="color:#960050;background-color:#1e0010"&gt;标准库函数&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#960050;background-color:#1e0010"&gt;异常处理&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;// 其他
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#a6e22e"&gt;syslog&lt;/span&gt;()
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#a6e22e"&gt;strtok&lt;/span&gt;()
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#a6e22e"&gt;localtime&lt;/span&gt;()
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;hr&gt;
&lt;h2 id="完整的崩溃信号处理器"&gt;完整的崩溃信号处理器&lt;/h2&gt;
&lt;h3 id="实现示例"&gt;实现示例&lt;/h3&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-c" data-lang="c"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;#include&lt;/span&gt; &lt;span style="color:#75715e"&gt;&amp;lt;signal.h&amp;gt;&lt;/span&gt;&lt;span style="color:#75715e"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;#include&lt;/span&gt; &lt;span style="color:#75715e"&gt;&amp;lt;execinfo.h&amp;gt;&lt;/span&gt;&lt;span style="color:#75715e"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;#include&lt;/span&gt; &lt;span style="color:#75715e"&gt;&amp;lt;unistd.h&amp;gt;&lt;/span&gt;&lt;span style="color:#75715e"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;#include&lt;/span&gt; &lt;span style="color:#75715e"&gt;&amp;lt;fcntl.h&amp;gt;&lt;/span&gt;&lt;span style="color:#75715e"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;#include&lt;/span&gt; &lt;span style="color:#75715e"&gt;&amp;lt;string.h&amp;gt;&lt;/span&gt;&lt;span style="color:#75715e"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;// 需要捕获的信号
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;static&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;const&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;int&lt;/span&gt; kFatalSignals[] &lt;span style="color:#f92672"&gt;=&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; SIGABRT,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; SIGBUS,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; SIGFPE,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; SIGILL,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; SIGSEGV,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; SIGTRAP,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; SIGSYS,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;};
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;static&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;const&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;int&lt;/span&gt; kFatalSignalsCount &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;sizeof&lt;/span&gt;(kFatalSignals) &lt;span style="color:#f92672"&gt;/&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;sizeof&lt;/span&gt;(kFatalSignals[&lt;span style="color:#ae81ff"&gt;0&lt;/span&gt;]);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;// 原始信号处理器
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;static&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;struct&lt;/span&gt; sigaction g_originalActions[&lt;span style="color:#ae81ff"&gt;32&lt;/span&gt;];
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;// 崩溃日志文件路径（预先设置）
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;static&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;char&lt;/span&gt; g_crashLogPath[&lt;span style="color:#ae81ff"&gt;1024&lt;/span&gt;];
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;// 防止重入的标志
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;static&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;volatile&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;sig_atomic_t&lt;/span&gt; g_handling &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;0&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;// 异步安全的字符串写入
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;static&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;void&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;safe_write_string&lt;/span&gt;(&lt;span style="color:#66d9ef"&gt;int&lt;/span&gt; fd, &lt;span style="color:#66d9ef"&gt;const&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;char&lt;/span&gt; &lt;span style="color:#f92672"&gt;*&lt;/span&gt;str) {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;if&lt;/span&gt; (str) {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;write&lt;/span&gt;(fd, str, &lt;span style="color:#a6e22e"&gt;strlen&lt;/span&gt;(str));
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; }
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;// 异步安全的整数转字符串
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;static&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;void&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;safe_write_int&lt;/span&gt;(&lt;span style="color:#66d9ef"&gt;int&lt;/span&gt; fd, &lt;span style="color:#66d9ef"&gt;long&lt;/span&gt; value) {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;char&lt;/span&gt; buffer[&lt;span style="color:#ae81ff"&gt;32&lt;/span&gt;];
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;char&lt;/span&gt; &lt;span style="color:#f92672"&gt;*&lt;/span&gt;ptr &lt;span style="color:#f92672"&gt;=&lt;/span&gt; buffer &lt;span style="color:#f92672"&gt;+&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;sizeof&lt;/span&gt;(buffer) &lt;span style="color:#f92672"&gt;-&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;1&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;*&lt;/span&gt;ptr &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#e6db74"&gt;&amp;#39;\0&amp;#39;&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;int&lt;/span&gt; negative &lt;span style="color:#f92672"&gt;=&lt;/span&gt; value &lt;span style="color:#f92672"&gt;&amp;lt;&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;0&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;if&lt;/span&gt; (negative) value &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#f92672"&gt;-&lt;/span&gt;value;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;do&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;*--&lt;/span&gt;ptr &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#e6db74"&gt;&amp;#39;0&amp;#39;&lt;/span&gt; &lt;span style="color:#f92672"&gt;+&lt;/span&gt; (value &lt;span style="color:#f92672"&gt;%&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;10&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; value &lt;span style="color:#f92672"&gt;/=&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;10&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; } &lt;span style="color:#66d9ef"&gt;while&lt;/span&gt; (value &lt;span style="color:#f92672"&gt;&amp;gt;&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;0&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;if&lt;/span&gt; (negative) &lt;span style="color:#f92672"&gt;*--&lt;/span&gt;ptr &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#e6db74"&gt;&amp;#39;-&amp;#39;&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;write&lt;/span&gt;(fd, ptr, buffer &lt;span style="color:#f92672"&gt;+&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;sizeof&lt;/span&gt;(buffer) &lt;span style="color:#f92672"&gt;-&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;1&lt;/span&gt; &lt;span style="color:#f92672"&gt;-&lt;/span&gt; ptr);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;// 异步安全的十六进制写入
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;static&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;void&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;safe_write_hex&lt;/span&gt;(&lt;span style="color:#66d9ef"&gt;int&lt;/span&gt; fd, &lt;span style="color:#66d9ef"&gt;unsigned&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;long&lt;/span&gt; value) {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;char&lt;/span&gt; buffer[&lt;span style="color:#ae81ff"&gt;32&lt;/span&gt;];
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;char&lt;/span&gt; &lt;span style="color:#f92672"&gt;*&lt;/span&gt;ptr &lt;span style="color:#f92672"&gt;=&lt;/span&gt; buffer &lt;span style="color:#f92672"&gt;+&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;sizeof&lt;/span&gt;(buffer) &lt;span style="color:#f92672"&gt;-&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;1&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;*&lt;/span&gt;ptr &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#e6db74"&gt;&amp;#39;\0&amp;#39;&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;static&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;const&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;char&lt;/span&gt; hex[] &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#e6db74"&gt;&amp;#34;0123456789abcdef&amp;#34;&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;do&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;*--&lt;/span&gt;ptr &lt;span style="color:#f92672"&gt;=&lt;/span&gt; hex[value &lt;span style="color:#f92672"&gt;&amp;amp;&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;0xf&lt;/span&gt;];
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; value &lt;span style="color:#f92672"&gt;&amp;gt;&amp;gt;=&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;4&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; } &lt;span style="color:#66d9ef"&gt;while&lt;/span&gt; (value &lt;span style="color:#f92672"&gt;&amp;gt;&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;0&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;*--&lt;/span&gt;ptr &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#e6db74"&gt;&amp;#39;x&amp;#39;&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;*--&lt;/span&gt;ptr &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#e6db74"&gt;&amp;#39;0&amp;#39;&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;write&lt;/span&gt;(fd, ptr, buffer &lt;span style="color:#f92672"&gt;+&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;sizeof&lt;/span&gt;(buffer) &lt;span style="color:#f92672"&gt;-&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;1&lt;/span&gt; &lt;span style="color:#f92672"&gt;-&lt;/span&gt; ptr);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;// 信号处理函数
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;static&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;void&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;crash_signal_handler&lt;/span&gt;(&lt;span style="color:#66d9ef"&gt;int&lt;/span&gt; sig, &lt;span style="color:#66d9ef"&gt;siginfo_t&lt;/span&gt; &lt;span style="color:#f92672"&gt;*&lt;/span&gt;info, &lt;span style="color:#66d9ef"&gt;void&lt;/span&gt; &lt;span style="color:#f92672"&gt;*&lt;/span&gt;context) {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#75715e"&gt;// 防止重入
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;if&lt;/span&gt; (g_handling) {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;return&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; }
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; g_handling &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;1&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#75715e"&gt;// 打开崩溃日志文件
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;int&lt;/span&gt; fd &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;open&lt;/span&gt;(g_crashLogPath, O_WRONLY &lt;span style="color:#f92672"&gt;|&lt;/span&gt; O_CREAT &lt;span style="color:#f92672"&gt;|&lt;/span&gt; O_TRUNC, &lt;span style="color:#ae81ff"&gt;0644&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;if&lt;/span&gt; (fd &lt;span style="color:#f92672"&gt;&amp;lt;&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;0&lt;/span&gt;) {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#75715e"&gt;// 无法打开文件，尝试写入stderr
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; fd &lt;span style="color:#f92672"&gt;=&lt;/span&gt; STDERR_FILENO;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; }
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#75715e"&gt;// 写入基本信息
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;safe_write_string&lt;/span&gt;(fd, &lt;span style="color:#e6db74"&gt;&amp;#34;=== Crash Report ===&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;\n&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#34;&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;safe_write_string&lt;/span&gt;(fd, &lt;span style="color:#e6db74"&gt;&amp;#34;Signal: &amp;#34;&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;safe_write_int&lt;/span&gt;(fd, sig);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;safe_write_string&lt;/span&gt;(fd, &lt;span style="color:#e6db74"&gt;&amp;#34; (&amp;#34;&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#75715e"&gt;// 信号名称
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;switch&lt;/span&gt; (sig) {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;case&lt;/span&gt; SIGABRT: &lt;span style="color:#a6e22e"&gt;safe_write_string&lt;/span&gt;(fd, &lt;span style="color:#e6db74"&gt;&amp;#34;SIGABRT&amp;#34;&lt;/span&gt;); &lt;span style="color:#66d9ef"&gt;break&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;case&lt;/span&gt; SIGBUS: &lt;span style="color:#a6e22e"&gt;safe_write_string&lt;/span&gt;(fd, &lt;span style="color:#e6db74"&gt;&amp;#34;SIGBUS&amp;#34;&lt;/span&gt;); &lt;span style="color:#66d9ef"&gt;break&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;case&lt;/span&gt; SIGFPE: &lt;span style="color:#a6e22e"&gt;safe_write_string&lt;/span&gt;(fd, &lt;span style="color:#e6db74"&gt;&amp;#34;SIGFPE&amp;#34;&lt;/span&gt;); &lt;span style="color:#66d9ef"&gt;break&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;case&lt;/span&gt; SIGILL: &lt;span style="color:#a6e22e"&gt;safe_write_string&lt;/span&gt;(fd, &lt;span style="color:#e6db74"&gt;&amp;#34;SIGILL&amp;#34;&lt;/span&gt;); &lt;span style="color:#66d9ef"&gt;break&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;case&lt;/span&gt; SIGSEGV: &lt;span style="color:#a6e22e"&gt;safe_write_string&lt;/span&gt;(fd, &lt;span style="color:#e6db74"&gt;&amp;#34;SIGSEGV&amp;#34;&lt;/span&gt;); &lt;span style="color:#66d9ef"&gt;break&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;case&lt;/span&gt; SIGTRAP: &lt;span style="color:#a6e22e"&gt;safe_write_string&lt;/span&gt;(fd, &lt;span style="color:#e6db74"&gt;&amp;#34;SIGTRAP&amp;#34;&lt;/span&gt;); &lt;span style="color:#66d9ef"&gt;break&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;default&lt;/span&gt;&lt;span style="color:#f92672"&gt;:&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;safe_write_string&lt;/span&gt;(fd, &lt;span style="color:#e6db74"&gt;&amp;#34;UNKNOWN&amp;#34;&lt;/span&gt;); &lt;span style="color:#66d9ef"&gt;break&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; }
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;safe_write_string&lt;/span&gt;(fd, &lt;span style="color:#e6db74"&gt;&amp;#34;)&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;\n&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#34;&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#75715e"&gt;// 信号代码
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;safe_write_string&lt;/span&gt;(fd, &lt;span style="color:#e6db74"&gt;&amp;#34;Code: &amp;#34;&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;safe_write_int&lt;/span&gt;(fd, info&lt;span style="color:#f92672"&gt;-&amp;gt;&lt;/span&gt;si_code);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;safe_write_string&lt;/span&gt;(fd, &lt;span style="color:#e6db74"&gt;&amp;#34;&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;\n&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#34;&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#75715e"&gt;// 故障地址
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;if&lt;/span&gt; (sig &lt;span style="color:#f92672"&gt;==&lt;/span&gt; SIGSEGV &lt;span style="color:#f92672"&gt;||&lt;/span&gt; sig &lt;span style="color:#f92672"&gt;==&lt;/span&gt; SIGBUS) {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;safe_write_string&lt;/span&gt;(fd, &lt;span style="color:#e6db74"&gt;&amp;#34;Fault Address: &amp;#34;&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;safe_write_hex&lt;/span&gt;(fd, (&lt;span style="color:#66d9ef"&gt;unsigned&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;long&lt;/span&gt;)info&lt;span style="color:#f92672"&gt;-&amp;gt;&lt;/span&gt;si_addr);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;safe_write_string&lt;/span&gt;(fd, &lt;span style="color:#e6db74"&gt;&amp;#34;&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;\n&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#34;&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; }
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#75715e"&gt;// 获取堆栈
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#75715e"&gt;// 注意：backtrace()严格来说也不是异步信号安全的函数
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#75715e"&gt;// 但为了获取崩溃堆栈，这是一个常见的权衡取舍
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;safe_write_string&lt;/span&gt;(fd, &lt;span style="color:#e6db74"&gt;&amp;#34;&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;\n&lt;/span&gt;&lt;span style="color:#e6db74"&gt;Backtrace:&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;\n&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#34;&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;void&lt;/span&gt; &lt;span style="color:#f92672"&gt;*&lt;/span&gt;callstack[&lt;span style="color:#ae81ff"&gt;128&lt;/span&gt;];
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;int&lt;/span&gt; frames &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;backtrace&lt;/span&gt;(callstack, &lt;span style="color:#ae81ff"&gt;128&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#75715e"&gt;// 注意：backtrace_symbols使用malloc，不是异步安全的
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#75715e"&gt;// 这里我们只写入地址，符号化在后续处理
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;for&lt;/span&gt; (&lt;span style="color:#66d9ef"&gt;int&lt;/span&gt; i &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;0&lt;/span&gt;; i &lt;span style="color:#f92672"&gt;&amp;lt;&lt;/span&gt; frames; i&lt;span style="color:#f92672"&gt;++&lt;/span&gt;) {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;safe_write_int&lt;/span&gt;(fd, i);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;safe_write_string&lt;/span&gt;(fd, &lt;span style="color:#e6db74"&gt;&amp;#34;: &amp;#34;&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;safe_write_hex&lt;/span&gt;(fd, (&lt;span style="color:#66d9ef"&gt;unsigned&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;long&lt;/span&gt;)callstack[i]);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;safe_write_string&lt;/span&gt;(fd, &lt;span style="color:#e6db74"&gt;&amp;#34;&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;\n&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#34;&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; }
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#75715e"&gt;// 同步写入
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;if&lt;/span&gt; (fd &lt;span style="color:#f92672"&gt;!=&lt;/span&gt; STDERR_FILENO) {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;fsync&lt;/span&gt;(fd);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;close&lt;/span&gt;(fd);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; }
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#75715e"&gt;// 恢复原始处理器并重新发送信号
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;sigaction&lt;/span&gt;(sig, &lt;span style="color:#f92672"&gt;&amp;amp;&lt;/span&gt;g_originalActions[sig], NULL);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;raise&lt;/span&gt;(sig);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;// 安装信号处理器
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;void&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;install_crash_signal_handlers&lt;/span&gt;(&lt;span style="color:#66d9ef"&gt;const&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;char&lt;/span&gt; &lt;span style="color:#f92672"&gt;*&lt;/span&gt;logPath) {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#75715e"&gt;// 保存日志路径
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;strncpy&lt;/span&gt;(g_crashLogPath, logPath, &lt;span style="color:#66d9ef"&gt;sizeof&lt;/span&gt;(g_crashLogPath) &lt;span style="color:#f92672"&gt;-&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;1&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#75715e"&gt;// 设置备用栈
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;static&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;char&lt;/span&gt; alternate_stack[SIGSTKSZ];
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;stack_t&lt;/span&gt; ss;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; ss.ss_sp &lt;span style="color:#f92672"&gt;=&lt;/span&gt; alternate_stack;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; ss.ss_size &lt;span style="color:#f92672"&gt;=&lt;/span&gt; SIGSTKSZ;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; ss.ss_flags &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;0&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;sigaltstack&lt;/span&gt;(&lt;span style="color:#f92672"&gt;&amp;amp;&lt;/span&gt;ss, NULL);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#75715e"&gt;// 配置信号处理器
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;struct&lt;/span&gt; sigaction action;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;memset&lt;/span&gt;(&lt;span style="color:#f92672"&gt;&amp;amp;&lt;/span&gt;action, &lt;span style="color:#ae81ff"&gt;0&lt;/span&gt;, &lt;span style="color:#66d9ef"&gt;sizeof&lt;/span&gt;(action));
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; action.sa_sigaction &lt;span style="color:#f92672"&gt;=&lt;/span&gt; crash_signal_handler;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; action.sa_flags &lt;span style="color:#f92672"&gt;=&lt;/span&gt; SA_SIGINFO &lt;span style="color:#f92672"&gt;|&lt;/span&gt; SA_ONSTACK;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;sigemptyset&lt;/span&gt;(&lt;span style="color:#f92672"&gt;&amp;amp;&lt;/span&gt;action.sa_mask);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#75715e"&gt;// 注册所有致命信号
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;for&lt;/span&gt; (&lt;span style="color:#66d9ef"&gt;int&lt;/span&gt; i &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;0&lt;/span&gt;; i &lt;span style="color:#f92672"&gt;&amp;lt;&lt;/span&gt; kFatalSignalsCount; i&lt;span style="color:#f92672"&gt;++&lt;/span&gt;) {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;int&lt;/span&gt; sig &lt;span style="color:#f92672"&gt;=&lt;/span&gt; kFatalSignals[i];
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;sigaction&lt;/span&gt;(sig, &lt;span style="color:#f92672"&gt;&amp;amp;&lt;/span&gt;action, &lt;span style="color:#f92672"&gt;&amp;amp;&lt;/span&gt;g_originalActions[sig]);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; }
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;// 卸载信号处理器
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;void&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;uninstall_crash_signal_handlers&lt;/span&gt;(&lt;span style="color:#66d9ef"&gt;void&lt;/span&gt;) {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;for&lt;/span&gt; (&lt;span style="color:#66d9ef"&gt;int&lt;/span&gt; i &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;0&lt;/span&gt;; i &lt;span style="color:#f92672"&gt;&amp;lt;&lt;/span&gt; kFatalSignalsCount; i&lt;span style="color:#f92672"&gt;++&lt;/span&gt;) {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;int&lt;/span&gt; sig &lt;span style="color:#f92672"&gt;=&lt;/span&gt; kFatalSignals[i];
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;sigaction&lt;/span&gt;(sig, &lt;span style="color:#f92672"&gt;&amp;amp;&lt;/span&gt;g_originalActions[sig], NULL);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; }
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;hr&gt;
&lt;h2 id="获取上下文信息"&gt;获取上下文信息&lt;/h2&gt;
&lt;h3 id="从ucontext获取寄存器"&gt;从ucontext获取寄存器&lt;/h3&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-c" data-lang="c"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;#include&lt;/span&gt; &lt;span style="color:#75715e"&gt;&amp;lt;signal.h&amp;gt;&lt;/span&gt;&lt;span style="color:#75715e"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;#include&lt;/span&gt; &lt;span style="color:#75715e"&gt;&amp;lt;sys/ucontext.h&amp;gt;&lt;/span&gt;&lt;span style="color:#75715e"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;void&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;signal_handler&lt;/span&gt;(&lt;span style="color:#66d9ef"&gt;int&lt;/span&gt; sig, &lt;span style="color:#66d9ef"&gt;siginfo_t&lt;/span&gt; &lt;span style="color:#f92672"&gt;*&lt;/span&gt;info, &lt;span style="color:#66d9ef"&gt;void&lt;/span&gt; &lt;span style="color:#f92672"&gt;*&lt;/span&gt;context) {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;ucontext_t&lt;/span&gt; &lt;span style="color:#f92672"&gt;*&lt;/span&gt;uc &lt;span style="color:#f92672"&gt;=&lt;/span&gt; (&lt;span style="color:#66d9ef"&gt;ucontext_t&lt;/span&gt; &lt;span style="color:#f92672"&gt;*&lt;/span&gt;)context;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;#if defined(__arm64__) || defined(__aarch64__)
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#75715e"&gt;// ARM64架构
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;mcontext_t&lt;/span&gt; mc &lt;span style="color:#f92672"&gt;=&lt;/span&gt; uc&lt;span style="color:#f92672"&gt;-&amp;gt;&lt;/span&gt;uc_mcontext;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#75715e"&gt;// 通用寄存器
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;for&lt;/span&gt; (&lt;span style="color:#66d9ef"&gt;int&lt;/span&gt; i &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;0&lt;/span&gt;; i &lt;span style="color:#f92672"&gt;&amp;lt;&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;29&lt;/span&gt;; i&lt;span style="color:#f92672"&gt;++&lt;/span&gt;) {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;printf&lt;/span&gt;(&lt;span style="color:#e6db74"&gt;&amp;#34;x%d: 0x%llx&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;\n&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#34;&lt;/span&gt;, i, mc&lt;span style="color:#f92672"&gt;-&amp;gt;&lt;/span&gt;__ss.__x[i]);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; }
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#75715e"&gt;// 特殊寄存器
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;printf&lt;/span&gt;(&lt;span style="color:#e6db74"&gt;&amp;#34;fp: 0x%llx&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;\n&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#34;&lt;/span&gt;, mc&lt;span style="color:#f92672"&gt;-&amp;gt;&lt;/span&gt;__ss.__fp); &lt;span style="color:#75715e"&gt;// 帧指针
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;printf&lt;/span&gt;(&lt;span style="color:#e6db74"&gt;&amp;#34;lr: 0x%llx&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;\n&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#34;&lt;/span&gt;, mc&lt;span style="color:#f92672"&gt;-&amp;gt;&lt;/span&gt;__ss.__lr); &lt;span style="color:#75715e"&gt;// 链接寄存器
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;printf&lt;/span&gt;(&lt;span style="color:#e6db74"&gt;&amp;#34;sp: 0x%llx&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;\n&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#34;&lt;/span&gt;, mc&lt;span style="color:#f92672"&gt;-&amp;gt;&lt;/span&gt;__ss.__sp); &lt;span style="color:#75715e"&gt;// 栈指针
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;printf&lt;/span&gt;(&lt;span style="color:#e6db74"&gt;&amp;#34;pc: 0x%llx&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;\n&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#34;&lt;/span&gt;, mc&lt;span style="color:#f92672"&gt;-&amp;gt;&lt;/span&gt;__ss.__pc); &lt;span style="color:#75715e"&gt;// 程序计数器
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;printf&lt;/span&gt;(&lt;span style="color:#e6db74"&gt;&amp;#34;cpsr: 0x%x&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;\n&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#34;&lt;/span&gt;, mc&lt;span style="color:#f92672"&gt;-&amp;gt;&lt;/span&gt;__ss.__cpsr); &lt;span style="color:#75715e"&gt;// 状态寄存器
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;#elif defined(__x86_64__)
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#75715e"&gt;// x86_64架构
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;mcontext_t&lt;/span&gt; mc &lt;span style="color:#f92672"&gt;=&lt;/span&gt; uc&lt;span style="color:#f92672"&gt;-&amp;gt;&lt;/span&gt;uc_mcontext;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;printf&lt;/span&gt;(&lt;span style="color:#e6db74"&gt;&amp;#34;rax: 0x%llx&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;\n&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#34;&lt;/span&gt;, mc&lt;span style="color:#f92672"&gt;-&amp;gt;&lt;/span&gt;__ss.__rax);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;printf&lt;/span&gt;(&lt;span style="color:#e6db74"&gt;&amp;#34;rbx: 0x%llx&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;\n&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#34;&lt;/span&gt;, mc&lt;span style="color:#f92672"&gt;-&amp;gt;&lt;/span&gt;__ss.__rbx);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;printf&lt;/span&gt;(&lt;span style="color:#e6db74"&gt;&amp;#34;rcx: 0x%llx&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;\n&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#34;&lt;/span&gt;, mc&lt;span style="color:#f92672"&gt;-&amp;gt;&lt;/span&gt;__ss.__rcx);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;printf&lt;/span&gt;(&lt;span style="color:#e6db74"&gt;&amp;#34;rdx: 0x%llx&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;\n&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#34;&lt;/span&gt;, mc&lt;span style="color:#f92672"&gt;-&amp;gt;&lt;/span&gt;__ss.__rdx);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;printf&lt;/span&gt;(&lt;span style="color:#e6db74"&gt;&amp;#34;rsi: 0x%llx&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;\n&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#34;&lt;/span&gt;, mc&lt;span style="color:#f92672"&gt;-&amp;gt;&lt;/span&gt;__ss.__rsi);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;printf&lt;/span&gt;(&lt;span style="color:#e6db74"&gt;&amp;#34;rdi: 0x%llx&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;\n&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#34;&lt;/span&gt;, mc&lt;span style="color:#f92672"&gt;-&amp;gt;&lt;/span&gt;__ss.__rdi);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;printf&lt;/span&gt;(&lt;span style="color:#e6db74"&gt;&amp;#34;rbp: 0x%llx&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;\n&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#34;&lt;/span&gt;, mc&lt;span style="color:#f92672"&gt;-&amp;gt;&lt;/span&gt;__ss.__rbp);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;printf&lt;/span&gt;(&lt;span style="color:#e6db74"&gt;&amp;#34;rsp: 0x%llx&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;\n&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#34;&lt;/span&gt;, mc&lt;span style="color:#f92672"&gt;-&amp;gt;&lt;/span&gt;__ss.__rsp);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;printf&lt;/span&gt;(&lt;span style="color:#e6db74"&gt;&amp;#34;rip: 0x%llx&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;\n&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#34;&lt;/span&gt;, mc&lt;span style="color:#f92672"&gt;-&amp;gt;&lt;/span&gt;__ss.__rip);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;#endif
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h3 id="从寄存器回溯堆栈"&gt;从寄存器回溯堆栈&lt;/h3&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-c" data-lang="c"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;// 基于帧指针的堆栈回溯
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;void&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;backtrace_from_context&lt;/span&gt;(&lt;span style="color:#66d9ef"&gt;ucontext_t&lt;/span&gt; &lt;span style="color:#f92672"&gt;*&lt;/span&gt;context) {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;mcontext_t&lt;/span&gt; mc &lt;span style="color:#f92672"&gt;=&lt;/span&gt; context&lt;span style="color:#f92672"&gt;-&amp;gt;&lt;/span&gt;uc_mcontext;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;#if defined(__arm64__)
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;uintptr_t&lt;/span&gt; pc &lt;span style="color:#f92672"&gt;=&lt;/span&gt; mc&lt;span style="color:#f92672"&gt;-&amp;gt;&lt;/span&gt;__ss.__pc;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;uintptr_t&lt;/span&gt; fp &lt;span style="color:#f92672"&gt;=&lt;/span&gt; mc&lt;span style="color:#f92672"&gt;-&amp;gt;&lt;/span&gt;__ss.__fp;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;printf&lt;/span&gt;(&lt;span style="color:#e6db74"&gt;&amp;#34;Backtrace:&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;\n&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#34;&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;printf&lt;/span&gt;(&lt;span style="color:#e6db74"&gt;&amp;#34;0: 0x%lx (PC)&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;\n&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#34;&lt;/span&gt;, (&lt;span style="color:#66d9ef"&gt;unsigned&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;long&lt;/span&gt;)pc);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;int&lt;/span&gt; frame &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;1&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;while&lt;/span&gt; (fp &lt;span style="color:#f92672"&gt;!=&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;0&lt;/span&gt; &lt;span style="color:#f92672"&gt;&amp;amp;&amp;amp;&lt;/span&gt; frame &lt;span style="color:#f92672"&gt;&amp;lt;&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;128&lt;/span&gt;) {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#75715e"&gt;// ARM64栈帧布局：
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#75715e"&gt;// [fp+0]: 上一帧的fp
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#75715e"&gt;// [fp+8]: 返回地址
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;uintptr_t&lt;/span&gt; &lt;span style="color:#f92672"&gt;*&lt;/span&gt;frame_ptr &lt;span style="color:#f92672"&gt;=&lt;/span&gt; (&lt;span style="color:#66d9ef"&gt;uintptr_t&lt;/span&gt; &lt;span style="color:#f92672"&gt;*&lt;/span&gt;)fp;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#75715e"&gt;// 安全检查
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;if&lt;/span&gt; ((&lt;span style="color:#66d9ef"&gt;uintptr_t&lt;/span&gt;)frame_ptr &lt;span style="color:#f92672"&gt;&amp;lt;&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;0x1000&lt;/span&gt;) &lt;span style="color:#66d9ef"&gt;break&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;uintptr_t&lt;/span&gt; return_addr &lt;span style="color:#f92672"&gt;=&lt;/span&gt; frame_ptr[&lt;span style="color:#ae81ff"&gt;1&lt;/span&gt;];
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;printf&lt;/span&gt;(&lt;span style="color:#e6db74"&gt;&amp;#34;%d: 0x%lx&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;\n&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#34;&lt;/span&gt;, frame, (&lt;span style="color:#66d9ef"&gt;unsigned&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;long&lt;/span&gt;)return_addr);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#75715e"&gt;// 移动到上一帧
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; fp &lt;span style="color:#f92672"&gt;=&lt;/span&gt; frame_ptr[&lt;span style="color:#ae81ff"&gt;0&lt;/span&gt;];
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; frame&lt;span style="color:#f92672"&gt;++&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; }
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;#endif
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;hr&gt;
&lt;h2 id="信号掩码"&gt;信号掩码&lt;/h2&gt;
&lt;h3 id="阻塞信号"&gt;阻塞信号&lt;/h3&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-c" data-lang="c"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;#include&lt;/span&gt; &lt;span style="color:#75715e"&gt;&amp;lt;signal.h&amp;gt;&lt;/span&gt;&lt;span style="color:#75715e"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;// 阻塞特定信号
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;void&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;block_signals&lt;/span&gt;(&lt;span style="color:#66d9ef"&gt;void&lt;/span&gt;) {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;sigset_t&lt;/span&gt; mask;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;sigemptyset&lt;/span&gt;(&lt;span style="color:#f92672"&gt;&amp;amp;&lt;/span&gt;mask);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;sigaddset&lt;/span&gt;(&lt;span style="color:#f92672"&gt;&amp;amp;&lt;/span&gt;mask, SIGINT);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;sigaddset&lt;/span&gt;(&lt;span style="color:#f92672"&gt;&amp;amp;&lt;/span&gt;mask, SIGTERM);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#75715e"&gt;// 阻塞信号
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;sigprocmask&lt;/span&gt;(SIG_BLOCK, &lt;span style="color:#f92672"&gt;&amp;amp;&lt;/span&gt;mask, NULL);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#75715e"&gt;// 执行关键代码...
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#75715e"&gt;// 解除阻塞
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;sigprocmask&lt;/span&gt;(SIG_UNBLOCK, &lt;span style="color:#f92672"&gt;&amp;amp;&lt;/span&gt;mask, NULL);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;// 在信号处理期间阻塞其他信号
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;void&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;setup_handler_with_mask&lt;/span&gt;(&lt;span style="color:#66d9ef"&gt;void&lt;/span&gt;) {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;struct&lt;/span&gt; sigaction action;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; action.sa_sigaction &lt;span style="color:#f92672"&gt;=&lt;/span&gt; signal_handler;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; action.sa_flags &lt;span style="color:#f92672"&gt;=&lt;/span&gt; SA_SIGINFO;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#75715e"&gt;// 在处理SIGSEGV时阻塞其他信号
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;sigfillset&lt;/span&gt;(&lt;span style="color:#f92672"&gt;&amp;amp;&lt;/span&gt;action.sa_mask);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;sigaction&lt;/span&gt;(SIGSEGV, &lt;span style="color:#f92672"&gt;&amp;amp;&lt;/span&gt;action, NULL);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h3 id="检查待处理信号"&gt;检查待处理信号&lt;/h3&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-c" data-lang="c"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;// 检查是否有信号待处理
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;void&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;check_pending_signals&lt;/span&gt;(&lt;span style="color:#66d9ef"&gt;void&lt;/span&gt;) {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;sigset_t&lt;/span&gt; pending;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;sigpending&lt;/span&gt;(&lt;span style="color:#f92672"&gt;&amp;amp;&lt;/span&gt;pending);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;if&lt;/span&gt; (&lt;span style="color:#a6e22e"&gt;sigismember&lt;/span&gt;(&lt;span style="color:#f92672"&gt;&amp;amp;&lt;/span&gt;pending, SIGINT)) {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;printf&lt;/span&gt;(&lt;span style="color:#e6db74"&gt;&amp;#34;SIGINT is pending&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;\n&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#34;&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; }
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;hr&gt;
&lt;h2 id="信号与多线程"&gt;信号与多线程&lt;/h2&gt;
&lt;h3 id="线程与信号"&gt;线程与信号&lt;/h3&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-plaintext" data-lang="plaintext"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;多线程环境下的信号处理：
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;1. 信号处理器是进程级的
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; • 所有线程共享信号处理器设置
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; • 一个线程设置的处理器影响整个进程
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;2. 信号掩码是线程级的
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; • 每个线程有自己的信号掩码
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; • pthread_sigmask()用于设置线程的信号掩码
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;3. 信号投递
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; • 同步信号（如SIGSEGV）投递给触发它的线程
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; • 异步信号投递给任意一个不阻塞该信号的线程
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h3 id="线程信号掩码"&gt;线程信号掩码&lt;/h3&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-c" data-lang="c"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;#include&lt;/span&gt; &lt;span style="color:#75715e"&gt;&amp;lt;pthread.h&amp;gt;&lt;/span&gt;&lt;span style="color:#75715e"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;#include&lt;/span&gt; &lt;span style="color:#75715e"&gt;&amp;lt;signal.h&amp;gt;&lt;/span&gt;&lt;span style="color:#75715e"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;// 设置线程信号掩码
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;void&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;setup_thread_signal_mask&lt;/span&gt;(&lt;span style="color:#66d9ef"&gt;void&lt;/span&gt;) {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;sigset_t&lt;/span&gt; mask;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;sigemptyset&lt;/span&gt;(&lt;span style="color:#f92672"&gt;&amp;amp;&lt;/span&gt;mask);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;sigaddset&lt;/span&gt;(&lt;span style="color:#f92672"&gt;&amp;amp;&lt;/span&gt;mask, SIGPIPE); &lt;span style="color:#75715e"&gt;// 阻塞SIGPIPE
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;pthread_sigmask&lt;/span&gt;(SIG_BLOCK, &lt;span style="color:#f92672"&gt;&amp;amp;&lt;/span&gt;mask, NULL);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;// 专门的信号处理线程
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;void&lt;/span&gt; &lt;span style="color:#f92672"&gt;*&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;signal_handler_thread&lt;/span&gt;(&lt;span style="color:#66d9ef"&gt;void&lt;/span&gt; &lt;span style="color:#f92672"&gt;*&lt;/span&gt;arg) {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;sigset_t&lt;/span&gt; mask;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;sigemptyset&lt;/span&gt;(&lt;span style="color:#f92672"&gt;&amp;amp;&lt;/span&gt;mask);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;sigaddset&lt;/span&gt;(&lt;span style="color:#f92672"&gt;&amp;amp;&lt;/span&gt;mask, SIGTERM);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;sigaddset&lt;/span&gt;(&lt;span style="color:#f92672"&gt;&amp;amp;&lt;/span&gt;mask, SIGINT);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;int&lt;/span&gt; sig;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;while&lt;/span&gt; (&lt;span style="color:#ae81ff"&gt;1&lt;/span&gt;) {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#75715e"&gt;// 同步等待信号
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;sigwait&lt;/span&gt;(&lt;span style="color:#f92672"&gt;&amp;amp;&lt;/span&gt;mask, &lt;span style="color:#f92672"&gt;&amp;amp;&lt;/span&gt;sig);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;printf&lt;/span&gt;(&lt;span style="color:#e6db74"&gt;&amp;#34;Received signal: %d&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;\n&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#34;&lt;/span&gt;, sig);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;if&lt;/span&gt; (sig &lt;span style="color:#f92672"&gt;==&lt;/span&gt; SIGTERM) {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#75715e"&gt;// 处理终止信号
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;break&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; }
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; }
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;return&lt;/span&gt; NULL;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;// 主线程设置
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;void&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;setup_signal_thread&lt;/span&gt;(&lt;span style="color:#66d9ef"&gt;void&lt;/span&gt;) {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#75715e"&gt;// 在主线程中阻塞这些信号
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;sigset_t&lt;/span&gt; mask;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;sigemptyset&lt;/span&gt;(&lt;span style="color:#f92672"&gt;&amp;amp;&lt;/span&gt;mask);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;sigaddset&lt;/span&gt;(&lt;span style="color:#f92672"&gt;&amp;amp;&lt;/span&gt;mask, SIGTERM);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;sigaddset&lt;/span&gt;(&lt;span style="color:#f92672"&gt;&amp;amp;&lt;/span&gt;mask, SIGINT);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;pthread_sigmask&lt;/span&gt;(SIG_BLOCK, &lt;span style="color:#f92672"&gt;&amp;amp;&lt;/span&gt;mask, NULL);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#75715e"&gt;// 创建信号处理线程
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;pthread_t&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;thread&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;pthread_create&lt;/span&gt;(&lt;span style="color:#f92672"&gt;&amp;amp;&lt;/span&gt;&lt;span style="color:#66d9ef"&gt;thread&lt;/span&gt;, NULL, signal_handler_thread, NULL);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;hr&gt;
&lt;h2 id="常见问题与解决方案"&gt;常见问题与解决方案&lt;/h2&gt;
&lt;h3 id="信号处理器中的死锁"&gt;信号处理器中的死锁&lt;/h3&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-plaintext" data-lang="plaintext"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;问题：信号处理器中调用了非异步安全函数导致死锁
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;场景：
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;1. 主线程调用malloc()，获取了内存分配锁
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;2. 此时收到SIGSEGV信号
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;3. 信号处理器中调用malloc()
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;4. 尝试获取同一把锁 -&amp;gt; 死锁
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;解决方案：
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;• 只使用异步信号安全的函数
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;• 使用预分配的内存
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;• 将复杂处理延迟到信号处理器外部
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h3 id="信号处理器重入"&gt;信号处理器重入&lt;/h3&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-c" data-lang="c"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;// 问题：信号处理器被再次调用
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;// 解决：使用标志位防止重入
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;static&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;volatile&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;sig_atomic_t&lt;/span&gt; g_handling &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;0&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;void&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;signal_handler&lt;/span&gt;(&lt;span style="color:#66d9ef"&gt;int&lt;/span&gt; sig, &lt;span style="color:#66d9ef"&gt;siginfo_t&lt;/span&gt; &lt;span style="color:#f92672"&gt;*&lt;/span&gt;info, &lt;span style="color:#66d9ef"&gt;void&lt;/span&gt; &lt;span style="color:#f92672"&gt;*&lt;/span&gt;context) {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#75715e"&gt;// 检查是否正在处理
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;if&lt;/span&gt; (g_handling) {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#75715e"&gt;// 已经在处理中，直接返回
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;return&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; }
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#75715e"&gt;// 设置标志
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; g_handling &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;1&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#75715e"&gt;// 处理信号...
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#75715e"&gt;// 注意：不要在这里清除标志
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#75715e"&gt;// 因为我们会重新发送信号
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h3 id="与其他sdk的冲突"&gt;与其他SDK的冲突&lt;/h3&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-c" data-lang="c"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;// 问题：多个SDK都注册了信号处理器
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;// 解决方案：保存并调用原始处理器
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;static&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;struct&lt;/span&gt; sigaction g_original_action;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;void&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;my_signal_handler&lt;/span&gt;(&lt;span style="color:#66d9ef"&gt;int&lt;/span&gt; sig, &lt;span style="color:#66d9ef"&gt;siginfo_t&lt;/span&gt; &lt;span style="color:#f92672"&gt;*&lt;/span&gt;info, &lt;span style="color:#66d9ef"&gt;void&lt;/span&gt; &lt;span style="color:#f92672"&gt;*&lt;/span&gt;context) {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#75715e"&gt;// 我的处理逻辑
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;handle_crash&lt;/span&gt;(sig, info, context);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#75715e"&gt;// 调用原始处理器
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;if&lt;/span&gt; (g_original_action.sa_flags &lt;span style="color:#f92672"&gt;&amp;amp;&lt;/span&gt; SA_SIGINFO) {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; g_original_action.&lt;span style="color:#a6e22e"&gt;sa_sigaction&lt;/span&gt;(sig, info, context);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; } &lt;span style="color:#66d9ef"&gt;else&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;if&lt;/span&gt; (g_original_action.sa_handler &lt;span style="color:#f92672"&gt;!=&lt;/span&gt; SIG_DFL &lt;span style="color:#f92672"&gt;&amp;amp;&amp;amp;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; g_original_action.sa_handler &lt;span style="color:#f92672"&gt;!=&lt;/span&gt; SIG_IGN) {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; g_original_action.&lt;span style="color:#a6e22e"&gt;sa_handler&lt;/span&gt;(sig);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; } &lt;span style="color:#66d9ef"&gt;else&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#75715e"&gt;// 恢复默认行为
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;signal&lt;/span&gt;(sig, SIG_DFL);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;raise&lt;/span&gt;(sig);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; }
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;void&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;install_handler&lt;/span&gt;(&lt;span style="color:#66d9ef"&gt;void&lt;/span&gt;) {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;struct&lt;/span&gt; sigaction action;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; action.sa_sigaction &lt;span style="color:#f92672"&gt;=&lt;/span&gt; my_signal_handler;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; action.sa_flags &lt;span style="color:#f92672"&gt;=&lt;/span&gt; SA_SIGINFO &lt;span style="color:#f92672"&gt;|&lt;/span&gt; SA_ONSTACK;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;sigemptyset&lt;/span&gt;(&lt;span style="color:#f92672"&gt;&amp;amp;&lt;/span&gt;action.sa_mask);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#75715e"&gt;// 保存原始处理器
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;sigaction&lt;/span&gt;(SIGSEGV, &lt;span style="color:#f92672"&gt;&amp;amp;&lt;/span&gt;action, &lt;span style="color:#f92672"&gt;&amp;amp;&lt;/span&gt;g_original_action);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;hr&gt;
&lt;h2 id="信号与mach异常的关系"&gt;信号与Mach异常的关系&lt;/h2&gt;
&lt;h3 id="转换关系"&gt;转换关系&lt;/h3&gt;
&lt;pre class="mermaid"&gt;flowchart LR
subgraph Mach["Mach异常"]
A1[EXC_BAD_ACCESS]
A2[EXC_BAD_INSTRUCTION]
A3[EXC_ARITHMETIC]
A4[EXC_BREAKPOINT]
A5[EXC_CRASH]
A6[EXC_SOFTWARE]
end
subgraph Signal["Unix信号"]
B1[SIGSEGV / SIGBUS]
B2[SIGILL]
B3[SIGFPE]
B4[SIGTRAP]
B5[SIGABRT]
B6[取决于具体代码]
end
A1 --&gt; B1
A2 --&gt; B2
A3 --&gt; B3
A4 --&gt; B4
A5 --&gt; B5
A6 --&gt; B6
&lt;/pre&gt;
&lt;p&gt;转换时机：&lt;/p&gt;</description></item><item><title>崩溃-原理</title><link>https://amatsuzero.github.io/LastStand/posts/interview/ios-performance/crash-%E5%8E%9F%E7%90%86/</link><pubDate>Sun, 10 May 2026 22:25:41 +0800</pubDate><guid>https://amatsuzero.github.io/LastStand/posts/interview/ios-performance/crash-%E5%8E%9F%E7%90%86/</guid><description>&lt;p&gt;理解崩溃的底层原理是有效治理的基础。本文详细介绍iOS的异常处理机制、崩溃的传递链路以及各类崩溃的本质原因。&lt;/p&gt;
&lt;hr&gt;
&lt;h2 id="ios异常处理架构"&gt;iOS异常处理架构&lt;/h2&gt;
&lt;p&gt;iOS的异常处理采用分层架构，从底层到上层依次为：&lt;/p&gt;
&lt;pre class="mermaid"&gt;flowchart BT
subgraph ARCH["异常处理架构"]
direction BT
HW["硬件层 (Hardware)&lt;br/&gt;CPU异常、内存访问违规、非法指令"]
MACH["Mach层 (Mach Exception)&lt;br/&gt;EXC_BAD_ACCESS、EXC_BAD_INSTRUCTION、EXC_CRASH"]
BSD["BSD层 (Unix Signal)&lt;br/&gt;SIGABRT、SIGSEGV、SIGBUS、SIGFPE、SIGILL"]
APP["应用层 (Application Layer)&lt;br/&gt;NSException、@try-@catch、Swift Error"]
HW --&gt; MACH
MACH --&gt; BSD
BSD --&gt; APP
end
&lt;/pre&gt;
&lt;p&gt;需要注意：这张图表示崩溃治理中常见的异常/终止机制层次，并不表示所有异常都一定从硬件层逐级向上传递。&lt;code&gt;NSException&lt;/code&gt; 属于 Objective-C 运行时/框架层的语言异常机制，不是内核产生的 Mach 异常。只有当 &lt;code&gt;NSException&lt;/code&gt; 未被捕获时，运行时最终通常会调用 &lt;code&gt;abort()&lt;/code&gt; 主动终止进程，随后表现为 &lt;code&gt;SIGABRT&lt;/code&gt; / &lt;code&gt;EXC_CRASH&lt;/code&gt;。&lt;/p&gt;
&lt;hr&gt;
&lt;h2 id="崩溃的传递链路"&gt;崩溃的传递链路&lt;/h2&gt;
&lt;p&gt;当异常发生时，会按照特定的链路传递：&lt;/p&gt;
&lt;pre class="mermaid"&gt;flowchart TD
A["1. 硬件触发异常&lt;br/&gt;CPU检测到非法操作（如访问无效内存地址）&lt;br/&gt;触发硬件中断，陷入内核态"] --&gt; B["2. Mach层处理&lt;br/&gt;内核将硬件异常转换为Mach异常&lt;br/&gt;通过异常端口发送给用户态的异常处理程序&lt;br/&gt;如果没有处理，转换为Unix信号"]
B --&gt; C["3. BSD层处理&lt;br/&gt;Mach异常被转换为对应的Unix信号&lt;br/&gt;调用进程注册的Signal Handler&lt;br/&gt;如果没有处理或处理后继续，执行默认行为"]
C --&gt; D["4. 进程终止&lt;br/&gt;默认行为通常是终止进程&lt;br/&gt;生成崩溃日志"]
&lt;/pre&gt;
&lt;h3 id="mach异常与unix信号的对应关系"&gt;Mach异常与Unix信号的对应关系&lt;/h3&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Mach异常&lt;/th&gt;
&lt;th&gt;Unix信号&lt;/th&gt;
&lt;th&gt;触发原因&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;EXC_BAD_ACCESS&lt;/td&gt;
&lt;td&gt;SIGSEGV/SIGBUS&lt;/td&gt;
&lt;td&gt;访问无效内存&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;EXC_BAD_INSTRUCTION&lt;/td&gt;
&lt;td&gt;SIGILL&lt;/td&gt;
&lt;td&gt;非法指令&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;EXC_ARITHMETIC&lt;/td&gt;
&lt;td&gt;SIGFPE&lt;/td&gt;
&lt;td&gt;算术异常（如除零）&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;EXC_BREAKPOINT&lt;/td&gt;
&lt;td&gt;SIGTRAP&lt;/td&gt;
&lt;td&gt;断点/调试陷阱&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;EXC_CRASH&lt;/td&gt;
&lt;td&gt;SIGABRT&lt;/td&gt;
&lt;td&gt;程序主动abort&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;hr&gt;
&lt;h2 id="mach异常机制"&gt;Mach异常机制&lt;/h2&gt;
&lt;h3 id="mach内核简介"&gt;Mach内核简介&lt;/h3&gt;
&lt;p&gt;Mach是macOS/iOS的微内核，提供了最基础的系统服务：&lt;/p&gt;</description></item><item><title>+load与+initialize的区别</title><link>https://amatsuzero.github.io/LastStand/posts/interview/ios-basics/load%E4%B8%8Einitialize%E7%9A%84%E5%8C%BA%E5%88%AB/</link><pubDate>Sat, 02 May 2026 22:32:27 +0800</pubDate><guid>https://amatsuzero.github.io/LastStand/posts/interview/ios-basics/load%E4%B8%8Einitialize%E7%9A%84%E5%8C%BA%E5%88%AB/</guid><description>&lt;p&gt;&lt;code&gt;+load&lt;/code&gt;和&lt;code&gt;+initialize&lt;/code&gt;是Objective-C中两个特殊的类方法，它们都会被Runtime自动调用，但调用时机、调用方式和使用场景有很大区别。理解它们的差异对于iOS开发和性能优化非常重要。&lt;/p&gt;
&lt;hr&gt;
&lt;h2 id="基本定义"&gt;基本定义&lt;/h2&gt;
&lt;h3 id="load方法"&gt;+load方法&lt;/h3&gt;
&lt;p&gt;&lt;code&gt;+load&lt;/code&gt;方法在类被加载到内存时由Runtime自动调用，发生在main函数执行之前。&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-objc" data-lang="objc"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;@implementation&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;MyClass&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;+ (&lt;span style="color:#66d9ef"&gt;void&lt;/span&gt;)&lt;span style="color:#a6e22e"&gt;load&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; NSLog(&lt;span style="color:#e6db74"&gt;@&amp;#34;MyClass loaded&amp;#34;&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;@end&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h3 id="initialize方法"&gt;+initialize方法&lt;/h3&gt;
&lt;p&gt;&lt;code&gt;+initialize&lt;/code&gt;方法在类第一次收到消息时由Runtime自动调用，是一种懒加载机制。&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-objc" data-lang="objc"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;@implementation&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;MyClass&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;+ (&lt;span style="color:#66d9ef"&gt;void&lt;/span&gt;)&lt;span style="color:#a6e22e"&gt;initialize&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; NSLog(&lt;span style="color:#e6db74"&gt;@&amp;#34;MyClass initialized&amp;#34;&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;@end&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;hr&gt;
&lt;h2 id="核心区别对比"&gt;核心区别对比&lt;/h2&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;特性&lt;/th&gt;
&lt;th&gt;+load&lt;/th&gt;
&lt;th&gt;+initialize&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;调用时机&lt;/td&gt;
&lt;td&gt;main函数之前，类加载时&lt;/td&gt;
&lt;td&gt;类首次收到消息时&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;调用方式&lt;/td&gt;
&lt;td&gt;直接调用函数指针&lt;/td&gt;
&lt;td&gt;通过objc_msgSend&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;调用次数&lt;/td&gt;
&lt;td&gt;每个类只调用一次&lt;/td&gt;
&lt;td&gt;可能被调用多次&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;是否阻塞启动&lt;/td&gt;
&lt;td&gt;是&lt;/td&gt;
&lt;td&gt;否&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;是否需要显式调用父类&lt;/td&gt;
&lt;td&gt;否，自动调用&lt;/td&gt;
&lt;td&gt;否，自动调用&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Category的行为&lt;/td&gt;
&lt;td&gt;都会被调用&lt;/td&gt;
&lt;td&gt;会覆盖主类实现&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;线程安全&lt;/td&gt;
&lt;td&gt;是&lt;/td&gt;
&lt;td&gt;是&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;调用顺序&lt;/td&gt;
&lt;td&gt;父类 -&amp;gt; 子类 -&amp;gt; Category&lt;/td&gt;
&lt;td&gt;父类 -&amp;gt; 子类&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;未实现时的行为&lt;/td&gt;
&lt;td&gt;不调用&lt;/td&gt;
&lt;td&gt;可能调用父类实现&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;hr&gt;
&lt;h2 id="调用时机详解"&gt;调用时机详解&lt;/h2&gt;
&lt;h3 id="load的调用时机"&gt;+load的调用时机&lt;/h3&gt;
&lt;p&gt;&lt;code&gt;+load&lt;/code&gt;的调用发生在dyld加载镜像的过程中：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-gdscript3" data-lang="gdscript3"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;dyld加载Mach&lt;span style="color:#f92672"&gt;-&lt;/span&gt;O
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#960050;background-color:#1e0010"&gt;↓&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#960050;background-color:#1e0010"&gt;映射到内存&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#960050;background-color:#1e0010"&gt;↓&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#960050;background-color:#1e0010"&gt;读取&lt;/span&gt;__DATA段中的__objc_nlclslist&lt;span style="color:#960050;background-color:#1e0010"&gt;（非懒加载类列表）&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#960050;background-color:#1e0010"&gt;↓&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#960050;background-color:#1e0010"&gt;调用所有类的&lt;/span&gt;&lt;span style="color:#f92672"&gt;+&lt;/span&gt;load方法
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#960050;background-color:#1e0010"&gt;↓&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#960050;background-color:#1e0010"&gt;读取&lt;/span&gt;__objc_nlcatlist&lt;span style="color:#960050;background-color:#1e0010"&gt;（非懒加载分类列表）&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#960050;background-color:#1e0010"&gt;↓&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#960050;background-color:#1e0010"&gt;调用所有分类的&lt;/span&gt;&lt;span style="color:#f92672"&gt;+&lt;/span&gt;load方法
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#960050;background-color:#1e0010"&gt;↓&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;main()&lt;span style="color:#960050;background-color:#1e0010"&gt;函数执行&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h3 id="initialize的调用时机"&gt;+initialize的调用时机&lt;/h3&gt;
&lt;p&gt;&lt;code&gt;+initialize&lt;/code&gt;在类第一次收到消息时调用：&lt;/p&gt;</description></item><item><title>mmap详解</title><link>https://amatsuzero.github.io/LastStand/posts/interview/ios-basics/mmap%E8%AF%A6%E8%A7%A3/</link><pubDate>Thu, 07 May 2026 10:26:09 +0800</pubDate><guid>https://amatsuzero.github.io/LastStand/posts/interview/ios-basics/mmap%E8%AF%A6%E8%A7%A3/</guid><description>&lt;p&gt;mmap（Memory-mapped file，内存映射文件）是一种将文件或设备映射到进程地址空间的技术。通过mmap，可以像操作内存一样操作文件，是iOS开发中实现高性能IO的重要手段。&lt;/p&gt;
&lt;hr&gt;
&lt;h2 id="基本概念"&gt;基本概念&lt;/h2&gt;
&lt;h3 id="什么是mmap"&gt;什么是mmap&lt;/h3&gt;
&lt;p&gt;mmap是一个POSIX系统调用，它在进程的虚拟地址空间中创建一个映射，将文件内容映射到内存地址。映射建立后，对该内存区域的读写操作会直接反映到文件上。&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;文件映射&lt;/strong&gt;：将磁盘上的普通文件映射到内存，用于高效读写文件内容（iOS开发中最常用）&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;设备映射&lt;/strong&gt;：将硬件设备的I/O内存（如显卡显存、网卡缓冲区）映射到用户空间，让程序可以像读写内存一样直接与硬件交互，常用于驱动开发和嵌入式系统&lt;/li&gt;
&lt;/ul&gt;
&lt;pre class="mermaid"&gt;flowchart LR
subgraph traditional["传统文件IO (read/write)"]
direction LR
U1["用户缓冲区"] &lt;-- "② 数据拷贝" --&gt; K1["内核缓冲区"]
K1 &lt;-- "① 磁盘读取" --&gt; F1["磁盘文件"]
end
subgraph mmap_io["mmap 内存映射"]
direction LR
U2["虚拟地址空间&lt;br/&gt;映射区域"] &lt;-. "直接映射&lt;br/&gt;零拷贝" .-&gt; F2["磁盘文件"]
end
traditional ~~~ mmap_io
&lt;/pre&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;方式&lt;/th&gt;
&lt;th&gt;数据流向&lt;/th&gt;
&lt;th&gt;拷贝次数&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;传统IO&lt;/td&gt;
&lt;td&gt;磁盘 → 内核缓冲 → 用户缓冲&lt;/td&gt;
&lt;td&gt;2次&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;mmap&lt;/td&gt;
&lt;td&gt;磁盘 ↔ 映射区域（直接访问）&lt;/td&gt;
&lt;td&gt;0次&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;h3 id="mmap的工作原理"&gt;mmap的工作原理&lt;/h3&gt;
&lt;pre class="mermaid"&gt;flowchart TD
A["调用mmap()"] --&gt; B["内核在进程虚拟地址空间&lt;br/&gt;分配一段连续地址"]
B --&gt; C["建立虚拟地址到文件的映射关系&lt;br/&gt;（页表项指向文件页）"]
C --&gt; D["返回映射区域的起始地址"]
D --&gt; E["进程访问映射地址"]
E --&gt; F{"页面是否在内存中?"}
F -- 否 --&gt; G["触发缺页中断&lt;br/&gt;(Page Fault)"]
G --&gt; H["内核从磁盘读取对应页面&lt;br/&gt;到物理内存"]
H --&gt; I["更新页表，建立映射"]
I --&gt; J["进程继续访问"]
F -- 是 --&gt; J
J --&gt; K["读写操作直接作用于内存"]
K --&gt; L["内核适时将脏页&lt;br/&gt;写回磁盘"]
&lt;/pre&gt;
&lt;hr&gt;
&lt;h2 id="api详解"&gt;API详解&lt;/h2&gt;
&lt;h3 id="mmap函数原型"&gt;mmap函数原型&lt;/h3&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-c" data-lang="c"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;#include&lt;/span&gt; &lt;span style="color:#75715e"&gt;&amp;lt;sys/mman.h&amp;gt;&lt;/span&gt;&lt;span style="color:#75715e"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;void&lt;/span&gt; &lt;span style="color:#f92672"&gt;*&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;mmap&lt;/span&gt;(
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;void&lt;/span&gt; &lt;span style="color:#f92672"&gt;*&lt;/span&gt;addr, &lt;span style="color:#75715e"&gt;// 建议的映射起始地址，通常传NULL让系统决定
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;size_t&lt;/span&gt; length, &lt;span style="color:#75715e"&gt;// 映射区域的长度（字节）
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;int&lt;/span&gt; prot, &lt;span style="color:#75715e"&gt;// 内存保护标志（可读/可写/可执行）
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;int&lt;/span&gt; flags, &lt;span style="color:#75715e"&gt;// 映射类型标志
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;int&lt;/span&gt; fd, &lt;span style="color:#75715e"&gt;// 文件描述符
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;off_t&lt;/span&gt; offset &lt;span style="color:#75715e"&gt;// 文件偏移量（必须是页大小的整数倍）
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;// 返回值：成功返回映射区域的起始地址，失败返回MAP_FAILED
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h3 id="参数详解"&gt;参数详解&lt;/h3&gt;
&lt;p&gt;&lt;strong&gt;prot（内存保护标志）&lt;/strong&gt;：&lt;/p&gt;</description></item><item><title>崩溃-治理</title><link>https://amatsuzero.github.io/LastStand/posts/interview/ios-performance/crash-%E6%B2%BB%E7%90%86/</link><pubDate>Sat, 02 May 2026 22:32:27 +0800</pubDate><guid>https://amatsuzero.github.io/LastStand/posts/interview/ios-performance/crash-%E6%B2%BB%E7%90%86/</guid><description>&lt;p&gt;本文详细介绍常见崩溃类型的修复方法、防崩溃保护机制以及线上监控体系。&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;崩溃治理是 APM 稳定性子系的核心模块。完整的监控建设、多类型稳定性问题（Watchdog/OOM/CPU/IO）的统一治理与 Zombie/Coredump/MemoryGraph 等高级归因能力，请参考 &lt;a href="https://amatsuzero.github.io/LastStand/posts/interview/ios-apm/apm/"&gt;APM 系列&lt;/a&gt;：&lt;a href="https://amatsuzero.github.io/LastStand/posts/interview/ios-apm/%E6%8C%87%E6%A0%87%E4%BD%93%E7%B3%BB/"&gt;指标体系&lt;/a&gt;、&lt;a href="https://amatsuzero.github.io/LastStand/posts/interview/ios-apm/%E4%B8%9A%E7%95%8C%E6%96%B9%E6%A1%88/"&gt;业界方案&lt;/a&gt;。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;hr&gt;
&lt;h2 id="崩溃治理流程"&gt;崩溃治理流程&lt;/h2&gt;
&lt;pre class="mermaid"&gt;flowchart TB
subgraph S1[1. 崩溃发现]
A1[线上监控报警]
A2[用户反馈]
A3[测试发现]
end
subgraph S2[2. 崩溃分析]
B1[符号化堆栈]
B2[问题定位]
B3[根因分析]
end
subgraph S3[3. 问题修复]
C1[代码修复]
C2[防护措施]
C3[回归测试]
end
subgraph S4[4. 效果验证]
D1[灰度发布]
D2[监控崩溃率]
D3[持续跟踪]
end
A1 --&gt; S2
A2 --&gt; S2
A3 --&gt; S2
S2 --&gt; S3
S3 --&gt; S4
&lt;/pre&gt;
&lt;hr&gt;
&lt;h2 id="常见崩溃类型及修复"&gt;常见崩溃类型及修复&lt;/h2&gt;
&lt;h3 id="1-数组越界"&gt;1. 数组越界&lt;/h3&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-objc" data-lang="objc"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;// 崩溃示例
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;NSArray &lt;span style="color:#f92672"&gt;*&lt;/span&gt;array &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;@[&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;@1&lt;/span&gt;, &lt;span style="color:#ae81ff"&gt;@2&lt;/span&gt;, &lt;span style="color:#ae81ff"&gt;@3&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;]&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;id&lt;/span&gt; obj &lt;span style="color:#f92672"&gt;=&lt;/span&gt; array[&lt;span style="color:#ae81ff"&gt;10&lt;/span&gt;]; &lt;span style="color:#75715e"&gt;// NSRangeException
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;// 修复方案1：边界检查
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;- (&lt;span style="color:#66d9ef"&gt;id&lt;/span&gt;)&lt;span style="color:#a6e22e"&gt;safeObjectAtIndex:&lt;/span&gt;(NSUInteger)index &lt;span style="color:#a6e22e"&gt;fromArray:&lt;/span&gt;(NSArray &lt;span style="color:#f92672"&gt;*&lt;/span&gt;)array {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;if&lt;/span&gt; (index &lt;span style="color:#f92672"&gt;&amp;lt;&lt;/span&gt; array.count) {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;return&lt;/span&gt; array[index];
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; }
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;return&lt;/span&gt; nil;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;// 修复方案2：分类安全方法
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;@implementation&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;NSArray&lt;/span&gt; (Safe)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;- (&lt;span style="color:#66d9ef"&gt;id&lt;/span&gt;)&lt;span style="color:#a6e22e"&gt;safeObjectAtIndex:&lt;/span&gt;(NSUInteger)index {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;if&lt;/span&gt; (index &lt;span style="color:#f92672"&gt;&amp;lt;&lt;/span&gt; self.count) {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;return&lt;/span&gt; [self objectAtIndex:index];
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; }
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;return&lt;/span&gt; nil;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;@end&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;// 修复方案3：Swift可选绑定
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;extension Array {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; subscript(safe index: Index) &lt;span style="color:#f92672"&gt;-&amp;gt;&lt;/span&gt; Element&lt;span style="color:#f92672"&gt;?&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;return&lt;/span&gt; indices.contains(index) &lt;span style="color:#f92672"&gt;?&lt;/span&gt; self[index] &lt;span style="color:#f92672"&gt;:&lt;/span&gt; nil
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; }
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;// 使用
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;let value &lt;span style="color:#f92672"&gt;=&lt;/span&gt; array[safe: &lt;span style="color:#ae81ff"&gt;10&lt;/span&gt;] &lt;span style="color:#75715e"&gt;// 返回nil而不是崩溃
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h3 id="2-字典插入nil"&gt;2. 字典插入nil&lt;/h3&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-objc" data-lang="objc"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;// 崩溃示例
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;NSMutableDictionary &lt;span style="color:#f92672"&gt;*&lt;/span&gt;dict &lt;span style="color:#f92672"&gt;=&lt;/span&gt; [NSMutableDictionary dictionary];
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;NSString &lt;span style="color:#f92672"&gt;*&lt;/span&gt;value &lt;span style="color:#f92672"&gt;=&lt;/span&gt; nil;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;[dict setObject:value forKey:&lt;span style="color:#e6db74"&gt;@&amp;#34;key&amp;#34;&lt;/span&gt;]; &lt;span style="color:#75715e"&gt;// NSInvalidArgumentException
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;// 修复方案1：nil检查
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;- (&lt;span style="color:#66d9ef"&gt;void&lt;/span&gt;)&lt;span style="color:#a6e22e"&gt;setObject:&lt;/span&gt;(&lt;span style="color:#66d9ef"&gt;id&lt;/span&gt;)object &lt;span style="color:#a6e22e"&gt;forKey:&lt;/span&gt;(&lt;span style="color:#66d9ef"&gt;id&lt;/span&gt;)key &lt;span style="color:#a6e22e"&gt;inDict:&lt;/span&gt;(NSMutableDictionary &lt;span style="color:#f92672"&gt;*&lt;/span&gt;)dict {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;if&lt;/span&gt; (object &lt;span style="color:#f92672"&gt;&amp;amp;&amp;amp;&lt;/span&gt; key) {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; dict[key] &lt;span style="color:#f92672"&gt;=&lt;/span&gt; object;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; }
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;// 修复方案2：分类安全方法
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;@implementation&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;NSMutableDictionary&lt;/span&gt; (Safe)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;- (&lt;span style="color:#66d9ef"&gt;void&lt;/span&gt;)&lt;span style="color:#a6e22e"&gt;safeSetObject:&lt;/span&gt;(&lt;span style="color:#66d9ef"&gt;id&lt;/span&gt;)object &lt;span style="color:#a6e22e"&gt;forKey:&lt;/span&gt;(&lt;span style="color:#66d9ef"&gt;id&lt;/span&gt;)key {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;if&lt;/span&gt; (object &lt;span style="color:#f92672"&gt;&amp;amp;&amp;amp;&lt;/span&gt; key) {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; [self setObject:object forKey:key];
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; }
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;@end&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;// 修复方案3：使用NSNull
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;dict[&lt;span style="color:#e6db74"&gt;@&amp;#34;key&amp;#34;&lt;/span&gt;] &lt;span style="color:#f92672"&gt;=&lt;/span&gt; value &lt;span style="color:#f92672"&gt;?:&lt;/span&gt; [NSNull null];
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h3 id="3-unrecognized-selector"&gt;3. Unrecognized Selector&lt;/h3&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-objc" data-lang="objc"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;// 崩溃示例
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;NSString &lt;span style="color:#f92672"&gt;*&lt;/span&gt;str &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#e6db74"&gt;@&amp;#34;hello&amp;#34;&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;[str performSelector:&lt;span style="color:#66d9ef"&gt;@selector&lt;/span&gt;(count)]; &lt;span style="color:#75715e"&gt;// unrecognized selector
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;// 修复方案1：respondsToSelector检查
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;if&lt;/span&gt; ([obj respondsToSelector:&lt;span style="color:#66d9ef"&gt;@selector&lt;/span&gt;(someMethod)]) {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; [obj performSelector:&lt;span style="color:#66d9ef"&gt;@selector&lt;/span&gt;(someMethod)];
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;// 修复方案2：消息转发防护
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;@implementation&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;NSObject&lt;/span&gt; (CrashProtection)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;+ (&lt;span style="color:#66d9ef"&gt;void&lt;/span&gt;)&lt;span style="color:#a6e22e"&gt;load&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#75715e"&gt;// Hook forwardingTargetForSelector:
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; Method original &lt;span style="color:#f92672"&gt;=&lt;/span&gt; class_getInstanceMethod(self, &lt;span style="color:#66d9ef"&gt;@selector&lt;/span&gt;(forwardingTargetForSelector:));
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; Method swizzled &lt;span style="color:#f92672"&gt;=&lt;/span&gt; class_getInstanceMethod(self, &lt;span style="color:#66d9ef"&gt;@selector&lt;/span&gt;(safe_forwardingTargetForSelector:));
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; method_exchangeImplementations(original, swizzled);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;- (&lt;span style="color:#66d9ef"&gt;id&lt;/span&gt;)&lt;span style="color:#a6e22e"&gt;safe_forwardingTargetForSelector:&lt;/span&gt;(&lt;span style="color:#66d9ef"&gt;SEL&lt;/span&gt;)aSelector {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#75715e"&gt;// 如果找不到方法，返回一个空实现的对象
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;id&lt;/span&gt; target &lt;span style="color:#f92672"&gt;=&lt;/span&gt; [self safe_forwardingTargetForSelector:aSelector];
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;if&lt;/span&gt; (target) &lt;span style="color:#66d9ef"&gt;return&lt;/span&gt; target;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#75715e"&gt;// 记录错误
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; NSLog(&lt;span style="color:#e6db74"&gt;@&amp;#34;Unrecognized selector: %@ on %@&amp;#34;&lt;/span&gt;, NSStringFromSelector(aSelector), self);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#75715e"&gt;// 返回一个能处理任何消息的对象
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;return&lt;/span&gt; [CrashStub shared];
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;@end&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h3 id="4-kvo崩溃"&gt;4. KVO崩溃&lt;/h3&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-objc" data-lang="objc"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;// 崩溃场景1：重复移除观察者
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;[obj removeObserver:self forKeyPath:&lt;span style="color:#e6db74"&gt;@&amp;#34;value&amp;#34;&lt;/span&gt;];
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;[obj removeObserver:self forKeyPath:&lt;span style="color:#e6db74"&gt;@&amp;#34;value&amp;#34;&lt;/span&gt;]; &lt;span style="color:#75715e"&gt;// 崩溃
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;// 崩溃场景2：未移除观察者就释放
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;- (&lt;span style="color:#66d9ef"&gt;void&lt;/span&gt;)&lt;span style="color:#a6e22e"&gt;dealloc&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#75715e"&gt;// 忘记移除观察者
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;// 修复方案：安全的KVO封装
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;@interface&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;SafeKVOProxy&lt;/span&gt; : &lt;span style="color:#a6e22e"&gt;NSObject&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;@property&lt;/span&gt; (&lt;span style="color:#66d9ef"&gt;nonatomic&lt;/span&gt;, &lt;span style="color:#66d9ef"&gt;weak&lt;/span&gt;) &lt;span style="color:#66d9ef"&gt;id&lt;/span&gt; observer;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;@property&lt;/span&gt; (&lt;span style="color:#66d9ef"&gt;nonatomic&lt;/span&gt;, &lt;span style="color:#66d9ef"&gt;weak&lt;/span&gt;) &lt;span style="color:#66d9ef"&gt;id&lt;/span&gt; target;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;@property&lt;/span&gt; (&lt;span style="color:#66d9ef"&gt;nonatomic&lt;/span&gt;, &lt;span style="color:#66d9ef"&gt;copy&lt;/span&gt;) NSString &lt;span style="color:#f92672"&gt;*&lt;/span&gt;keyPath;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;@property&lt;/span&gt; (&lt;span style="color:#66d9ef"&gt;nonatomic&lt;/span&gt;, &lt;span style="color:#66d9ef"&gt;copy&lt;/span&gt;) &lt;span style="color:#66d9ef"&gt;void&lt;/span&gt; (&lt;span style="color:#f92672"&gt;^&lt;/span&gt;callback)(&lt;span style="color:#66d9ef"&gt;id&lt;/span&gt; newValue);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;@end&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;@implementation&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;SafeKVOProxy&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;- (&lt;span style="color:#66d9ef"&gt;instancetype&lt;/span&gt;)&lt;span style="color:#a6e22e"&gt;initWithTarget:&lt;/span&gt;(&lt;span style="color:#66d9ef"&gt;id&lt;/span&gt;)target
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;keyPath:&lt;/span&gt;(NSString &lt;span style="color:#f92672"&gt;*&lt;/span&gt;)keyPath
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;observer:&lt;/span&gt;(&lt;span style="color:#66d9ef"&gt;id&lt;/span&gt;)observer
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;callback:&lt;/span&gt;(&lt;span style="color:#66d9ef"&gt;void&lt;/span&gt; (&lt;span style="color:#f92672"&gt;^&lt;/span&gt;)(&lt;span style="color:#66d9ef"&gt;id&lt;/span&gt;))callback {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; self &lt;span style="color:#f92672"&gt;=&lt;/span&gt; [super init];
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;if&lt;/span&gt; (self) {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; _target &lt;span style="color:#f92672"&gt;=&lt;/span&gt; target;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; _keyPath &lt;span style="color:#f92672"&gt;=&lt;/span&gt; keyPath;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; _observer &lt;span style="color:#f92672"&gt;=&lt;/span&gt; observer;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; _callback &lt;span style="color:#f92672"&gt;=&lt;/span&gt; callback;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; [target addObserver:self forKeyPath:keyPath options:NSKeyValueObservingOptionNew context:NULL];
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; }
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;return&lt;/span&gt; self;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;- (&lt;span style="color:#66d9ef"&gt;void&lt;/span&gt;)&lt;span style="color:#a6e22e"&gt;observeValueForKeyPath:&lt;/span&gt;(NSString &lt;span style="color:#f92672"&gt;*&lt;/span&gt;)keyPath
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;ofObject:&lt;/span&gt;(&lt;span style="color:#66d9ef"&gt;id&lt;/span&gt;)object
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;change:&lt;/span&gt;(NSDictionary &lt;span style="color:#f92672"&gt;*&lt;/span&gt;)change
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;context:&lt;/span&gt;(&lt;span style="color:#66d9ef"&gt;void&lt;/span&gt; &lt;span style="color:#f92672"&gt;*&lt;/span&gt;)context {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;if&lt;/span&gt; (self.callback) {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; self.callback(change[NSKeyValueChangeNewKey]);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; }
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;- (&lt;span style="color:#66d9ef"&gt;void&lt;/span&gt;)&lt;span style="color:#a6e22e"&gt;dealloc&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; [_target removeObserver:self forKeyPath:_keyPath];
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;@end&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h3 id="5-多线程崩溃"&gt;5. 多线程崩溃&lt;/h3&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-objc" data-lang="objc"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;// 崩溃场景：非线程安全的集合操作
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;// 线程1
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;[mutableArray addObject:obj1];
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;// 线程2
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;[mutableArray removeObjectAtIndex:&lt;span style="color:#ae81ff"&gt;0&lt;/span&gt;]; &lt;span style="color:#75715e"&gt;// 可能崩溃
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;// 修复方案1：加锁
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;@property&lt;/span&gt; (&lt;span style="color:#66d9ef"&gt;nonatomic&lt;/span&gt;, &lt;span style="color:#66d9ef"&gt;strong&lt;/span&gt;) NSLock &lt;span style="color:#f92672"&gt;*&lt;/span&gt;arrayLock;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;- (&lt;span style="color:#66d9ef"&gt;void&lt;/span&gt;)&lt;span style="color:#a6e22e"&gt;safeAddObject:&lt;/span&gt;(&lt;span style="color:#66d9ef"&gt;id&lt;/span&gt;)object {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; [self.arrayLock lock];
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; [self.mutableArray addObject:object];
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; [self.arrayLock unlock];
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;// 修复方案2：使用GCD串行队列
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;@property&lt;/span&gt; (&lt;span style="color:#66d9ef"&gt;nonatomic&lt;/span&gt;, &lt;span style="color:#66d9ef"&gt;strong&lt;/span&gt;) dispatch_queue_t arrayQueue;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;- (&lt;span style="color:#66d9ef"&gt;void&lt;/span&gt;)&lt;span style="color:#a6e22e"&gt;safeAddObject:&lt;/span&gt;(&lt;span style="color:#66d9ef"&gt;id&lt;/span&gt;)object {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; dispatch_sync(self.arrayQueue, &lt;span style="color:#f92672"&gt;^&lt;/span&gt;{
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; [self.mutableArray addObject:object];
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; });
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;// 修复方案3：使用Actor（Swift Concurrency）
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;actor SafeStorage {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; private var items: [Any] &lt;span style="color:#f92672"&gt;=&lt;/span&gt; []
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; func append(_ item: Any) {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; items.append(item)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; }
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; func remove(at index: Int) {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; guard index &lt;span style="color:#f92672"&gt;&amp;lt;&lt;/span&gt; items.count &lt;span style="color:#66d9ef"&gt;else&lt;/span&gt; { &lt;span style="color:#66d9ef"&gt;return&lt;/span&gt; }
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; items.remove(at: index)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; }
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; func getAll() &lt;span style="color:#f92672"&gt;-&amp;gt;&lt;/span&gt; [Any] {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;return&lt;/span&gt; items
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; }
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;let storage &lt;span style="color:#f92672"&gt;=&lt;/span&gt; SafeStorage()
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;await storage.append(obj1)
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h3 id="6-野指针崩溃"&gt;6. 野指针崩溃&lt;/h3&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-objc" data-lang="objc"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;// 崩溃场景
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;__unsafe_unretained &lt;span style="color:#66d9ef"&gt;id&lt;/span&gt; unsafeRef &lt;span style="color:#f92672"&gt;=&lt;/span&gt; obj;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;obj &lt;span style="color:#f92672"&gt;=&lt;/span&gt; nil;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;[unsafeRef description]; &lt;span style="color:#75715e"&gt;// EXC_BAD_ACCESS
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;// 修复方案1：使用weak而非unsafe_unretained
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;__weak&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;id&lt;/span&gt; weakRef &lt;span style="color:#f92672"&gt;=&lt;/span&gt; obj;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;obj &lt;span style="color:#f92672"&gt;=&lt;/span&gt; nil;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;[weakRef description]; &lt;span style="color:#75715e"&gt;// 安全，weakRef为nil
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;// 修复方案2：Zombie Objects检测（调试用）
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;// 在Scheme中启用Zombie Objects
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;// 修复方案3：野指针检测工具
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;// 使用Address Sanitizer
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;// Product -&amp;gt; Scheme -&amp;gt; Edit Scheme -&amp;gt; Diagnostics -&amp;gt; Address Sanitizer
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h3 id="7-swift强制解包崩溃"&gt;7. Swift强制解包崩溃&lt;/h3&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-swift" data-lang="swift"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;// 崩溃示例&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;let&lt;/span&gt; value: String? = &lt;span style="color:#66d9ef"&gt;nil&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;print(value!) &lt;span style="color:#75715e"&gt;// Fatal error: Unexpectedly found nil&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;// 修复方案1：可选绑定&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;if&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;let&lt;/span&gt; value = optionalValue {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; print(value)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;// 修复方案2：空合运算符&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;let&lt;/span&gt; value = optionalValue ?? &lt;span style="color:#e6db74"&gt;&amp;#34;default&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;// 修复方案3：guard语句&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;guard&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;let&lt;/span&gt; value = optionalValue &lt;span style="color:#66d9ef"&gt;else&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;return&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;print(value)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;// 修复方案4：可选链&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;let&lt;/span&gt; length = optionalString?.count &lt;span style="color:#75715e"&gt;// 返回Int?&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h3 id="8-oomout-of-memory崩溃"&gt;8. OOM（Out Of Memory）崩溃&lt;/h3&gt;
&lt;p&gt;OOM 是 iOS 最难治理的崩溃类型之一：系统因进程占用内存超过限制而将其强杀，不会产生标准崩溃日志，App 也没有机会在崩溃现场同步写下详细堆栈。因此 OOM 治理必须&lt;strong&gt;在事故前就把现场数据预埋下来&lt;/strong&gt;，分为三个时段：&lt;/p&gt;</description></item><item><title>崩溃-采集</title><link>https://amatsuzero.github.io/LastStand/posts/interview/ios-performance/crash-%E9%87%87%E9%9B%86/</link><pubDate>Sun, 21 Jun 2026 22:41:52 +0800</pubDate><guid>https://amatsuzero.github.io/LastStand/posts/interview/ios-performance/crash-%E9%87%87%E9%9B%86/</guid><description>&lt;p&gt;准确采集崩溃信息是分析和修复问题的前提。本文详细介绍iOS崩溃的捕获方案、堆栈回溯技术以及符号化原理。&lt;/p&gt;
&lt;hr&gt;
&lt;h2 id="崩溃采集架构"&gt;崩溃采集架构&lt;/h2&gt;
&lt;pre class="mermaid"&gt;flowchart TB
subgraph capture["崩溃捕获层"]
direction LR
mach["Mach Exception Handler"]
signal["Unix Signal Handler"]
exception["NSException Handler"]
end
subgraph collect["信息采集层"]
direction LR
backtrace["堆栈回溯(Backtrace)"]
register["寄存器状态"]
thread["线程信息"]
device["设备/应用信息"]
end
subgraph storage["本地存储层"]
direction LR
async_write["异步安全写入"]
file_manage["崩溃文件管理"]
end
subgraph report["上报处理层"]
direction LR
symbolicate["符号化解析"]
aggregate["崩溃聚合"]
analyze["数据分析"]
end
capture --&gt; collect
collect --&gt; storage
storage --&gt; report
&lt;/pre&gt;
&lt;hr&gt;
&lt;h2 id="mach异常捕获"&gt;Mach异常捕获&lt;/h2&gt;
&lt;p&gt;Mach是macOS/iOS的内核，提供了底层的异常处理机制。Mach异常是最底层的异常类型，发生在内核态，比Unix信号更早被触发。通过注册Mach异常处理器，可以在信号处理之前捕获到崩溃信息。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;核心概念&lt;/strong&gt;：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Mach Port（端口）&lt;/strong&gt;：Mach内核中进程间通信（IPC）的基本单元，类似于文件描述符&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Exception Port（异常端口）&lt;/strong&gt;：专门用于接收异常消息的端口&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Task&lt;/strong&gt;：Mach中的任务概念，对应一个进程，包含地址空间和资源&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id="异常端口注册"&gt;异常端口注册&lt;/h3&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-c" data-lang="c"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;#include&lt;/span&gt; &lt;span style="color:#75715e"&gt;&amp;lt;mach/mach.h&amp;gt;&lt;/span&gt;&lt;span style="color:#75715e"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;// 异常处理线程函数
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;static&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;void&lt;/span&gt; &lt;span style="color:#f92672"&gt;*&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;exception_handler_thread&lt;/span&gt;(&lt;span style="color:#66d9ef"&gt;void&lt;/span&gt; &lt;span style="color:#f92672"&gt;*&lt;/span&gt;arg) {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;mach_port_t&lt;/span&gt; exception_port &lt;span style="color:#f92672"&gt;=&lt;/span&gt; (&lt;span style="color:#66d9ef"&gt;mach_port_t&lt;/span&gt;)(&lt;span style="color:#66d9ef"&gt;uintptr_t&lt;/span&gt;)arg;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;while&lt;/span&gt; (&lt;span style="color:#ae81ff"&gt;1&lt;/span&gt;) {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#75715e"&gt;// 接收异常消息
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;struct&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;mach_msg_header_t&lt;/span&gt; head;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;mach_msg_body_t&lt;/span&gt; body;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#75715e"&gt;// ... 其他字段
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; } request;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;mach_msg_return_t&lt;/span&gt; result &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;mach_msg&lt;/span&gt;(
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;&amp;amp;&lt;/span&gt;request.head,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; MACH_RCV_MSG &lt;span style="color:#f92672"&gt;|&lt;/span&gt; MACH_RCV_LARGE,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#ae81ff"&gt;0&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;sizeof&lt;/span&gt;(request),
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; exception_port,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; MACH_MSG_TIMEOUT_NONE,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; MACH_PORT_NULL
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; );
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;if&lt;/span&gt; (result &lt;span style="color:#f92672"&gt;==&lt;/span&gt; MACH_MSG_SUCCESS) {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#75715e"&gt;// 处理异常
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;handle_exception&lt;/span&gt;(&lt;span style="color:#f92672"&gt;&amp;amp;&lt;/span&gt;request);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; }
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; }
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;return&lt;/span&gt; NULL;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;// 注册异常端口
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;kern_return_t&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;register_exception_handler&lt;/span&gt;(&lt;span style="color:#66d9ef"&gt;void&lt;/span&gt;) {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;kern_return_t&lt;/span&gt; kr;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;mach_port_t&lt;/span&gt; exception_port;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#75715e"&gt;// 创建异常端口
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; kr &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;mach_port_allocate&lt;/span&gt;(
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;mach_task_self&lt;/span&gt;(),
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; MACH_PORT_RIGHT_RECEIVE,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;&amp;amp;&lt;/span&gt;exception_port
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; );
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;if&lt;/span&gt; (kr &lt;span style="color:#f92672"&gt;!=&lt;/span&gt; KERN_SUCCESS) &lt;span style="color:#66d9ef"&gt;return&lt;/span&gt; kr;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#75715e"&gt;// 添加发送权限
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; kr &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;mach_port_insert_right&lt;/span&gt;(
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;mach_task_self&lt;/span&gt;(),
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; exception_port,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; exception_port,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; MACH_MSG_TYPE_MAKE_SEND
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; );
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;if&lt;/span&gt; (kr &lt;span style="color:#f92672"&gt;!=&lt;/span&gt; KERN_SUCCESS) &lt;span style="color:#66d9ef"&gt;return&lt;/span&gt; kr;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#75715e"&gt;// 设置任务异常端口
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; kr &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;task_set_exception_ports&lt;/span&gt;(
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;mach_task_self&lt;/span&gt;(),
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; EXC_MASK_BAD_ACCESS &lt;span style="color:#f92672"&gt;|&lt;/span&gt; EXC_MASK_BAD_INSTRUCTION &lt;span style="color:#f92672"&gt;|&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; EXC_MASK_ARITHMETIC &lt;span style="color:#f92672"&gt;|&lt;/span&gt; EXC_MASK_BREAKPOINT,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; exception_port,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; EXCEPTION_DEFAULT &lt;span style="color:#f92672"&gt;|&lt;/span&gt; MACH_EXCEPTION_CODES,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; THREAD_STATE_NONE
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; );
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;if&lt;/span&gt; (kr &lt;span style="color:#f92672"&gt;!=&lt;/span&gt; KERN_SUCCESS) &lt;span style="color:#66d9ef"&gt;return&lt;/span&gt; kr;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#75715e"&gt;// 创建异常处理线程
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;pthread_t&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;thread&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;pthread_create&lt;/span&gt;(&lt;span style="color:#f92672"&gt;&amp;amp;&lt;/span&gt;&lt;span style="color:#66d9ef"&gt;thread&lt;/span&gt;, NULL, exception_handler_thread,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; (&lt;span style="color:#66d9ef"&gt;void&lt;/span&gt; &lt;span style="color:#f92672"&gt;*&lt;/span&gt;)(&lt;span style="color:#66d9ef"&gt;uintptr_t&lt;/span&gt;)exception_port);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;return&lt;/span&gt; KERN_SUCCESS;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h3 id="mach异常处理流程"&gt;Mach异常处理流程&lt;/h3&gt;
&lt;pre class="mermaid"&gt;flowchart TD
A["1. 异常发生"] --&gt; B["2. 内核发送异常消息到异常端口"]
B --&gt; C["3. 异常处理线程接收消息"]
C --&gt; D["4. 解析异常信息"]
D --&gt; D1["exception type"]
D --&gt; D2["exception code"]
D --&gt; D3["thread state"]
D1 &amp; D2 &amp; D3 --&gt; E["5. 采集崩溃信息"]
E --&gt; E1["堆栈回溯"]
E --&gt; E2["寄存器状态"]
E --&gt; E3["其他上下文"]
E1 &amp; E2 &amp; E3 --&gt; F["6. 保存崩溃日志"]
F --&gt; G["7. 决定后续处理"]
G --&gt; G1["转发给原异常处理器"]
G --&gt; G2["让进程终止"]
&lt;/pre&gt;
&lt;hr&gt;
&lt;h2 id="unix信号捕获"&gt;Unix信号捕获&lt;/h2&gt;
&lt;p&gt;Unix信号（Signal）是操作系统向进程发送的异步通知机制。当发生特定事件（如非法内存访问、算术错误等）时，内核会向进程发送相应的信号。iOS中，Mach异常通常会被转换为对应的Unix信号。&lt;/p&gt;</description></item><item><title>RunLoop</title><link>https://amatsuzero.github.io/LastStand/posts/interview/ios-basics/runloop/</link><pubDate>Wed, 27 May 2026 22:24:03 +0800</pubDate><guid>https://amatsuzero.github.io/LastStand/posts/interview/ios-basics/runloop/</guid><description>&lt;p&gt;RunLoop 是 iOS/macOS 中用于管理线程的事件循环机制。它的核心作用是让线程在有任务时处理任务，没有任务时进入休眠状态，从而避免线程退出并节省 CPU 资源。&lt;/p&gt;
&lt;p&gt;简单来说，RunLoop 就是一个 do-while 循环：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-c" data-lang="c"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;// 伪代码
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;void&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;CFRunLoopRun&lt;/span&gt;() {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;do&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#75715e"&gt;// 处理各种事件源
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#75715e"&gt;// 如果没有事件，线程休眠
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#75715e"&gt;// 有事件时被唤醒处理
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; } &lt;span style="color:#66d9ef"&gt;while&lt;/span&gt; (running);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h2 id="runloop-与线程的关系"&gt;RunLoop 与线程的关系&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;每个线程都有唯一对应的 RunLoop 对象&lt;/li&gt;
&lt;li&gt;主线程和子线程的 RunLoop 都采用懒加载机制，在第一次获取时才创建&lt;/li&gt;
&lt;li&gt;主线程的 RunLoop 由 &lt;code&gt;UIApplicationMain&lt;/code&gt; 内部首次获取并启动（调用链：&lt;code&gt;UIApplicationMain&lt;/code&gt; → &lt;code&gt;GSEventRunModal&lt;/code&gt; → &lt;code&gt;CFRunLoopRunSpecific&lt;/code&gt;）&lt;/li&gt;
&lt;li&gt;RunLoop 与线程是一一对应的，存储在一个全局字典（&lt;code&gt;__CFRunLoops&lt;/code&gt;）中&lt;/li&gt;
&lt;/ul&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-objc" data-lang="objc"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;// 获取当前线程的 RunLoop
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;CFRunLoopRef runLoop &lt;span style="color:#f92672"&gt;=&lt;/span&gt; CFRunLoopGetCurrent();
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;NSRunLoop &lt;span style="color:#f92672"&gt;*&lt;/span&gt;runLoop &lt;span style="color:#f92672"&gt;=&lt;/span&gt; [NSRunLoop currentRunLoop];
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;// 获取主线程的 RunLoop
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;CFRunLoopRef mainRunLoop &lt;span style="color:#f92672"&gt;=&lt;/span&gt; CFRunLoopGetMain();
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;NSRunLoop &lt;span style="color:#f92672"&gt;*&lt;/span&gt;mainRunLoop &lt;span style="color:#f92672"&gt;=&lt;/span&gt; [NSRunLoop mainRunLoop];
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h2 id="runloop-的核心组成"&gt;RunLoop 的核心组成&lt;/h2&gt;
&lt;p&gt;RunLoop 包含以下几个核心概念：&lt;/p&gt;
&lt;h3 id="1-runloop-对象cfrunloopref"&gt;1. RunLoop 对象（CFRunLoopRef）&lt;/h3&gt;
&lt;p&gt;RunLoop 对象本身，管理整个事件循环。在代码层面对应 &lt;code&gt;CFRunLoopRef&lt;/code&gt; 类型。&lt;/p&gt;</description></item><item><title>崩溃</title><link>https://amatsuzero.github.io/LastStand/posts/interview/ios-performance/crash-%E5%B4%A9%E6%BA%83/</link><pubDate>Mon, 04 May 2026 10:37:14 +0800</pubDate><guid>https://amatsuzero.github.io/LastStand/posts/interview/ios-performance/crash-%E5%B4%A9%E6%BA%83/</guid><description>&lt;p&gt;崩溃是影响App稳定性的最严重问题。当应用发生崩溃时，用户会被强制退出应用，严重影响用户体验和产品口碑。&lt;/p&gt;
&lt;p&gt;本系列文章系统性地介绍iOS崩溃的原理、采集方案以及治理策略。&lt;/p&gt;
&lt;hr&gt;
&lt;h2 id="什么是崩溃"&gt;什么是崩溃&lt;/h2&gt;
&lt;p&gt;崩溃（Crash）是指应用程序因为异常或错误而被强制终止的现象。从技术角度看，崩溃可以分为以下几类：&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;崩溃类型&lt;/th&gt;
&lt;th&gt;触发原因&lt;/th&gt;
&lt;th&gt;典型场景&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Mach异常&lt;/td&gt;
&lt;td&gt;底层硬件/内核异常&lt;/td&gt;
&lt;td&gt;访问无效内存、除零错误&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Unix信号&lt;/td&gt;
&lt;td&gt;系统信号导致进程终止&lt;/td&gt;
&lt;td&gt;SIGABRT、SIGSEGV、SIGBUS&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;NSException&lt;/td&gt;
&lt;td&gt;OC层未捕获的异常&lt;/td&gt;
&lt;td&gt;数组越界、unrecognized selector&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;内存问题&lt;/td&gt;
&lt;td&gt;OOM或内存损坏&lt;/td&gt;
&lt;td&gt;内存不足、野指针&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Watchdog&lt;/td&gt;
&lt;td&gt;系统监控超时&lt;/td&gt;
&lt;td&gt;启动超时、后台任务超时&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;hr&gt;
&lt;h2 id="崩溃率指标"&gt;崩溃率指标&lt;/h2&gt;
&lt;p&gt;崩溃率是衡量App稳定性的核心指标：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-plaintext" data-lang="plaintext"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;崩溃率计算方式：
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;1. 崩溃用户率（推荐）
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; 崩溃用户率 = 发生崩溃的用户数 / 总活跃用户数 × 100%
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;2. 崩溃次数率
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; 崩溃次数率 = 崩溃次数 / 启动次数 × 100%
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;3. 崩溃Session率
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; 崩溃Session率 = 崩溃Session数 / 总Session数 × 100%
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;hr&gt;
&lt;h2 id="崩溃处理的整体架构"&gt;崩溃处理的整体架构&lt;/h2&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-plaintext" data-lang="plaintext"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;┌─────────────────────────────────────────────────────────────┐
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;│ 崩溃处理架构 │
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;├─────────────────────────────────────────────────────────────┤
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;│ │
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;│ ┌─────────────────────────────────────────────────────┐ │
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;│ │ 崩溃发生 │ │
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;│ │ Mach异常 / Unix信号 / NSException / OOM │ │
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;│ └─────────────────────────────────────────────────────┘ │
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;│ ↓ │
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;│ ┌─────────────────────────────────────────────────────┐ │
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;│ │ 崩溃捕获 │ │
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;│ │ • Mach异常处理 │ │
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;│ │ • Signal Handler │ │
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;│ │ • NSSetUncaughtExceptionHandler │ │
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;│ └─────────────────────────────────────────────────────┘ │
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;│ ↓ │
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;│ ┌─────────────────────────────────────────────────────┐ │
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;│ │ 信息采集 │ │
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;│ │ • 堆栈信息 │ │
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;│ │ • 设备信息 │ │
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;│ │ • 用户上下文 │ │
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;│ │ • 崩溃现场 │ │
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;│ └─────────────────────────────────────────────────────┘ │
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;│ ↓ │
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;│ ┌─────────────────────────────────────────────────────┐ │
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;│ │ 本地存储 │ │
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;│ │ • 写入文件（需要异步安全） │ │
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;│ │ • 避免使用OC/Swift API │ │
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;│ └─────────────────────────────────────────────────────┘ │
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;│ ↓ │
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;│ ┌─────────────────────────────────────────────────────┐ │
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;│ │ 上报分析 │ │
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;│ │ • 下次启动时上报 │ │
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;│ │ • 符号化解析 │ │
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;│ │ • 聚合分析 │ │
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;│ └─────────────────────────────────────────────────────┘ │
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;│ │
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;└─────────────────────────────────────────────────────────────┘
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;hr&gt;
&lt;h2 id="文章导航"&gt;文章导航&lt;/h2&gt;
&lt;p&gt;本系列包含以下文章，建议按顺序阅读：&lt;/p&gt;</description></item><item><title>Runtime</title><link>https://amatsuzero.github.io/LastStand/posts/interview/ios-basics/runtime/</link><pubDate>Sat, 02 May 2026 22:32:27 +0800</pubDate><guid>https://amatsuzero.github.io/LastStand/posts/interview/ios-basics/runtime/</guid><description>&lt;h2 id="什么是-runtime"&gt;什么是 Runtime&lt;/h2&gt;
&lt;p&gt;Runtime 是 Objective-C 的运行时系统，是一套底层的 C 语言 API。Objective-C 是一门动态语言，很多操作都是在运行时而非编译时决定的，这一切都依赖于 Runtime。&lt;/p&gt;
&lt;p&gt;Runtime 提供的核心能力：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;消息发送与转发&lt;/li&gt;
&lt;li&gt;方法交换（Method Swizzling）&lt;/li&gt;
&lt;li&gt;关联对象（Associated Objects）&lt;/li&gt;
&lt;li&gt;动态创建类和对象&lt;/li&gt;
&lt;li&gt;动态添加和修改方法、属性&lt;/li&gt;
&lt;/ul&gt;
&lt;blockquote&gt;
&lt;p&gt;关于对象、类、isa 指针等底层数据结构的详细介绍，请参考 &lt;a href="https://amatsuzero.github.io/LastStand/posts/interview/ios-basics/objective-c%E5%BA%95%E5%B1%82%E5%8E%9F%E7%90%86-nsobject/"&gt;Objective-C底层原理-NSObject&lt;/a&gt;。本文专注于 Runtime 的动态能力和实际应用。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h2 id="消息发送机制"&gt;消息发送机制&lt;/h2&gt;
&lt;p&gt;Objective-C 的消息发送机制是其动态性的核心体现。与 Swift 支持静态派发不同，Objective-C 的方法调用都是动态消息派发。更多关于两者的对比，请参考 &lt;a href="https://amatsuzero.github.io/LastStand/posts/interview/ios-basics/objective-c%E4%B8%8Eswift%E5%8C%BA%E5%88%AB/"&gt;Objective-C与Swift区别&lt;/a&gt;。&lt;/p&gt;
&lt;h3 id="objc_msgsend"&gt;objc_msgSend&lt;/h3&gt;
&lt;p&gt;Objective-C 的方法调用本质上是消息发送，编译器会将方法调用转换为 &lt;code&gt;objc_msgSend&lt;/code&gt; 函数：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-objc" data-lang="objc"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;// 源代码
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;[obj doSomething];
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;// 编译后
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;objc_msgSend(obj, &lt;span style="color:#66d9ef"&gt;@selector&lt;/span&gt;(doSomething));
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h3 id="消息发送流程"&gt;消息发送流程&lt;/h3&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-fallback" data-lang="fallback"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;1. 检查 receiver 是否为 nil，如果是则直接返回
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;2. 通过 isa 找到 receiver 的类对象
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;3. 在类对象的方法缓存（cache_t）中查找方法
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;4. 如果缓存命中，直接调用方法实现（IMP）
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;5. 如果缓存未命中，在类对象的方法列表中查找
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;6. 如果找到，缓存方法并调用
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;7. 如果未找到，沿着 superclass 链向上查找
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;8. 如果最终未找到，进入消息转发流程
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h3 id="方法缓存"&gt;方法缓存&lt;/h3&gt;
&lt;p&gt;为了提高消息发送效率，Runtime 在类对象中使用哈希表缓存最近调用的方法：&lt;/p&gt;</description></item><item><title>static关键字详解</title><link>https://amatsuzero.github.io/LastStand/posts/interview/ios-basics/static%E5%85%B3%E9%94%AE%E5%AD%97%E8%AF%A6%E8%A7%A3/</link><pubDate>Sun, 03 May 2026 23:11:47 +0800</pubDate><guid>https://amatsuzero.github.io/LastStand/posts/interview/ios-basics/static%E5%85%B3%E9%94%AE%E5%AD%97%E8%AF%A6%E8%A7%A3/</guid><description>&lt;h2 id="基础概念"&gt;基础概念&lt;/h2&gt;
&lt;p&gt;&lt;code&gt;static&lt;/code&gt; 是 C 语言定义的存储类说明符（Storage Class Specifier），Objective-C 和 Swift 中均有使用，但语义有所扩展。它的核心作用可以归纳为两点：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;改变存储位置&lt;/strong&gt;：将局部变量从栈区移到数据段，使其在函数返回后依然存活&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;限制链接可见性&lt;/strong&gt;：将全局变量或函数的链接属性从 external 改为 internal，使其仅在当前编译单元（&lt;code&gt;.m&lt;/code&gt; 文件）内可见&lt;/li&gt;
&lt;/ol&gt;
&lt;pre class="mermaid"&gt;flowchart TD
A["static 关键字"] --&gt; B["修饰局部变量"]
A --&gt; C["修饰全局变量"]
A --&gt; D["修饰函数"]
A --&gt; E["Swift 中的 static"]
B --&gt; B1["存储位置：栈 → 数据段"]
B --&gt; B2["生命周期：函数作用域 → 整个进程"]
B --&gt; B3["作用域不变：仍限于函数内"]
C --&gt; C1["存储位置不变：仍在数据段"]
C --&gt; C2["链接属性：external → internal"]
C --&gt; C3["作用域缩小：全局 → 当前文件"]
D --&gt; D1["存储位置不变：仍在代码段"]
D --&gt; D2["链接属性：external → internal"]
D --&gt; D3["作用域缩小：全局 → 当前文件"]
&lt;/pre&gt;
&lt;h2 id="一静态局部变量"&gt;一、静态局部变量&lt;/h2&gt;
&lt;h3 id="基本用法"&gt;基本用法&lt;/h3&gt;
&lt;p&gt;在函数或方法内部用 &lt;code&gt;static&lt;/code&gt; 修饰局部变量，使其只初始化一次，后续调用保留上次的值。&lt;/p&gt;</description></item><item><title>崩溃日志解读</title><link>https://amatsuzero.github.io/LastStand/posts/interview/ios-performance/crash-%E5%B4%A9%E6%BA%83%E6%97%A5%E5%BF%97%E8%A7%A3%E8%AF%BB/</link><pubDate>Sat, 02 May 2026 22:32:27 +0800</pubDate><guid>https://amatsuzero.github.io/LastStand/posts/interview/ios-performance/crash-%E5%B4%A9%E6%BA%83%E6%97%A5%E5%BF%97%E8%A7%A3%E8%AF%BB/</guid><description>&lt;p&gt;iOS 崩溃日志（&lt;code&gt;.ips&lt;/code&gt; / 老版 &lt;code&gt;.crash&lt;/code&gt;）是排查线上问题的一手证据。它不仅记录了&amp;quot;谁崩了&amp;quot;，更隐藏着&lt;strong&gt;异常类型、终止命名空间、寄存器现场、线程堆栈、二进制映射、资源限额&lt;/strong&gt;等多维度事实。看懂每一个字段，才能把&amp;quot;不能复现&amp;quot;的崩溃拆成&amp;quot;寄存器 x0 是 nil 的后果&amp;quot;这种可复现假设。&lt;/p&gt;
&lt;p&gt;本文聚焦系统生成的崩溃日志本身：格式演变、&lt;code&gt;bug_type&lt;/code&gt; 全景、Header/Body 逐字段、Exception Type / Termination Namespace 深度解读、寄存器视角、符号化工具链、实战案例库、自动化脚本。OOM 专用的 JetsamEvent 日志见 &lt;a href="https://amatsuzero.github.io/LastStand/posts/interview/ios-performance/crash-jetsamevent%E6%97%A5%E5%BF%97%E8%A7%A3%E8%AF%BB/"&gt;JetsamEvent 日志解读&lt;/a&gt;；崩溃采集与治理方法论见 &lt;a href="https://amatsuzero.github.io/LastStand/posts/interview/ios-performance/crash-%E9%87%87%E9%9B%86/"&gt;崩溃-采集&lt;/a&gt;、&lt;a href="https://amatsuzero.github.io/LastStand/posts/interview/ios-performance/crash-%E6%B2%BB%E7%90%86/"&gt;崩溃-治理&lt;/a&gt;。&lt;/p&gt;
&lt;hr&gt;
&lt;h2 id="1-ips--crash-格式演变"&gt;1. &lt;code&gt;.ips&lt;/code&gt; / &lt;code&gt;.crash&lt;/code&gt; 格式演变&lt;/h2&gt;
&lt;p&gt;iOS 的崩溃日志格式几经迭代：&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;时代&lt;/th&gt;
&lt;th&gt;文件扩展名&lt;/th&gt;
&lt;th&gt;格式&lt;/th&gt;
&lt;th&gt;说明&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;iOS 13 及以前&lt;/td&gt;
&lt;td&gt;&lt;code&gt;.crash&lt;/code&gt; / &lt;code&gt;.ips&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;类 plist 纯文本&lt;/td&gt;
&lt;td&gt;Key-Value 混排，人眼可读但难解析&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;iOS 14+&lt;/td&gt;
&lt;td&gt;&lt;code&gt;.ips&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;双段 JSON&lt;/strong&gt;（Header JSON + Body JSON，以换行分隔）&lt;/td&gt;
&lt;td&gt;机器可解析，字段更标准化&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Xcode Organizer 导出&lt;/td&gt;
&lt;td&gt;&lt;code&gt;.crash&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;纯文本渲染视图&lt;/td&gt;
&lt;td&gt;由 &lt;code&gt;.ips&lt;/code&gt; 通过 &lt;code&gt;CrashReporter.framework&lt;/code&gt; 渲染而来&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;解析规则和 JetsamEvent 完全一致——第一行是 Header JSON，剩余部分是 Body JSON，不能整体 parse。iOS 14+ &lt;code&gt;.ips&lt;/code&gt; 内容可用 &lt;code&gt;log show --archive&lt;/code&gt; 或 Xcode Organizer 转为旧式可读文本，但&lt;strong&gt;字段原始数据始终在 JSON 里&lt;/strong&gt;。&lt;/p&gt;</description></item><item><title>weak详解</title><link>https://amatsuzero.github.io/LastStand/posts/interview/ios-basics/weak%E8%AF%A6%E8%A7%A3/</link><pubDate>Sat, 02 May 2026 22:32:27 +0800</pubDate><guid>https://amatsuzero.github.io/LastStand/posts/interview/ios-basics/weak%E8%AF%A6%E8%A7%A3/</guid><description>&lt;p&gt;本文将深入探讨iOS中&lt;code&gt;weak&lt;/code&gt;引用的实现原理，包括底层数据结构、核心函数实现、生命周期管理，以及&lt;code&gt;weak&lt;/code&gt;、&lt;code&gt;unowned&lt;/code&gt;、&lt;code&gt;unsafe_unretained&lt;/code&gt;三者的对比。&lt;/p&gt;
&lt;h2 id="weak的基本概念"&gt;weak的基本概念&lt;/h2&gt;
&lt;p&gt;&lt;code&gt;weak&lt;/code&gt;是一种弱引用修饰符，它&lt;strong&gt;不会增加对象的引用计数&lt;/strong&gt;，也就是说不会持有对象。当对象被释放时，所有指向该对象的&lt;code&gt;weak&lt;/code&gt;引用会&lt;strong&gt;自动被置为nil&lt;/strong&gt;，这是&lt;code&gt;weak&lt;/code&gt;最核心的特性。&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-objc" data-lang="objc"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;// Objective-C中使用weak
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;@property&lt;/span&gt; (&lt;span style="color:#66d9ef"&gt;nonatomic&lt;/span&gt;, &lt;span style="color:#66d9ef"&gt;weak&lt;/span&gt;) &lt;span style="color:#66d9ef"&gt;id&lt;/span&gt;&lt;span style="color:#f92672"&gt;&amp;lt;&lt;/span&gt;SomeDelegate&lt;span style="color:#f92672"&gt;&amp;gt;&lt;/span&gt; delegate;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;__weak&lt;/span&gt; NSObject &lt;span style="color:#f92672"&gt;*&lt;/span&gt;weakObj &lt;span style="color:#f92672"&gt;=&lt;/span&gt; strongObj;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-swift" data-lang="swift"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;// Swift中使用weak&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;weak&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;var&lt;/span&gt; delegate: SomeDelegate?
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;weak&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;var&lt;/span&gt; weakObj = strongObj
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h2 id="weak的底层数据结构"&gt;weak的底层数据结构&lt;/h2&gt;
&lt;p&gt;要理解&lt;code&gt;weak&lt;/code&gt;的实现原理，首先需要了解几个核心数据结构。&lt;/p&gt;
&lt;h3 id="sidetable"&gt;SideTable&lt;/h3&gt;
&lt;p&gt;&lt;code&gt;SideTable&lt;/code&gt;是Runtime中非常重要的数据结构。关于SideTable在引用计数存储中的作用，请参考&lt;a href="https://amatsuzero.github.io/LastStand/posts/interview/ios-basics/ios%E4%B8%AD%E7%9A%84%E5%86%85%E5%AD%98%E7%AE%A1%E7%90%86/#%E4%BE%A7%E8%A1%A8%E5%AD%98%E5%82%A8sidetable"&gt;iOS中的内存管理-侧表存储&lt;/a&gt;。&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-c" data-lang="c"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;struct&lt;/span&gt; SideTable {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; os_unfair_lock slock; &lt;span style="color:#75715e"&gt;// 锁，保证线程安全
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; RefcountMap refcnts; &lt;span style="color:#75715e"&gt;// 引用计数哈希表
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;weak_table_t&lt;/span&gt; weak_table; &lt;span style="color:#75715e"&gt;// 弱引用表
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;};
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;系统维护了一个&lt;strong&gt;固定大小&lt;/strong&gt;的&lt;code&gt;SideTable&lt;/code&gt;数组，称为&lt;code&gt;StripedMap&lt;/code&gt;。通过对对象地址做哈希和取模来定位对应的&lt;code&gt;SideTable&lt;/code&gt;：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-c" data-lang="c"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;// 通过对象地址获取对应的SideTable
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;static&lt;/span&gt; SideTable&lt;span style="color:#f92672"&gt;&amp;amp;&lt;/span&gt; table &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;SideTables&lt;/span&gt;()[obj];
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;// 内部等效逻辑：index = hash(obj) % StripeCount
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;// StripeCount为StripedMap的大小
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;由于对象数量远大于&lt;code&gt;SideTable&lt;/code&gt;数量，&lt;strong&gt;多个对象会被映射到同一个&lt;code&gt;SideTable&lt;/code&gt;&lt;/strong&gt;，这类似于哈希表中的哈希冲突。这种设计的核心目的是&lt;strong&gt;分散锁竞争&lt;/strong&gt;——每个&lt;code&gt;SideTable&lt;/code&gt;拥有独立的锁，不同&lt;code&gt;SideTable&lt;/code&gt;上的操作可以并行执行，相比单一全局表大幅提升了多线程性能。&lt;/p&gt;
&lt;h3 id="weak_table_t"&gt;weak_table_t&lt;/h3&gt;
&lt;p&gt;&lt;code&gt;weak_table_t&lt;/code&gt;是存储弱引用关系的哈希表，采用 &lt;strong&gt;开放寻址法（线性探测）&lt;/strong&gt; 解决哈希冲突：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-c" data-lang="c"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;struct&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;weak_table_t&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;weak_entry_t&lt;/span&gt; &lt;span style="color:#f92672"&gt;*&lt;/span&gt;weak_entries; &lt;span style="color:#75715e"&gt;// 连续分配的数组，作为开放寻址哈希表的底层存储
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;size_t&lt;/span&gt; num_entries; &lt;span style="color:#75715e"&gt;// 当前已使用的条目数量
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;uintptr_t&lt;/span&gt; mask; &lt;span style="color:#75715e"&gt;// 容量掩码（= 数组容量 - 1），用于 hash &amp;amp; mask 快速取模
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;uintptr_t&lt;/span&gt; max_hash_displacement; &lt;span style="color:#75715e"&gt;// 最大哈希冲突偏移量
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;};
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;虽然 &lt;code&gt;weak_entries&lt;/code&gt; 的类型是 &lt;code&gt;weak_entry_t *&lt;/code&gt;（即一块连续内存），但元素&lt;strong&gt;不是按顺序填入&lt;/strong&gt;的——插入时通过 &lt;code&gt;hash(referent地址) &amp;amp; mask&lt;/code&gt; 计算目标槽位，冲突时向后线性探测。因此它本质上是一个&lt;strong&gt;用数组实现的开放寻址哈希表&lt;/strong&gt;，而非普通的顺序数组。&lt;/p&gt;</description></item><item><title>卡顿-TableView优化</title><link>https://amatsuzero.github.io/LastStand/posts/interview/ios-performance/stutter-tableview%E4%BC%98%E5%8C%96/</link><pubDate>Sat, 02 May 2026 22:32:27 +0800</pubDate><guid>https://amatsuzero.github.io/LastStand/posts/interview/ios-performance/stutter-tableview%E4%BC%98%E5%8C%96/</guid><description>&lt;p&gt;列表滚动是用户最敏感的交互场景之一。本文介绍UITableView和UICollectionView的性能优化方案。&lt;/p&gt;
&lt;hr&gt;
&lt;h2 id="列表卡顿的常见原因"&gt;列表卡顿的常见原因&lt;/h2&gt;
&lt;pre class="mermaid"&gt;flowchart TB
subgraph frame["每一帧（16.67ms内）需要完成"]
A["1. 计算可见Cell"] --&gt; B["2. 复用或创建Cell"]
B --&gt; C["3. 配置Cell内容"]
C --&gt; C1["设置文本"]
C --&gt; C2["加载图片"]
C --&gt; C3["计算布局"]
C --&gt; C4["渲染视图"]
C1 --&gt; D["4. 提交渲染"]
C2 --&gt; D
C3 --&gt; D
C4 --&gt; D
end
D --&gt; E["⚠️ 任何一步超时都会导致掉帧"]
&lt;/pre&gt;
&lt;h3 id="常见问题"&gt;常见问题&lt;/h3&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;问题&lt;/th&gt;
&lt;th&gt;原因&lt;/th&gt;
&lt;th&gt;影响&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;高度计算慢&lt;/td&gt;
&lt;td&gt;复杂布局、Auto Layout&lt;/td&gt;
&lt;td&gt;滚动卡顿&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Cell配置慢&lt;/td&gt;
&lt;td&gt;大量视图操作、图片加载&lt;/td&gt;
&lt;td&gt;滚动卡顿&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;复用失效&lt;/td&gt;
&lt;td&gt;未正确注册、identifier错误&lt;/td&gt;
&lt;td&gt;内存暴涨、卡顿&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;离屏渲染&lt;/td&gt;
&lt;td&gt;圆角、阴影&lt;/td&gt;
&lt;td&gt;GPU瓶颈&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;图片加载&lt;/td&gt;
&lt;td&gt;主线程解码&lt;/td&gt;
&lt;td&gt;滚动卡顿&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;hr&gt;
&lt;h2 id="cell复用机制"&gt;Cell复用机制&lt;/h2&gt;
&lt;h3 id="正确使用复用"&gt;正确使用复用&lt;/h3&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-swift" data-lang="swift"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;class&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;OptimizedTableViewController&lt;/span&gt;: UITableViewController {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;private&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;let&lt;/span&gt; cellIdentifier = &lt;span style="color:#e6db74"&gt;&amp;#34;OptimizedCell&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;override&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;func&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;viewDidLoad&lt;/span&gt;() {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;super&lt;/span&gt;.viewDidLoad()
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#75715e"&gt;// 注册Cell类（推荐）&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; tableView.register(OptimizedCell.&lt;span style="color:#66d9ef"&gt;self&lt;/span&gt;, forCellReuseIdentifier: cellIdentifier)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#75715e"&gt;// 或注册Nib&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#75715e"&gt;// tableView.register(UINib(nibName: &amp;#34;OptimizedCell&amp;#34;, bundle: nil), forCellReuseIdentifier: cellIdentifier)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; }
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;override&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;func&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;tableView&lt;/span&gt;(&lt;span style="color:#66d9ef"&gt;_&lt;/span&gt; tableView: UITableView, cellForRowAt indexPath: IndexPath) -&amp;gt; UITableViewCell {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#75715e"&gt;// 使用dequeueReusableCell（带indexPath的版本会自动创建）&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;let&lt;/span&gt; cell = tableView.dequeueReusableCell(withIdentifier: cellIdentifier, &lt;span style="color:#66d9ef"&gt;for&lt;/span&gt;: indexPath) &lt;span style="color:#66d9ef"&gt;as&lt;/span&gt;! OptimizedCell
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#75715e"&gt;// 配置Cell&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;let&lt;/span&gt; item = items[indexPath.row]
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; cell.configure(with: item)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;return&lt;/span&gt; cell
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; }
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h3 id="cell的prepareforreuse"&gt;Cell的prepareForReuse&lt;/h3&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-swift" data-lang="swift"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;class&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;OptimizedCell&lt;/span&gt;: UITableViewCell {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;private&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;let&lt;/span&gt; titleLabel = UILabel()
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;private&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;let&lt;/span&gt; avatarImageView = OptimizedImageView()
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;private&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;var&lt;/span&gt; currentTask: URLSessionTask?
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;override&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;func&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;prepareForReuse&lt;/span&gt;() {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;super&lt;/span&gt;.prepareForReuse()
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#75715e"&gt;// 重置状态&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; titleLabel.text = &lt;span style="color:#66d9ef"&gt;nil&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; avatarImageView.image = &lt;span style="color:#66d9ef"&gt;nil&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#75715e"&gt;// 取消进行中的任务&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; currentTask?.cancel()
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; currentTask = &lt;span style="color:#66d9ef"&gt;nil&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; avatarImageView.cancelLoading()
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; }
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;func&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;configure&lt;/span&gt;(with item: Item) {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; titleLabel.text = item.title
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#75715e"&gt;// 异步加载图片&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; avatarImageView.setImage(from: item.avatarURL, placeholder: UIImage(named: &lt;span style="color:#e6db74"&gt;&amp;#34;placeholder&amp;#34;&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; }
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;hr&gt;
&lt;h2 id="高度缓存"&gt;高度缓存&lt;/h2&gt;
&lt;h3 id="问题每次都计算高度"&gt;问题：每次都计算高度&lt;/h3&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-swift" data-lang="swift"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;// 问题代码：每次滚动都重新计算&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;func&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;tableView&lt;/span&gt;(&lt;span style="color:#66d9ef"&gt;_&lt;/span&gt; tableView: UITableView, heightForRowAt indexPath: IndexPath) -&amp;gt; CGFloat {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;let&lt;/span&gt; item = items[indexPath.row]
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;return&lt;/span&gt; calculateHeight(&lt;span style="color:#66d9ef"&gt;for&lt;/span&gt;: item) &lt;span style="color:#75715e"&gt;// 耗时操作&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h3 id="解决方案1预计算并缓存"&gt;解决方案1：预计算并缓存&lt;/h3&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-swift" data-lang="swift"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;class&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;HeightCachedTableViewController&lt;/span&gt;: UITableViewController {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;private&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;var&lt;/span&gt; items: [Item] = []
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;private&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;var&lt;/span&gt; heightCache: [IndexPath: CGFloat] = [:]
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;func&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;setItems&lt;/span&gt;(&lt;span style="color:#66d9ef"&gt;_&lt;/span&gt; newItems: [Item]) {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; items = newItems
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; heightCache.removeAll()
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#75715e"&gt;// 预计算高度（可以在后台线程）&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; precomputeHeights()
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; tableView.reloadData()
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; }
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;private&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;func&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;precomputeHeights&lt;/span&gt;() {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;let&lt;/span&gt; width = tableView.bounds.width
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;for&lt;/span&gt; (index, item) &lt;span style="color:#66d9ef"&gt;in&lt;/span&gt; items.enumerated() {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;let&lt;/span&gt; indexPath = IndexPath(row: index, section: &lt;span style="color:#ae81ff"&gt;0&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; heightCache[indexPath] = calculateHeight(&lt;span style="color:#66d9ef"&gt;for&lt;/span&gt;: item, width: width)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; }
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; }
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;private&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;func&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;calculateHeight&lt;/span&gt;(&lt;span style="color:#66d9ef"&gt;for&lt;/span&gt; item: Item, width: CGFloat) -&amp;gt; CGFloat {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#75715e"&gt;// 计算文本高度&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;let&lt;/span&gt; textHeight = item.content.boundingRect(
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; with: CGSize(width: width &lt;span style="color:#f92672"&gt;-&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;32&lt;/span&gt;, height: .greatestFiniteMagnitude),
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; options: [.usesLineFragmentOrigin, .usesFontLeading],
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; attributes: [.font: UIFont.systemFont(ofSize: &lt;span style="color:#ae81ff"&gt;16&lt;/span&gt;)],
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; context: &lt;span style="color:#66d9ef"&gt;nil&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; ).height
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;return&lt;/span&gt; ceil(textHeight) &lt;span style="color:#f92672"&gt;+&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;60&lt;/span&gt; &lt;span style="color:#75715e"&gt;// 加上其他元素的高度&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; }
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;override&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;func&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;tableView&lt;/span&gt;(&lt;span style="color:#66d9ef"&gt;_&lt;/span&gt; tableView: UITableView, heightForRowAt indexPath: IndexPath) -&amp;gt; CGFloat {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;return&lt;/span&gt; heightCache[indexPath] ?? UITableView.automaticDimension
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; }
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#75715e"&gt;// 数据更新时更新缓存&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;func&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;updateItem&lt;/span&gt;(at indexPath: IndexPath, with item: Item) {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; items[indexPath.row] = item
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; heightCache[indexPath] = calculateHeight(&lt;span style="color:#66d9ef"&gt;for&lt;/span&gt;: item, width: tableView.bounds.width)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; tableView.reloadRows(at: [indexPath], with: .automatic)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; }
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h3 id="解决方案2使用estimatedheight"&gt;解决方案2：使用estimatedHeight&lt;/h3&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-swift" data-lang="swift"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;class&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;EstimatedHeightTableViewController&lt;/span&gt;: UITableViewController {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;private&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;var&lt;/span&gt; heightCache: [IndexPath: CGFloat] = [:]
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;override&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;func&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;viewDidLoad&lt;/span&gt;() {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;super&lt;/span&gt;.viewDidLoad()
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#75715e"&gt;// 设置估算高度（重要！）&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; tableView.estimatedRowHeight = &lt;span style="color:#ae81ff"&gt;100&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; tableView.rowHeight = UITableView.automaticDimension
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; }
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;override&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;func&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;tableView&lt;/span&gt;(&lt;span style="color:#66d9ef"&gt;_&lt;/span&gt; tableView: UITableView, willDisplay cell: UITableViewCell, forRowAt indexPath: IndexPath) {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#75715e"&gt;// 缓存实际显示的高度&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; heightCache[indexPath] = cell.bounds.height
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; }
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;override&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;func&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;tableView&lt;/span&gt;(&lt;span style="color:#66d9ef"&gt;_&lt;/span&gt; tableView: UITableView, estimatedHeightForRowAt indexPath: IndexPath) -&amp;gt; CGFloat {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#75715e"&gt;// 优先返回缓存的高度&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;return&lt;/span&gt; heightCache[indexPath] ?? &lt;span style="color:#ae81ff"&gt;100&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; }
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h3 id="解决方案3固定高度"&gt;解决方案3：固定高度&lt;/h3&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-swift" data-lang="swift"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;// 如果所有Cell高度相同，直接设置固定值&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;override&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;func&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;viewDidLoad&lt;/span&gt;() {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;super&lt;/span&gt;.viewDidLoad()
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; tableView.rowHeight = &lt;span style="color:#ae81ff"&gt;80&lt;/span&gt; &lt;span style="color:#75715e"&gt;// 固定高度，性能最好&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; tableView.estimatedRowHeight = &lt;span style="color:#ae81ff"&gt;0&lt;/span&gt; &lt;span style="color:#75715e"&gt;// 关闭估算&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;hr&gt;
&lt;h2 id="异步渲染"&gt;异步渲染&lt;/h2&gt;
&lt;h3 id="基本原理"&gt;基本原理&lt;/h3&gt;
&lt;p&gt;将复杂的渲染工作移到后台线程：&lt;/p&gt;</description></item><item><title>值类型和引用类型的区别</title><link>https://amatsuzero.github.io/LastStand/posts/interview/ios-basics/%E5%80%BC%E7%B1%BB%E5%9E%8B%E5%92%8C%E5%BC%95%E7%94%A8%E7%B1%BB%E5%9E%8B%E7%9A%84%E5%8C%BA%E5%88%AB/</link><pubDate>Sun, 10 May 2026 22:25:41 +0800</pubDate><guid>https://amatsuzero.github.io/LastStand/posts/interview/ios-basics/%E5%80%BC%E7%B1%BB%E5%9E%8B%E5%92%8C%E5%BC%95%E7%94%A8%E7%B1%BB%E5%9E%8B%E7%9A%84%E5%8C%BA%E5%88%AB/</guid><description>&lt;h2 id="定义"&gt;定义&lt;/h2&gt;
&lt;h3 id="值类型"&gt;值类型&lt;/h3&gt;
&lt;p&gt;值类型是指变量直接存储自身字段或描述信息的类型。值类型具有值语义，当将一个值类型变量赋值给另一个变量时，语义上会得到一份独立的值；底层是否立即复制完整数据，取决于编译器优化和写时拷贝等实现。&lt;/p&gt;
&lt;h3 id="引用类型"&gt;引用类型&lt;/h3&gt;
&lt;p&gt;引用类型是指变量存储的是指向数据在内存中位置的引用（指针）。当将一个引用类型变量赋值给另一个变量时，两个变量指向同一块内存区域。&lt;/p&gt;
&lt;h2 id="objective-c中的类型分类"&gt;Objective-C中的类型分类&lt;/h2&gt;
&lt;p&gt;在Objective-C中：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;值类型&lt;/strong&gt;：基础数据类型（int、float、double、BOOL、char等）、结构体（struct）、枚举（enum）&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;引用类型&lt;/strong&gt;：除基础数据类型之外的大部分类型，包括NSObject及其子类（NSString、NSArray、NSDictionary、自定义类等）&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="swift中的类型分类"&gt;Swift中的类型分类&lt;/h2&gt;
&lt;p&gt;Swift对类型的分类更加清晰：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;值类型&lt;/strong&gt;：基础数据类型（Int、Float、Double、Bool等）、字符串（String）、结构体（Struct）、枚举（Enum）、数组（Array）、字典（Dictionary）、集合（Set）等&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;引用类型&lt;/strong&gt;：类（Class）、闭包（Closure）、Actor等&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="拷贝机制差异"&gt;拷贝机制差异&lt;/h2&gt;
&lt;h3 id="值类型---值语义拷贝"&gt;值类型 - 值语义拷贝&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;每个值类型变量都有自己的字段存储&lt;/li&gt;
&lt;li&gt;对一个变量的操作不会影响另一个变量&lt;/li&gt;
&lt;li&gt;赋值语义上会得到独立副本；如果字段是引用类型，复制的是引用本身，底层也可能通过写时拷贝延迟真正的数据复制&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id="引用类型---浅拷贝"&gt;引用类型 - 浅拷贝&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;引用类型在内存中有一个指向该位置的引用&lt;/li&gt;
&lt;li&gt;引用类型的变量可以指向相同类型的数据&lt;/li&gt;
&lt;li&gt;对一个变量进行的操作会影响另一变量所指向的数据&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="内存分配机制"&gt;内存分配机制&lt;/h2&gt;
&lt;p&gt;需要注意：&lt;strong&gt;值类型/引用类型描述的是语义模型，不等价于栈/堆分配规则&lt;/strong&gt;。Swift编译器会根据生命周期、逃逸分析、优化级别、协议类型包装、集合存储等因素决定具体放在哪里。&lt;/p&gt;
&lt;p&gt;理解Swift对象和字段的内存位置，可以先记住三个规则：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;class实例本体&lt;/strong&gt;通常在堆上，通过引用计数管理生命周期&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;struct/enum的字段&lt;/strong&gt;通常内联存储在这个值本身所在的位置&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;class类型的字段&lt;/strong&gt;存储的是对象引用，也就是一个指针，真实class实例仍然在堆上&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id="常见存储位置"&gt;常见存储位置&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;局部值类型变量&lt;/strong&gt;：生命周期明确、未逃逸时，通常可以放在当前线程的栈区，甚至被优化到寄存器中&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;class实例&lt;/strong&gt;：实例本体在堆区，局部变量中保存的是指向堆对象的引用&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;class里的struct属性&lt;/strong&gt;：struct属性内联存储在class实例这块堆内存中&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;struct里的class属性&lt;/strong&gt;：struct内部只保存class引用，真实class实例仍然在堆上&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;被逃逸闭包捕获的值类型&lt;/strong&gt;可能随闭包上下文一起存储在堆区&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Array、Dictionary、Set、String等写时拷贝值类型&lt;/strong&gt;通常只有一小段描述信息是值本身，真实元素或字符缓冲区可能在堆上&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;协议类型（existential container）持有大值类型&lt;/strong&gt;时，如果超过存在容器的内联缓冲区大小，会使用堆分配&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;indirect enum&lt;/strong&gt;的间接关联值会通过堆上的盒子存储，常见于递归枚举&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;全局变量、静态变量&lt;/strong&gt;不属于栈区，也不是普通意义上的堆对象，它们通常位于全局/静态存储区&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;栈区内存分配和销毁通常只需移动栈顶指针，成本较低；堆区更动态，但分配、释放和引用计数维护都有额外成本。&lt;/p&gt;
&lt;h3 id="struct中包含class属性"&gt;struct中包含class属性&lt;/h3&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-swift" data-lang="swift"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;class&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;Dog&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;var&lt;/span&gt; name: String
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;init&lt;/span&gt;(name: String) {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;self&lt;/span&gt;.name = name
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; }
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;struct&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;Person&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;var&lt;/span&gt; age: Int
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;var&lt;/span&gt; dog: Dog
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;var&lt;/span&gt; p1 = Person(age: &lt;span style="color:#ae81ff"&gt;18&lt;/span&gt;, dog: Dog(name: &lt;span style="color:#e6db74"&gt;&amp;#34;Lucky&amp;#34;&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;var&lt;/span&gt; p2 = p1
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;p2.age = &lt;span style="color:#ae81ff"&gt;20&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;p2.dog.name = &lt;span style="color:#e6db74"&gt;&amp;#34;Max&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;print(p1.age) &lt;span style="color:#75715e"&gt;// 18&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;print(p1.dog.name) &lt;span style="color:#75715e"&gt;// Max&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;内存关系可以近似理解为：&lt;/p&gt;</description></item><item><title>卡顿-主线程优化</title><link>https://amatsuzero.github.io/LastStand/posts/interview/ios-performance/stutter-%E4%B8%BB%E7%BA%BF%E7%A8%8B%E4%BC%98%E5%8C%96/</link><pubDate>Sat, 02 May 2026 22:32:27 +0800</pubDate><guid>https://amatsuzero.github.io/LastStand/posts/interview/ios-performance/stutter-%E4%B8%BB%E7%BA%BF%E7%A8%8B%E4%BC%98%E5%8C%96/</guid><description>&lt;p&gt;主线程阻塞是卡顿最常见的原因。本文介绍如何优化主线程的工作，减少阻塞时间。&lt;/p&gt;
&lt;hr&gt;
&lt;h2 id="主线程的职责"&gt;主线程的职责&lt;/h2&gt;
&lt;p&gt;主线程（UI线程）负责：&lt;/p&gt;
&lt;pre class="mermaid"&gt;mindmap
root((主线程职责))
事件处理
触摸事件
手势识别
UI更新
布局计算
视图绘制
动画执行
Core Animation
UIView动画
系统回调
生命周期
AppDelegate
定时器
NSTimer
CADisplayLink
通知处理
NotificationCenter
KVO
&lt;/pre&gt;
&lt;blockquote&gt;
&lt;p&gt;原则：主线程应该只做UI相关的轻量级工作&lt;/p&gt;
&lt;/blockquote&gt;
&lt;hr&gt;
&lt;h2 id="常见的主线程阻塞场景"&gt;常见的主线程阻塞场景&lt;/h2&gt;
&lt;h3 id="1-耗时计算"&gt;1. 耗时计算&lt;/h3&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-swift" data-lang="swift"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;// 问题代码：在主线程进行复杂计算&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;func&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;processData&lt;/span&gt;() {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;let&lt;/span&gt; result = heavyComputation(data) &lt;span style="color:#75715e"&gt;// 阻塞主线程&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; updateUI(with: result)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;// 优化后：异步计算&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;func&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;processDataAsync&lt;/span&gt;() {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; DispatchQueue.global(qos: .userInitiated).async {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;let&lt;/span&gt; result = &lt;span style="color:#66d9ef"&gt;self&lt;/span&gt;.heavyComputation(&lt;span style="color:#66d9ef"&gt;self&lt;/span&gt;.data)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; DispatchQueue.main.async {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;self&lt;/span&gt;.updateUI(with: result)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; }
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; }
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h3 id="2-文件io"&gt;2. 文件I/O&lt;/h3&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-swift" data-lang="swift"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;// 问题代码：主线程读写文件&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;func&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;loadConfig&lt;/span&gt;() {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;let&lt;/span&gt; data = &lt;span style="color:#66d9ef"&gt;try&lt;/span&gt;? Data(contentsOf: configURL) &lt;span style="color:#75715e"&gt;// 阻塞&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; parseConfig(data)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;// 优化后：异步I/O&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;func&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;loadConfigAsync&lt;/span&gt;() {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; DispatchQueue.global(qos: .utility).async {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;let&lt;/span&gt; data = &lt;span style="color:#66d9ef"&gt;try&lt;/span&gt;? Data(contentsOf: &lt;span style="color:#66d9ef"&gt;self&lt;/span&gt;.configURL)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; DispatchQueue.main.async {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;self&lt;/span&gt;.parseConfig(data)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; }
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; }
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h3 id="3-数据库操作"&gt;3. 数据库操作&lt;/h3&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-swift" data-lang="swift"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;// 问题代码：主线程数据库查询&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;func&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;loadUsers&lt;/span&gt;() {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;let&lt;/span&gt; users = database.query(&lt;span style="color:#e6db74"&gt;&amp;#34;SELECT * FROM users&amp;#34;&lt;/span&gt;) &lt;span style="color:#75715e"&gt;// 阻塞&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; tableView.reloadData()
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;// 优化后：异步查询&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;func&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;loadUsersAsync&lt;/span&gt;() {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; database.queryAsync(&lt;span style="color:#e6db74"&gt;&amp;#34;SELECT * FROM users&amp;#34;&lt;/span&gt;) { [&lt;span style="color:#66d9ef"&gt;weak&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;self&lt;/span&gt;] users &lt;span style="color:#66d9ef"&gt;in&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;self&lt;/span&gt;?.users = users
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; DispatchQueue.main.async {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;self&lt;/span&gt;?.tableView.reloadData()
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; }
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; }
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;hr&gt;
&lt;h2 id="任务异步化"&gt;任务异步化&lt;/h2&gt;
&lt;h3 id="基本原则"&gt;基本原则&lt;/h3&gt;
&lt;pre class="mermaid"&gt;flowchart TB
subgraph main["主线程任务"]
direction LR
A1["UI更新&lt;br/&gt;视图刷新、动画"]
A2["用户交互&lt;br/&gt;点击响应、手势处理"]
A3["轻量计算&lt;br/&gt;简单数据转换"]
end
subgraph bg["后台线程任务"]
direction LR
B1["复杂计算&lt;br/&gt;数据处理、算法"]
B2["I/O操作&lt;br/&gt;文件读写、网络请求"]
B3["数据库操作&lt;br/&gt;查询、写入"]
B4["图片处理&lt;br/&gt;解码、缩放、滤镜"]
end
main --&gt; |"轻量、快速"| UI((用户界面))
bg --&gt; |"耗时、阻塞"| main
&lt;/pre&gt;
&lt;h3 id="gcd任务调度"&gt;GCD任务调度&lt;/h3&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-swift" data-lang="swift"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;class&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;AsyncTaskManager&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#75715e"&gt;// 计算密集型任务&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;static&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;func&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;compute&lt;/span&gt;&amp;lt;T&amp;gt;(&lt;span style="color:#66d9ef"&gt;_&lt;/span&gt; work: @escaping () -&amp;gt; T,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; completion: @escaping (T) -&amp;gt; Void) {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; DispatchQueue.global(qos: .userInitiated).async {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;let&lt;/span&gt; result = work()
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; DispatchQueue.main.async {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; completion(result)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; }
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; }
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; }
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#75715e"&gt;// I/O任务&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;static&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;func&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;io&lt;/span&gt;&amp;lt;T&amp;gt;(&lt;span style="color:#66d9ef"&gt;_&lt;/span&gt; work: @escaping () &lt;span style="color:#66d9ef"&gt;throws&lt;/span&gt; -&amp;gt; T,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; completion: @escaping (Result&amp;lt;T, Error&amp;gt;) -&amp;gt; Void) {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; DispatchQueue.global(qos: .utility).async {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;do&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;let&lt;/span&gt; result = &lt;span style="color:#66d9ef"&gt;try&lt;/span&gt; work()
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; DispatchQueue.main.async {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; completion(.success(result))
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; }
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; } &lt;span style="color:#66d9ef"&gt;catch&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; DispatchQueue.main.async {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; completion(.failure(error))
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; }
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; }
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; }
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; }
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#75715e"&gt;// 低优先级后台任务&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;static&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;func&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;background&lt;/span&gt;(&lt;span style="color:#66d9ef"&gt;_&lt;/span&gt; work: @escaping () -&amp;gt; Void) {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; DispatchQueue.global(qos: .background).async {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; work()
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; }
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; }
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;// 使用示例&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;AsyncTaskManager.compute({
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#75715e"&gt;// 复杂计算&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;return&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;self&lt;/span&gt;.processLargeDataSet()
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;}) { result &lt;span style="color:#66d9ef"&gt;in&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#75715e"&gt;// 主线程更新UI&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;self&lt;/span&gt;.displayResult(result)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h3 id="swift-concurrency"&gt;Swift Concurrency&lt;/h3&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-swift" data-lang="swift"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;// 使用async/await&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;class&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;DataProcessor&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;func&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;processAsync&lt;/span&gt;() async &lt;span style="color:#66d9ef"&gt;throws&lt;/span&gt; -&amp;gt; ProcessedData {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#75715e"&gt;// 在后台执行&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;return&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;try&lt;/span&gt; await Task.detached(priority: .userInitiated) {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;return&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;self&lt;/span&gt;.heavyProcessing()
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; }.value
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; }
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; @MainActor
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;func&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;loadAndDisplay&lt;/span&gt;() async {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;do&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;let&lt;/span&gt; data = &lt;span style="color:#66d9ef"&gt;try&lt;/span&gt; await processAsync()
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#75715e"&gt;// 自动在主线程更新UI&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; updateUI(with: data)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; } &lt;span style="color:#66d9ef"&gt;catch&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; showError(error)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; }
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; }
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;// 使用TaskGroup并行处理&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;func&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;processImagesParallel&lt;/span&gt;(urls: [URL]) async -&amp;gt; [UIImage] {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; await withTaskGroup(of: UIImage?.&lt;span style="color:#66d9ef"&gt;self&lt;/span&gt;) { group &lt;span style="color:#66d9ef"&gt;in&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;for&lt;/span&gt; url &lt;span style="color:#66d9ef"&gt;in&lt;/span&gt; urls {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; group.addTask {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; await &lt;span style="color:#66d9ef"&gt;self&lt;/span&gt;.loadImage(from: url)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; }
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; }
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;var&lt;/span&gt; images: [UIImage] = []
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;for&lt;/span&gt; await image &lt;span style="color:#66d9ef"&gt;in&lt;/span&gt; group {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;if&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;let&lt;/span&gt; image = image {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; images.append(image)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; }
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; }
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;return&lt;/span&gt; images
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; }
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;hr&gt;
&lt;h2 id="任务拆分与调度"&gt;任务拆分与调度&lt;/h2&gt;
&lt;h3 id="大任务拆分"&gt;大任务拆分&lt;/h3&gt;
&lt;p&gt;当必须在主线程执行大量工作时，可以拆分成小块：&lt;/p&gt;</description></item><item><title>iOS响应者链与事件处理机制</title><link>https://amatsuzero.github.io/LastStand/posts/interview/ios-basics/%E5%93%8D%E5%BA%94%E8%80%85%E9%93%BE/</link><pubDate>Sat, 02 May 2026 22:32:27 +0800</pubDate><guid>https://amatsuzero.github.io/LastStand/posts/interview/ios-basics/%E5%93%8D%E5%BA%94%E8%80%85%E9%93%BE/</guid><description>&lt;p&gt;当手指触碰iPhone屏幕上的一个按钮时，背后经历了从硬件感知、系统传递、命中测试、事件分发到最终响应的完整链路。本文将系统性地拆解iOS事件处理机制的每个环节。&lt;/p&gt;
&lt;h2 id="一响应者与响应者链"&gt;一、响应者与响应者链&lt;/h2&gt;
&lt;p&gt;理解事件处理的前提是理解&amp;quot;谁有能力处理事件&amp;quot;。在iOS中，这个问题的答案是 &lt;strong&gt;响应者（Responder）&lt;/strong&gt;。&lt;/p&gt;
&lt;h3 id="11-uiresponder"&gt;1.1 UIResponder&lt;/h3&gt;
&lt;p&gt;所有能够接收并处理事件的对象都继承自 &lt;code&gt;UIResponder&lt;/code&gt;：&lt;/p&gt;
&lt;pre class="mermaid"&gt;classDiagram
NSObject &lt;|-- UIResponder
UIResponder &lt;|-- UIView
UIResponder &lt;|-- UIViewController
UIResponder &lt;|-- UIApplication
UIView &lt;|-- UIWindow
UIView &lt;|-- UIControl
UIView &lt;|-- UIScrollView
UIControl &lt;|-- UIButton
UIControl &lt;|-- UISlider
UIScrollView &lt;|-- UITableView
class UIResponder {
+nextResponder: UIResponder?
+touchesBegan(touches, event)
+touchesMoved(touches, event)
+touchesEnded(touches, event)
+touchesCancelled(touches, event)
}
&lt;/pre&gt;
&lt;p&gt;&lt;code&gt;UIResponder&lt;/code&gt; 定义了处理触摸事件的四个核心方法：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-objc" data-lang="objc"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;- (&lt;span style="color:#66d9ef"&gt;void&lt;/span&gt;)&lt;span style="color:#a6e22e"&gt;touchesBegan:&lt;/span&gt;(NSSet&lt;span style="color:#f92672"&gt;&amp;lt;&lt;/span&gt;UITouch &lt;span style="color:#f92672"&gt;*&amp;gt;&lt;/span&gt; &lt;span style="color:#f92672"&gt;*&lt;/span&gt;)touches &lt;span style="color:#a6e22e"&gt;withEvent:&lt;/span&gt;(UIEvent &lt;span style="color:#f92672"&gt;*&lt;/span&gt;)event;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;- (&lt;span style="color:#66d9ef"&gt;void&lt;/span&gt;)&lt;span style="color:#a6e22e"&gt;touchesMoved:&lt;/span&gt;(NSSet&lt;span style="color:#f92672"&gt;&amp;lt;&lt;/span&gt;UITouch &lt;span style="color:#f92672"&gt;*&amp;gt;&lt;/span&gt; &lt;span style="color:#f92672"&gt;*&lt;/span&gt;)touches &lt;span style="color:#a6e22e"&gt;withEvent:&lt;/span&gt;(UIEvent &lt;span style="color:#f92672"&gt;*&lt;/span&gt;)event;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;- (&lt;span style="color:#66d9ef"&gt;void&lt;/span&gt;)&lt;span style="color:#a6e22e"&gt;touchesEnded:&lt;/span&gt;(NSSet&lt;span style="color:#f92672"&gt;&amp;lt;&lt;/span&gt;UITouch &lt;span style="color:#f92672"&gt;*&amp;gt;&lt;/span&gt; &lt;span style="color:#f92672"&gt;*&lt;/span&gt;)touches &lt;span style="color:#a6e22e"&gt;withEvent:&lt;/span&gt;(UIEvent &lt;span style="color:#f92672"&gt;*&lt;/span&gt;)event;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;- (&lt;span style="color:#66d9ef"&gt;void&lt;/span&gt;)&lt;span style="color:#a6e22e"&gt;touchesCancelled:&lt;/span&gt;(NSSet&lt;span style="color:#f92672"&gt;&amp;lt;&lt;/span&gt;UITouch &lt;span style="color:#f92672"&gt;*&amp;gt;&lt;/span&gt; &lt;span style="color:#f92672"&gt;*&lt;/span&gt;)touches &lt;span style="color:#a6e22e"&gt;withEvent:&lt;/span&gt;(UIEvent &lt;span style="color:#f92672"&gt;*&lt;/span&gt;)event;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h3 id="12-nextresponder与响应者链"&gt;1.2 nextResponder与响应者链&lt;/h3&gt;
&lt;p&gt;每个 &lt;code&gt;UIResponder&lt;/code&gt; 都有一个 &lt;code&gt;nextResponder&lt;/code&gt; 属性，指向&amp;quot;下一个响应者&amp;quot;。所有响应者通过这个属性串联成一条 &lt;strong&gt;响应者链（Responder Chain）&lt;/strong&gt;。&lt;/p&gt;</description></item><item><title>卡顿-原理</title><link>https://amatsuzero.github.io/LastStand/posts/interview/ios-performance/stutter-%E5%8E%9F%E7%90%86/</link><pubDate>Sat, 02 May 2026 22:32:27 +0800</pubDate><guid>https://amatsuzero.github.io/LastStand/posts/interview/ios-performance/stutter-%E5%8E%9F%E7%90%86/</guid><description>&lt;p&gt;理解卡顿的原理是优化的基础。本文从屏幕显示的底层机制出发，沿着&amp;quot;VSync信号 -&amp;gt; 渲染管线 -&amp;gt; RunLoop协作 -&amp;gt; 掉帧产生&amp;quot;的逻辑链条，逐步揭示卡顿产生的根本原因。&lt;/p&gt;
&lt;h2 id="屏幕显示的基础vsync与缓冲机制"&gt;屏幕显示的基础：VSync与缓冲机制&lt;/h2&gt;
&lt;p&gt;要理解卡顿，首先要理解屏幕是如何显示画面的。&lt;/p&gt;
&lt;h3 id="vsync信号"&gt;VSync信号&lt;/h3&gt;
&lt;p&gt;VSync（Vertical Synchronization，垂直同步）是显示器发出的信号，用于协调GPU渲染和屏幕显示的时机。在60Hz的屏幕上，每16.67ms发出一次VSync信号。当信号到来时，屏幕从帧缓冲区读取数据进行显示。&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-plaintext" data-lang="plaintext"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;时间轴：
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;│←── 16.67ms ──→│←── 16.67ms ──→│←── 16.67ms ──→│
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; ↑ ↑ ↑
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; VSync 1 VSync 2 VSync 3
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; │ │ │
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; 显示帧1 显示帧2 显示帧3
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h3 id="双缓冲与三缓冲"&gt;双缓冲与三缓冲&lt;/h3&gt;
&lt;p&gt;为了避免画面撕裂（GPU写入和屏幕读取同一块内存导致），iOS使用多缓冲机制：&lt;/p&gt;
&lt;pre class="mermaid"&gt;flowchart LR
subgraph 双缓冲机制
direction TB
GPU["GPU"] --&gt;|渲染到| BB["后缓冲区（Back Buffer）"]
BB &lt;--&gt;|VSync时交换| FB["前缓冲区（Frame Buffer）"]
FB --&gt;|读取显示| Display["显示器"]
end
&lt;/pre&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;双缓冲（默认）&lt;/strong&gt;：GPU渲染到后缓冲区，VSync到来时交换前后缓冲区，显示器从前缓冲区读取。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;三缓冲（高负载时自动启用）&lt;/strong&gt;：增加第三个缓冲区，当渲染无法在一个VSync周期内完成时，GPU可以在额外缓冲区继续渲染，不必等待交换完成。代价是增加一帧延迟和内存占用。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;系统在两者之间动态切换，开发者无需手动干预。&lt;/p&gt;
&lt;h3 id="promotion自适应刷新率"&gt;ProMotion自适应刷新率&lt;/h3&gt;
&lt;p&gt;ProMotion设备（iPhone 13 Pro及以上）支持10Hz-120Hz的自适应刷新率，这意味着帧时间预算不再固定：&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;刷新率&lt;/th&gt;
&lt;th&gt;帧时间&lt;/th&gt;
&lt;th&gt;卡顿阈值建议&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;120Hz&lt;/td&gt;
&lt;td&gt;8.33ms&lt;/td&gt;
&lt;td&gt;&amp;gt;16ms视为掉帧&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;60Hz&lt;/td&gt;
&lt;td&gt;16.67ms&lt;/td&gt;
&lt;td&gt;&amp;gt;33ms视为掉帧&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;30Hz&lt;/td&gt;
&lt;td&gt;33.33ms&lt;/td&gt;
&lt;td&gt;&amp;gt;66ms视为掉帧&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-swift" data-lang="swift"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;// 检查设备最大刷新率&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;let&lt;/span&gt; maxFrameRate = UIScreen.main.maximumFramesPerSecond
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;// CADisplayLink适配ProMotion&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;if&lt;/span&gt; &lt;span style="color:#75715e"&gt;#available&lt;/span&gt;(&lt;span style="color:#75715e"&gt;iOS&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;15.0&lt;/span&gt;, &lt;span style="color:#f92672"&gt;*&lt;/span&gt;) {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; displayLink?.preferredFrameRateRange = CAFrameRateRange(
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; minimum: &lt;span style="color:#ae81ff"&gt;60&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; maximum: &lt;span style="color:#ae81ff"&gt;120&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; preferred: &lt;span style="color:#ae81ff"&gt;120&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; )
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h2 id="ios渲染架构"&gt;iOS渲染架构&lt;/h2&gt;
&lt;p&gt;了解了屏幕显示机制后，接下来看iOS是如何将UI元素最终变成屏幕上的像素的。&lt;/p&gt;</description></item><item><title>iOS多线程编程</title><link>https://amatsuzero.github.io/LastStand/posts/interview/ios-basics/%E5%A4%9A%E7%BA%BF%E7%A8%8B/</link><pubDate>Sat, 02 May 2026 22:32:27 +0800</pubDate><guid>https://amatsuzero.github.io/LastStand/posts/interview/ios-basics/%E5%A4%9A%E7%BA%BF%E7%A8%8B/</guid><description>&lt;p&gt;iOS多线程方案对比&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;方案&lt;/th&gt;
&lt;th&gt;简介&lt;/th&gt;
&lt;th&gt;语言&lt;/th&gt;
&lt;th&gt;生命周期管理&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;pthread&lt;/td&gt;
&lt;td&gt;POSIX标准的多线程API&lt;/td&gt;
&lt;td&gt;C&lt;/td&gt;
&lt;td&gt;手动管理&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;NSThread&lt;/td&gt;
&lt;td&gt;面向对象的线程封装&lt;/td&gt;
&lt;td&gt;OC/Swift&lt;/td&gt;
&lt;td&gt;手动管理&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;GCD&lt;/td&gt;
&lt;td&gt;Grand Central Dispatch&lt;/td&gt;
&lt;td&gt;C/OC/Swift&lt;/td&gt;
&lt;td&gt;自动管理&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;NSOperation&lt;/td&gt;
&lt;td&gt;基于GCD的面向对象封装&lt;/td&gt;
&lt;td&gt;OC/Swift&lt;/td&gt;
&lt;td&gt;自动管理&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;h2 id="pthread"&gt;pthread&lt;/h2&gt;
&lt;p&gt;pthread是POSIX标准的多线程API，是最底层的多线程方案，使用C语言编写。&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-c" data-lang="c"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;#import &amp;lt;pthread.h&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;void&lt;/span&gt; &lt;span style="color:#f92672"&gt;*&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;threadFunction&lt;/span&gt;(&lt;span style="color:#66d9ef"&gt;void&lt;/span&gt; &lt;span style="color:#f92672"&gt;*&lt;/span&gt;param) {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;NSLog&lt;/span&gt;(&lt;span style="color:#960050;background-color:#1e0010"&gt;@&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#34;pthread执行任务: %@&amp;#34;&lt;/span&gt;, [NSThread currentThread]);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;return&lt;/span&gt; NULL;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;-&lt;/span&gt; (&lt;span style="color:#66d9ef"&gt;void&lt;/span&gt;)createPthread {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;pthread_t&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;thread&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;pthread_create&lt;/span&gt;(&lt;span style="color:#f92672"&gt;&amp;amp;&lt;/span&gt;&lt;span style="color:#66d9ef"&gt;thread&lt;/span&gt;, NULL, threadFunction, NULL);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;&lt;strong&gt;特点&lt;/strong&gt;：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;跨平台，可移植性强&lt;/li&gt;
&lt;li&gt;使用复杂，需要手动管理线程生命周期&lt;/li&gt;
&lt;li&gt;实际开发中很少直接使用&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="nsthread"&gt;NSThread&lt;/h2&gt;
&lt;p&gt;NSThread是苹果对pthread的面向对象封装，使用更加简单。&lt;/p&gt;
&lt;h3 id="创建线程的方式"&gt;创建线程的方式&lt;/h3&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-objc" data-lang="objc"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;// 方式1：实例方法创建，需要手动启动
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;NSThread &lt;span style="color:#f92672"&gt;*&lt;/span&gt;&lt;span style="color:#66d9ef"&gt;thread&lt;/span&gt; &lt;span style="color:#f92672"&gt;=&lt;/span&gt; [[NSThread alloc] initWithTarget:self
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; selector:&lt;span style="color:#66d9ef"&gt;@selector&lt;/span&gt;(doTask)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; object:nil];
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;thread&lt;/span&gt;.name &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#e6db74"&gt;@&amp;#34;MyThread&amp;#34;&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;[&lt;span style="color:#66d9ef"&gt;thread&lt;/span&gt; start];
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;// 方式2：类方法创建，自动启动
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;[NSThread detachNewThreadSelector:&lt;span style="color:#66d9ef"&gt;@selector&lt;/span&gt;(doTask)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; toTarget:self
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; withObject:nil];
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;// 方式3：隐式创建
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;[self performSelectorInBackground:&lt;span style="color:#66d9ef"&gt;@selector&lt;/span&gt;(doTask) withObject:nil];
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h3 id="常用方法"&gt;常用方法&lt;/h3&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-objc" data-lang="objc"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;// 获取当前线程
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;NSThread &lt;span style="color:#f92672"&gt;*&lt;/span&gt;currentThread &lt;span style="color:#f92672"&gt;=&lt;/span&gt; [NSThread currentThread];
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;// 获取主线程
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;NSThread &lt;span style="color:#f92672"&gt;*&lt;/span&gt;mainThread &lt;span style="color:#f92672"&gt;=&lt;/span&gt; [NSThread mainThread];
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;// 判断是否是主线程
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;BOOL&lt;/span&gt; isMain &lt;span style="color:#f92672"&gt;=&lt;/span&gt; [NSThread isMainThread];
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;// 线程休眠
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;[NSThread sleepForTimeInterval:&lt;span style="color:#ae81ff"&gt;2.0&lt;/span&gt;];
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;[NSThread sleepUntilDate:[NSDate dateWithTimeIntervalSinceNow:&lt;span style="color:#ae81ff"&gt;2.0&lt;/span&gt;]];
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;// 退出当前线程
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;[NSThread exit];
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h3 id="线程间通信"&gt;线程间通信&lt;/h3&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-objc" data-lang="objc"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;// 回到主线程执行
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;[self performSelectorOnMainThread:&lt;span style="color:#66d9ef"&gt;@selector&lt;/span&gt;(updateUI)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; withObject:nil
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; waitUntilDone:NO];
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;// 在指定线程执行
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;[self performSelector:&lt;span style="color:#66d9ef"&gt;@selector&lt;/span&gt;(doTask)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; onThread:&lt;span style="color:#66d9ef"&gt;thread&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; withObject:nil
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; waitUntilDone:NO];
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h2 id="gcdgrand-central-dispatch"&gt;GCD（Grand Central Dispatch）&lt;/h2&gt;
&lt;p&gt;GCD是苹果推出的多线程解决方案，基于C语言实现，自动管理线程的生命周期。GCD的核心概念是 &lt;strong&gt;队列（Queue）&lt;/strong&gt; 和&lt;strong&gt;任务（Task）&lt;/strong&gt;。&lt;/p&gt;</description></item><item><title>卡顿-图片优化</title><link>https://amatsuzero.github.io/LastStand/posts/interview/ios-performance/stutter-%E5%9B%BE%E7%89%87%E4%BC%98%E5%8C%96/</link><pubDate>Sat, 02 May 2026 22:32:27 +0800</pubDate><guid>https://amatsuzero.github.io/LastStand/posts/interview/ios-performance/stutter-%E5%9B%BE%E7%89%87%E4%BC%98%E5%8C%96/</guid><description>&lt;p&gt;图片处理是iOS应用中常见的性能瓶颈。本文介绍图片解码原理以及各种优化方案。&lt;/p&gt;
&lt;hr&gt;
&lt;h2 id="图片解码原理"&gt;图片解码原理&lt;/h2&gt;
&lt;h3 id="为什么需要解码"&gt;为什么需要解码&lt;/h3&gt;
&lt;p&gt;图片文件（PNG、JPEG等）是压缩格式，无法直接显示。GPU需要的是位图（Bitmap）格式：&lt;/p&gt;
&lt;pre class="mermaid"&gt;flowchart LR
A[压缩图片&lt;br/&gt;PNG/JPEG] --&gt; B[解码&lt;br/&gt;Decode&lt;br/&gt;CPU密集操作]
B --&gt; C[位图&lt;br/&gt;Bitmap&lt;br/&gt;GPU可直接使用]
&lt;/pre&gt;
&lt;blockquote&gt;
&lt;p&gt;位图大小 = 宽度 × 高度 × 每像素字节数
例如：1000×1000 RGBA图片 = 1000 × 1000 × 4 = 4MB&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h3 id="默认解码时机"&gt;默认解码时机&lt;/h3&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-swift" data-lang="swift"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;// 加载图片（此时未解码）&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;let&lt;/span&gt; image = UIImage(named: &lt;span style="color:#e6db74"&gt;&amp;#34;large_image&amp;#34;&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;// 设置到ImageView（仍未解码）&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;imageView.image = image
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;// 在 CATransaction commit 的 prepare 阶段，Core Animation 会在主线程对未解码的图片执行解码&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;// 未提前解码的图片一定会在此阶段被解码，从而阻塞主线程引发卡顿&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;hr&gt;
&lt;h2 id="异步解码"&gt;异步解码&lt;/h2&gt;
&lt;h3 id="基本原理"&gt;基本原理&lt;/h3&gt;
&lt;p&gt;将解码工作移到后台线程：&lt;/p&gt;
&lt;pre class="mermaid"&gt;sequenceDiagram
participant M as 主线程
participant B as 后台线程
M-&gt;&gt;B: 请求加载图片
Note over M: 继续处理其他事件
B-&gt;&gt;B: 加载压缩数据
B-&gt;&gt;B: 解码为位图
B-&gt;&gt;B: 创建CGImage
B-&gt;&gt;M: 返回解码后的图片
M-&gt;&gt;M: 更新UI
&lt;/pre&gt;
&lt;h3 id="实现方案1强制解码"&gt;实现方案1：强制解码&lt;/h3&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-swift" data-lang="swift"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;extension&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;UIImage&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#75715e"&gt;/// 强制解码图片&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;func&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;decodedImage&lt;/span&gt;() -&amp;gt; UIImage? {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;guard&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;let&lt;/span&gt; cgImage = &lt;span style="color:#66d9ef"&gt;self&lt;/span&gt;.cgImage &lt;span style="color:#66d9ef"&gt;else&lt;/span&gt; { &lt;span style="color:#66d9ef"&gt;return&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;nil&lt;/span&gt; }
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;let&lt;/span&gt; width = cgImage.width
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;let&lt;/span&gt; height = cgImage.height
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#75715e"&gt;// 创建位图上下文&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;let&lt;/span&gt; colorSpace = CGColorSpaceCreateDeviceRGB()
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;let&lt;/span&gt; bitmapInfo = CGBitmapInfo(rawValue: CGImageAlphaInfo.premultipliedFirst.rawValue &lt;span style="color:#f92672"&gt;|&lt;/span&gt; CGBitmapInfo.byteOrder32Little.rawValue)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;guard&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;let&lt;/span&gt; context = CGContext(
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; data: &lt;span style="color:#66d9ef"&gt;nil&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; width: width,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; height: height,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; bitsPerComponent: &lt;span style="color:#ae81ff"&gt;8&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; bytesPerRow: &lt;span style="color:#ae81ff"&gt;0&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; space: colorSpace,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; bitmapInfo: bitmapInfo.rawValue
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; ) &lt;span style="color:#66d9ef"&gt;else&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;return&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;nil&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; }
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#75715e"&gt;// 绘制到上下文（触发解码）&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; context.draw(cgImage, &lt;span style="color:#66d9ef"&gt;in&lt;/span&gt;: CGRect(x: &lt;span style="color:#ae81ff"&gt;0&lt;/span&gt;, y: &lt;span style="color:#ae81ff"&gt;0&lt;/span&gt;, width: width, height: height))
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#75715e"&gt;// 从上下文创建新图片&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;guard&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;let&lt;/span&gt; decodedCGImage = context.makeImage() &lt;span style="color:#66d9ef"&gt;else&lt;/span&gt; { &lt;span style="color:#66d9ef"&gt;return&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;nil&lt;/span&gt; }
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;return&lt;/span&gt; UIImage(cgImage: decodedCGImage, scale: scale, orientation: imageOrientation)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; }
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;// 异步使用&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;func&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;loadImageAsync&lt;/span&gt;(named name: String, completion: @escaping (UIImage?) -&amp;gt; Void) {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; DispatchQueue.global(qos: .userInitiated).async {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;let&lt;/span&gt; image = UIImage(named: name)?.decodedImage()
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; DispatchQueue.main.async {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; completion(image)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; }
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; }
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h3 id="实现方案2使用imageio"&gt;实现方案2：使用ImageIO&lt;/h3&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-swift" data-lang="swift"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;import&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;ImageIO&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;class&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;ImageDecoder&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;static&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;func&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;decodeImage&lt;/span&gt;(from url: URL) -&amp;gt; UIImage? {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;guard&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;let&lt;/span&gt; source = CGImageSourceCreateWithURL(url &lt;span style="color:#66d9ef"&gt;as&lt;/span&gt; CFURL, &lt;span style="color:#66d9ef"&gt;nil&lt;/span&gt;) &lt;span style="color:#66d9ef"&gt;else&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;return&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;nil&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; }
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;let&lt;/span&gt; options: [CFString: Any] = [
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; kCGImageSourceShouldCache: &lt;span style="color:#66d9ef"&gt;true&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; kCGImageSourceShouldCacheImmediately: &lt;span style="color:#66d9ef"&gt;true&lt;/span&gt; &lt;span style="color:#75715e"&gt;// 立即解码&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; ]
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;guard&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;let&lt;/span&gt; cgImage = CGImageSourceCreateImageAtIndex(source, &lt;span style="color:#ae81ff"&gt;0&lt;/span&gt;, options &lt;span style="color:#66d9ef"&gt;as&lt;/span&gt; CFDictionary) &lt;span style="color:#66d9ef"&gt;else&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;return&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;nil&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; }
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;return&lt;/span&gt; UIImage(cgImage: cgImage)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; }
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;static&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;func&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;decodeImageAsync&lt;/span&gt;(from url: URL, completion: @escaping (UIImage?) -&amp;gt; Void) {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; DispatchQueue.global(qos: .userInitiated).async {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;let&lt;/span&gt; image = ImageDecoder.decodeImage(from: url)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; DispatchQueue.main.async {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; completion(image)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; }
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; }
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; }
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h3 id="实现方案3使用uigraphicsimagerenderer"&gt;实现方案3：使用UIGraphicsImageRenderer&lt;/h3&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-swift" data-lang="swift"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;extension&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;UIImage&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;func&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;decodedImageUsingRenderer&lt;/span&gt;() -&amp;gt; UIImage {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;let&lt;/span&gt; format = UIGraphicsImageRendererFormat()
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; format.scale = scale
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; format.opaque = &lt;span style="color:#66d9ef"&gt;true&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; format.preferredRange = .standard
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;let&lt;/span&gt; renderer = UIGraphicsImageRenderer(size: size, format: format)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;return&lt;/span&gt; renderer.image { context &lt;span style="color:#66d9ef"&gt;in&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; draw(at: .zero)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; }
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; }
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;hr&gt;
&lt;h2 id="图片降采样"&gt;图片降采样&lt;/h2&gt;
&lt;h3 id="为什么需要降采样"&gt;为什么需要降采样&lt;/h3&gt;
&lt;p&gt;当图片尺寸远大于显示尺寸时，加载原图是浪费：&lt;/p&gt;</description></item><item><title>卡顿-检测</title><link>https://amatsuzero.github.io/LastStand/posts/interview/ios-performance/stutter-%E6%A3%80%E6%B5%8B/</link><pubDate>Thu, 07 May 2026 16:54:12 +0800</pubDate><guid>https://amatsuzero.github.io/LastStand/posts/interview/ios-performance/stutter-%E6%A3%80%E6%B5%8B/</guid><description>&lt;p&gt;准确检测卡顿是优化的前提。本文介绍多种卡顿检测方案，从开发调试到线上监控都有对应的方案。&lt;/p&gt;
&lt;hr&gt;
&lt;h2 id="检测方案概览"&gt;检测方案概览&lt;/h2&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;方案&lt;/th&gt;
&lt;th&gt;原理&lt;/th&gt;
&lt;th&gt;优点&lt;/th&gt;
&lt;th&gt;缺点&lt;/th&gt;
&lt;th&gt;适用场景&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;CADisplayLink&lt;/td&gt;
&lt;td&gt;监控帧节奏、FPS、慢帧/掉帧&lt;/td&gt;
&lt;td&gt;简单直接、适合趋势观察&lt;/td&gt;
&lt;td&gt;无法直接给出堆栈，FPS 只能辅助判断&lt;/td&gt;
&lt;td&gt;开发调试/线上辅助指标&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;RunLoop Observer&lt;/td&gt;
&lt;td&gt;监控RunLoop状态&lt;/td&gt;
&lt;td&gt;可获取堆栈&lt;/td&gt;
&lt;td&gt;有一定开销&lt;/td&gt;
&lt;td&gt;开发/线上&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;子线程Ping&lt;/td&gt;
&lt;td&gt;定时检测主线程响应&lt;/td&gt;
&lt;td&gt;实现简单&lt;/td&gt;
&lt;td&gt;精度有限&lt;/td&gt;
&lt;td&gt;线上监控&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Instruments&lt;/td&gt;
&lt;td&gt;系统级分析&lt;/td&gt;
&lt;td&gt;信息详细&lt;/td&gt;
&lt;td&gt;只能开发时用&lt;/td&gt;
&lt;td&gt;性能分析&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;MetricKit&lt;/td&gt;
&lt;td&gt;系统数据收集&lt;/td&gt;
&lt;td&gt;无额外开销&lt;/td&gt;
&lt;td&gt;iOS 13+&lt;/td&gt;
&lt;td&gt;线上监控&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Sentry ANR V2&lt;/td&gt;
&lt;td&gt;帧延迟分析&lt;/td&gt;
&lt;td&gt;区分阻塞类型&lt;/td&gt;
&lt;td&gt;需集成SDK&lt;/td&gt;
&lt;td&gt;线上监控&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;hr&gt;
&lt;h2 id="1-cadisplaylink监控"&gt;1. CADisplayLink监控&lt;/h2&gt;
&lt;h3 id="基本原理"&gt;基本原理&lt;/h3&gt;
&lt;p&gt;CADisplayLink 是一个和屏幕显示刷新节奏同步的回调。它适合回答“当前 UI 刷新是否顺畅、是否出现慢帧、掉帧或冻结帧”，但 &lt;strong&gt;FPS 本身只是辅助参考&lt;/strong&gt;，不能单独作为卡顿结论。&lt;/p&gt;
&lt;p&gt;原因是：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;FPS 只描述结果，不描述原因&lt;/strong&gt;：FPS 下降只能说明某段时间显示帧变少了，不能告诉你是主线程计算、布局、图片解码、锁等待、I/O、GPU 渲染还是系统主动降刷新率导致的。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;ProMotion 会动态调整刷新率&lt;/strong&gt;：在支持 120Hz 的机型上，系统可能根据内容和功耗策略把刷新率降到 10Hz、24Hz、30Hz、60Hz、80Hz、120Hz 等。静止页面低 FPS 可能只是系统主动省电，不是卡顿。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;主线程阻塞会让回调延迟&lt;/strong&gt;：如果主线程真的被阻塞，CADisplayLink 回调本身也会延后，此时需要结合实际回调间隔、RunLoop 状态和堆栈采样判断。&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;因此线上卡顿监控更推荐记录 &lt;strong&gt;帧间隔 / 慢帧 / 冻结帧 / 交互场景&lt;/strong&gt;，而不是只显示一个“当前 FPS”。&lt;/p&gt;</description></item><item><title>布局方法详解</title><link>https://amatsuzero.github.io/LastStand/posts/interview/ios-basics/%E5%B8%83%E5%B1%80%E6%96%B9%E6%B3%95%E8%AF%A6%E8%A7%A3/</link><pubDate>Sat, 02 May 2026 22:32:27 +0800</pubDate><guid>https://amatsuzero.github.io/LastStand/posts/interview/ios-basics/%E5%B8%83%E5%B1%80%E6%96%B9%E6%B3%95%E8%AF%A6%E8%A7%A3/</guid><description>&lt;p&gt;本文详细介绍 iOS 中三种布局方式（Frame、Auto Layout、UIStackView）的原理和对比，视图更新的三个阶段（约束、布局、绘制），UIView 与 CALayer 的关系和区别，以及 &lt;code&gt;updateConstraints&lt;/code&gt;、&lt;code&gt;layoutSubviews&lt;/code&gt;、&lt;code&gt;setNeedsLayout&lt;/code&gt;、&lt;code&gt;layoutIfNeeded&lt;/code&gt;、&lt;code&gt;setNeedsDisplay&lt;/code&gt; 等相关方法的作用、调用时机和区别。&lt;/p&gt;
&lt;h2 id="ios-布局方式"&gt;iOS 布局方式&lt;/h2&gt;
&lt;p&gt;iOS 提供了三种主要的布局方式，按出现时间排列：&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;布局方式&lt;/th&gt;
&lt;th&gt;引入版本&lt;/th&gt;
&lt;th&gt;核心思想&lt;/th&gt;
&lt;th&gt;API&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Frame 布局&lt;/td&gt;
&lt;td&gt;iOS 2&lt;/td&gt;
&lt;td&gt;直接指定视图的位置和大小&lt;/td&gt;
&lt;td&gt;frame、bounds、center&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Auto Layout&lt;/td&gt;
&lt;td&gt;iOS 6&lt;/td&gt;
&lt;td&gt;通过约束描述视图间关系，系统自动计算 frame&lt;/td&gt;
&lt;td&gt;NSLayoutConstraint、Anchor API&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;UIStackView&lt;/td&gt;
&lt;td&gt;iOS 9&lt;/td&gt;
&lt;td&gt;线性排列子视图，自动管理约束&lt;/td&gt;
&lt;td&gt;UIStackView&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;h3 id="frame-布局"&gt;Frame 布局&lt;/h3&gt;
&lt;p&gt;直接通过设置 &lt;code&gt;frame&lt;/code&gt; 属性来确定视图的位置和大小，是最基础的布局方式。&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-swift" data-lang="swift"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;let&lt;/span&gt; label = UILabel()
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;label.frame = CGRect(x: &lt;span style="color:#ae81ff"&gt;20&lt;/span&gt;, y: &lt;span style="color:#ae81ff"&gt;100&lt;/span&gt;, width: &lt;span style="color:#ae81ff"&gt;200&lt;/span&gt;, height: &lt;span style="color:#ae81ff"&gt;44&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;view.addSubview(label)
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;&lt;strong&gt;优点&lt;/strong&gt;：性能最好（无需约束求解），逻辑直观，完全可控。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;缺点&lt;/strong&gt;：需要手动计算所有数值，难以适配不同屏幕尺寸和动态内容，维护成本高。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;适用场景&lt;/strong&gt;：简单固定布局、性能敏感的场景（如 &lt;code&gt;UITableViewCell&lt;/code&gt; 内大量视图手动布局）、需要频繁更新 frame 的动画。&lt;/p&gt;
&lt;h3 id="auto-layout"&gt;Auto Layout&lt;/h3&gt;
&lt;p&gt;Auto Layout 是基于 &lt;strong&gt;约束（Constraint）&lt;/strong&gt; 的布局系统。开发者不直接设置 frame，而是描述视图之间的关系（如&amp;quot;A 的左边距 B 右边 16pt&amp;quot;），系统通过求解约束方程组自动计算出每个视图的 frame。&lt;/p&gt;</description></item><item><title>iOS中的生命周期</title><link>https://amatsuzero.github.io/LastStand/posts/interview/ios-basics/%E7%94%9F%E5%91%BD%E5%91%A8%E6%9C%9F/</link><pubDate>Tue, 05 May 2026 00:41:41 +0800</pubDate><guid>https://amatsuzero.github.io/LastStand/posts/interview/ios-basics/%E7%94%9F%E5%91%BD%E5%91%A8%E6%9C%9F/</guid><description>&lt;p&gt;iOS开发中，理解各种生命周期是非常重要的基础知识。本文将详细介绍应用生命周期、UIViewController生命周期、UIView生命周期，以及其他常见的生命周期。&lt;/p&gt;
&lt;h2 id="应用生命周期app-lifecycle"&gt;应用生命周期（App Lifecycle）&lt;/h2&gt;
&lt;h3 id="应用状态"&gt;应用状态&lt;/h3&gt;
&lt;p&gt;iOS应用有五种运行状态：&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;状态&lt;/th&gt;
&lt;th&gt;描述&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Not Running&lt;/td&gt;
&lt;td&gt;应用未启动或已被系统终止&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Inactive&lt;/td&gt;
&lt;td&gt;应用在前台运行但未接收事件（如来电、锁屏时的过渡状态）&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Active&lt;/td&gt;
&lt;td&gt;应用在前台运行并接收事件，这是应用的正常运行状态&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Background&lt;/td&gt;
&lt;td&gt;应用在后台执行代码，通常只有短暂的执行时间&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Suspended&lt;/td&gt;
&lt;td&gt;应用在后台但不执行代码，系统会在内存不足时自动终止该状态的应用&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;h3 id="状态转换图"&gt;状态转换图&lt;/h3&gt;
&lt;pre class="mermaid"&gt;stateDiagram-v2
[*] --&gt; Not_Running
Not_Running --&gt; Inactive : 启动
Inactive --&gt; Active
Active --&gt; Background
Background --&gt; Inactive
Background --&gt; Suspended
Suspended --&gt; [*]
&lt;/pre&gt;
&lt;h3 id="uiapplicationdelegate-方法ios-12及之前"&gt;UIApplicationDelegate 方法（iOS 12及之前）&lt;/h3&gt;
&lt;p&gt;在iOS 12及之前的版本中，应用生命周期主要通过&lt;code&gt;UIApplicationDelegate&lt;/code&gt;协议来管理：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-swift" data-lang="swift"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;// 应用启动完成&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;func&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;application&lt;/span&gt;(&lt;span style="color:#66d9ef"&gt;_&lt;/span&gt; application: UIApplication,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -&amp;gt; Bool {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#75715e"&gt;// 初始化配置、第三方SDK等&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;return&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;true&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;// 应用即将进入非活动状态&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;func&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;applicationWillResignActive&lt;/span&gt;(&lt;span style="color:#66d9ef"&gt;_&lt;/span&gt; application: UIApplication) {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#75715e"&gt;// 暂停正在进行的任务、禁用定时器&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#75715e"&gt;// 游戏应该在此暂停&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;// 应用已进入后台&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;func&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;applicationDidEnterBackground&lt;/span&gt;(&lt;span style="color:#66d9ef"&gt;_&lt;/span&gt; application: UIApplication) {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#75715e"&gt;// 释放共享资源、保存用户数据&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#75715e"&gt;// 可以请求额外的后台执行时间&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;// 应用即将进入前台&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;func&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;applicationWillEnterForeground&lt;/span&gt;(&lt;span style="color:#66d9ef"&gt;_&lt;/span&gt; application: UIApplication) {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#75715e"&gt;// 撤销进入后台时所做的更改&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;// 应用已变为活动状态&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;func&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;applicationDidBecomeActive&lt;/span&gt;(&lt;span style="color:#66d9ef"&gt;_&lt;/span&gt; application: UIApplication) {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#75715e"&gt;// 重启被暂停的任务&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#75715e"&gt;// 如果应用之前在后台，可以刷新UI&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;// 应用即将终止&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;func&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;applicationWillTerminate&lt;/span&gt;(&lt;span style="color:#66d9ef"&gt;_&lt;/span&gt; application: UIApplication) {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#75715e"&gt;// 保存数据、清理资源&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#75715e"&gt;// 注意：如果应用从Suspended状态被终止，此方法不会被调用&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h3 id="uiscenedelegate-方法ios-13"&gt;UISceneDelegate 方法（iOS 13+）&lt;/h3&gt;
&lt;p&gt;从iOS 13开始，Apple引入了Scene-based生命周期，支持多窗口场景。&lt;/p&gt;</description></item><item><title>卡顿-离屏渲染</title><link>https://amatsuzero.github.io/LastStand/posts/interview/ios-performance/stutter-%E7%A6%BB%E5%B1%8F%E6%B8%B2%E6%9F%93/</link><pubDate>Sat, 02 May 2026 22:32:27 +0800</pubDate><guid>https://amatsuzero.github.io/LastStand/posts/interview/ios-performance/stutter-%E7%A6%BB%E5%B1%8F%E6%B8%B2%E6%9F%93/</guid><description>&lt;p&gt;离屏渲染（Offscreen Rendering）是GPU渲染中的性能杀手。本文介绍离屏渲染的原理、触发条件以及优化方案。&lt;/p&gt;
&lt;hr&gt;
&lt;h2 id="什么是离屏渲染"&gt;什么是离屏渲染&lt;/h2&gt;
&lt;h3 id="正常渲染流程"&gt;正常渲染流程&lt;/h3&gt;
&lt;p&gt;正常情况下，GPU直接将渲染结果写入帧缓冲区（Frame Buffer）：&lt;/p&gt;
&lt;pre class="mermaid"&gt;flowchart LR
subgraph 正常渲染["正常渲染 On-Screen Rendering"]
A[GPU&lt;br/&gt;渲染] --&gt; B[Frame Buffer&lt;br/&gt;帧缓冲区] --&gt; C[屏幕&lt;br/&gt;显示]
end
style A fill:#e1f5fe
style B fill:#fff3e0
style C fill:#e8f5e9
&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;特点：&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;直接渲染到帧缓冲区&lt;/li&gt;
&lt;li&gt;渲染完成即可显示&lt;/li&gt;
&lt;li&gt;效率最高&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id="离屏渲染流程"&gt;离屏渲染流程&lt;/h3&gt;
&lt;p&gt;离屏渲染需要先渲染到离屏缓冲区，再合成到帧缓冲区：&lt;/p&gt;
&lt;pre class="mermaid"&gt;flowchart LR
subgraph 离屏渲染["离屏渲染 Offscreen Rendering"]
A[GPU&lt;br/&gt;渲染] --&gt; B[Offscreen Buffer&lt;br/&gt;离屏缓冲区]
B --&gt; C[Frame Buffer&lt;br/&gt;帧缓冲区]
C --&gt; D[屏幕&lt;br/&gt;显示]
end
E[额外的缓冲区] -.-&gt; B
style A fill:#e1f5fe
style B fill:#f48fb1
style C fill:#fff3e0
style D fill:#e8f5e9
style E fill:#f48fb1,stroke:#f44336,stroke-dasharray: 5 5
&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;性能开销：&lt;/strong&gt;&lt;/p&gt;</description></item><item><title>卡顿</title><link>https://amatsuzero.github.io/LastStand/posts/interview/ios-performance/stutter-%E5%8D%A1%E9%A1%BF/</link><pubDate>Sat, 02 May 2026 22:32:27 +0800</pubDate><guid>https://amatsuzero.github.io/LastStand/posts/interview/ios-performance/stutter-%E5%8D%A1%E9%A1%BF/</guid><description>&lt;p&gt;卡顿是影响用户体验的关键问题之一。当应用无法在一帧的时间内（通常为16.67ms）完成渲染工作时，就会出现掉帧，用户会感知到界面不流畅。&lt;/p&gt;
&lt;p&gt;本系列文章从渲染原理入手，系统性地介绍iOS卡顿的检测与优化方法。&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;卡顿监控是 APM 流畅性子系的核心能力，线上指标体系、检测采集、上报策略请参考 &lt;a href="https://amatsuzero.github.io/LastStand/posts/interview/ios-apm/apm/"&gt;APM 系列&lt;/a&gt;：&lt;a href="https://amatsuzero.github.io/LastStand/posts/interview/ios-apm/%E6%8C%87%E6%A0%87%E4%BD%93%E7%B3%BB/"&gt;指标体系&lt;/a&gt;、&lt;a href="https://amatsuzero.github.io/LastStand/posts/interview/ios-apm/%E6%95%B0%E6%8D%AE%E9%87%87%E9%9B%86/"&gt;数据采集&lt;/a&gt;、&lt;a href="https://amatsuzero.github.io/LastStand/posts/interview/ios-apm/%E4%B8%9A%E7%95%8C%E6%96%B9%E6%A1%88/"&gt;业界方案（微信 Matrix / 字节 Slardar 卡死监控）&lt;/a&gt;。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;hr&gt;
&lt;h2 id="什么是卡顿"&gt;什么是卡顿&lt;/h2&gt;
&lt;p&gt;iOS设备的屏幕刷新率通常为60Hz（ProMotion设备可达120Hz），这意味着每秒需要渲染60帧画面。每一帧的渲染时间窗口约为16.67ms（1000ms / 60）。&lt;/p&gt;
&lt;p&gt;当CPU或GPU无法在这个时间窗口内完成工作时，就会发生掉帧（Frame Drop），用户会感知到卡顿。&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;掉帧情况&lt;/th&gt;
&lt;th&gt;用户感知&lt;/th&gt;
&lt;th&gt;严重程度&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;偶尔掉1-2帧&lt;/td&gt;
&lt;td&gt;几乎无感知&lt;/td&gt;
&lt;td&gt;轻微&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;连续掉帧&lt;/td&gt;
&lt;td&gt;明显卡顿&lt;/td&gt;
&lt;td&gt;中等&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;长时间阻塞（&amp;gt;250ms）&lt;/td&gt;
&lt;td&gt;界面冻结&lt;/td&gt;
&lt;td&gt;严重&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;hr&gt;
&lt;h2 id="渲染流程概述"&gt;渲染流程概述&lt;/h2&gt;
&lt;p&gt;iOS的渲染流程涉及CPU和GPU的协作，通过Core Animation Pipeline完成：&lt;/p&gt;
&lt;pre class="mermaid"&gt;flowchart TB
subgraph APP["App 进程（CPU 阶段）"]
direction TB
Layout["Layout（布局计算）&lt;br/&gt;layoutSubviews、约束计算"]
Display["Display（绘制显示）&lt;br/&gt;drawRect:、文本绘制"]
Prepare["Prepare（准备）&lt;br/&gt;图片解码、格式转换"]
Commit["Commit（提交）&lt;br/&gt;打包图层树"]
Layout --&gt; Display --&gt; Prepare --&gt; Commit
end
subgraph RS["Render Server 进程（GPU 阶段）"]
direction TB
Decode["解码图层树"]
Vertex["顶点着色器"]
Raster["光栅化"]
Fragment["片段着色器"]
Buffer["帧缓冲区写入"]
Decode --&gt; Vertex --&gt; Raster --&gt; Fragment --&gt; Buffer
end
APP --&gt;|"IPC 传输"| RS
RS --&gt; VSync["VSync 信号到来"]
VSync --&gt; Screen["显示到屏幕"]
&lt;/pre&gt;
&lt;h3 id="cpu与gpu的职责"&gt;CPU与GPU的职责&lt;/h3&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;阶段&lt;/th&gt;
&lt;th&gt;主要工作&lt;/th&gt;
&lt;th&gt;常见瓶颈&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;CPU&lt;/td&gt;
&lt;td&gt;布局计算、视图创建、文本计算、图片解码&lt;/td&gt;
&lt;td&gt;复杂布局、大量文本、主线程阻塞&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;GPU&lt;/td&gt;
&lt;td&gt;纹理渲染、图层混合、离屏渲染&lt;/td&gt;
&lt;td&gt;离屏渲染、大量透明图层、超大图片&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;hr&gt;
&lt;h2 id="卡顿的常见原因"&gt;卡顿的常见原因&lt;/h2&gt;
&lt;h3 id="cpu瓶颈"&gt;CPU瓶颈&lt;/h3&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;主线程阻塞&lt;/strong&gt;：耗时操作在主线程执行&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;复杂布局&lt;/strong&gt;：大量约束计算、频繁布局&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;文本计算&lt;/strong&gt;：复杂富文本、大量文本渲染&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;图片解码&lt;/strong&gt;：大图片在主线程解码&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;对象创建&lt;/strong&gt;：大量对象的创建和销毁&lt;/li&gt;
&lt;/ol&gt;
&lt;h3 id="gpu瓶颈"&gt;GPU瓶颈&lt;/h3&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;离屏渲染&lt;/strong&gt;：圆角、阴影、遮罩触发离屏渲染&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;图层混合&lt;/strong&gt;：大量透明图层叠加&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;超大图片&lt;/strong&gt;：纹理尺寸超过GPU限制&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;复杂特效&lt;/strong&gt;：模糊、滤镜等GPU密集操作&lt;/li&gt;
&lt;/ol&gt;
&lt;hr&gt;
&lt;h2 id="文章导航"&gt;文章导航&lt;/h2&gt;
&lt;p&gt;本系列包含以下文章，建议按顺序阅读：&lt;/p&gt;</description></item><item><title>类型擦除</title><link>https://amatsuzero.github.io/LastStand/posts/interview/ios-basics/%E7%B1%BB%E5%9E%8B%E6%93%A6%E9%99%A4/</link><pubDate>Sat, 02 May 2026 22:32:27 +0800</pubDate><guid>https://amatsuzero.github.io/LastStand/posts/interview/ios-basics/%E7%B1%BB%E5%9E%8B%E6%93%A6%E9%99%A4/</guid><description>&lt;p&gt;类型擦除（Type Erasure）是一种编程技术，用于在运行时隐藏具体的类型信息，使得不同类型可以通过统一的接口进行操作。在iOS开发中，Objective-C和Swift都有类型擦除的概念，但实现方式和应用场景有所不同。&lt;/p&gt;
&lt;h2 id="swift中的类型擦除"&gt;Swift中的类型擦除&lt;/h2&gt;
&lt;p&gt;Swift是一门强类型语言，类型信息在编译时被严格检查。但在某些场景下，我们需要隐藏具体类型信息，这时就需要使用类型擦除技术。&lt;/p&gt;
&lt;h3 id="存在类型与不透明类型"&gt;存在类型与不透明类型&lt;/h3&gt;
&lt;p&gt;在理解类型擦除之前，需要先理解 Swift 类型系统中两个关键概念：&lt;strong&gt;存在类型（Existential Type）&lt;/strong&gt; 和&lt;strong&gt;不透明类型（Opaque Type）&lt;/strong&gt;。它们是协议在类型层面的两种使用方式，也是理解 &lt;code&gt;any&lt;/code&gt; 和 &lt;code&gt;some&lt;/code&gt; 关键字的基础。&lt;/p&gt;
&lt;h4 id="存在类型existential-type"&gt;存在类型（Existential Type）&lt;/h4&gt;
&lt;p&gt;&amp;ldquo;存在类型&amp;quot;这个术语来自类型论中的存在量词（∃）。它表达的语义是：&lt;strong&gt;&amp;ldquo;存在某个类型 T 遵循了协议 P，但我不知道也不关心 T 具体是什么。&amp;rdquo;&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;当你把一个协议当作类型来使用时（而非泛型约束），你就在使用存在类型：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-swift" data-lang="swift"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;protocol&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;Animal&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;func&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;makeSound&lt;/span&gt;() -&amp;gt; String
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;struct&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;Dog&lt;/span&gt;: Animal {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;func&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;makeSound&lt;/span&gt;() -&amp;gt; String { &lt;span style="color:#e6db74"&gt;&amp;#34;Woof!&amp;#34;&lt;/span&gt; }
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;struct&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;Cat&lt;/span&gt;: Animal {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;func&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;makeSound&lt;/span&gt;() -&amp;gt; String { &lt;span style="color:#e6db74"&gt;&amp;#34;Meow!&amp;#34;&lt;/span&gt; }
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;// animals 数组中的每个元素都是存在类型&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;// 编译器不知道每个元素的具体类型，只知道&amp;#34;存在某个类型遵循了 Animal&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;var&lt;/span&gt; animals: [any Animal] = [Dog(), Cat()]
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;存在类型的核心特征：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;运行时多态&lt;/strong&gt;：具体类型在运行时才确定，同一个变量可以在不同时刻持有不同的具体类型&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;有性能开销&lt;/strong&gt;：Swift 通过存在容器（Existential Container）来存储值，方法调用需要通过见证表间接派发&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;类型信息被隐藏&lt;/strong&gt;：调用方只能通过协议接口与值交互，无法访问具体类型的特有成员&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;在 Swift 5.6 之前，直接把协议写成类型（如 &lt;code&gt;let x: Animal&lt;/code&gt;）就是存在类型，但语法上没有任何标记。Swift 5.6 引入 &lt;code&gt;any&lt;/code&gt; 关键字使其变得显式，目的是提醒开发者这里存在运行时开销。Swift 5.7 起，对于带有关联类型的协议，必须使用 &lt;code&gt;any&lt;/code&gt; 才能作为存在类型。&lt;/p&gt;</description></item><item><title>计算机网络</title><link>https://amatsuzero.github.io/LastStand/posts/interview/ios-basics/%E8%AE%A1%E7%AE%97%E6%9C%BA%E7%BD%91%E7%BB%9C/</link><pubDate>Sun, 03 May 2026 23:11:47 +0800</pubDate><guid>https://amatsuzero.github.io/LastStand/posts/interview/ios-basics/%E8%AE%A1%E7%AE%97%E6%9C%BA%E7%BD%91%E7%BB%9C/</guid><description>&lt;h2 id="网络分层模型"&gt;网络分层模型&lt;/h2&gt;
&lt;h3 id="osi七层模型"&gt;OSI七层模型&lt;/h3&gt;
&lt;p&gt;OSI（Open Systems Interconnection）是国际标准化组织提出的网络通信参考模型：&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;层级&lt;/th&gt;
&lt;th&gt;名称&lt;/th&gt;
&lt;th&gt;功能&lt;/th&gt;
&lt;th&gt;协议/设备举例&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;7&lt;/td&gt;
&lt;td&gt;应用层&lt;/td&gt;
&lt;td&gt;为应用程序提供网络服务&lt;/td&gt;
&lt;td&gt;HTTP, FTP, DNS, SMTP&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;6&lt;/td&gt;
&lt;td&gt;表示层&lt;/td&gt;
&lt;td&gt;数据格式转换、加密/解密&lt;/td&gt;
&lt;td&gt;SSL/TLS, JPEG, ASCII&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;5&lt;/td&gt;
&lt;td&gt;会话层&lt;/td&gt;
&lt;td&gt;建立、管理和终止会话&lt;/td&gt;
&lt;td&gt;RPC, SQL&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;4&lt;/td&gt;
&lt;td&gt;传输层&lt;/td&gt;
&lt;td&gt;端到端的可靠数据传输&lt;/td&gt;
&lt;td&gt;TCP, UDP&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;3&lt;/td&gt;
&lt;td&gt;网络层&lt;/td&gt;
&lt;td&gt;路由选择与IP寻址&lt;/td&gt;
&lt;td&gt;IP, ICMP, ARP&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;2&lt;/td&gt;
&lt;td&gt;数据链路层&lt;/td&gt;
&lt;td&gt;帧的封装与MAC寻址&lt;/td&gt;
&lt;td&gt;Ethernet, Wi-Fi&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;1&lt;/td&gt;
&lt;td&gt;物理层&lt;/td&gt;
&lt;td&gt;比特流的物理传输&lt;/td&gt;
&lt;td&gt;光纤, 双绞线&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;h3 id="tcpip四层模型"&gt;TCP/IP四层模型&lt;/h3&gt;
&lt;p&gt;实际工程中更常用的是TCP/IP四层模型，它将OSI的上三层合并为应用层，下两层合并为网络接口层：&lt;/p&gt;
&lt;pre class="mermaid"&gt;graph TB
subgraph "TCP/IP四层模型"
A["应用层&lt;br/&gt;HTTP, DNS, FTP, SMTP"]
B["传输层&lt;br/&gt;TCP, UDP"]
C["网络层&lt;br/&gt;IP, ICMP, ARP"]
D["网络接口层&lt;br/&gt;Ethernet, Wi-Fi"]
end
subgraph "OSI七层模型"
E["应用层"]
F["表示层"]
G["会话层"]
H["传输层"]
I["网络层"]
J["数据链路层"]
K["物理层"]
end
A --- E
A --- F
A --- G
B --- H
C --- I
D --- J
D --- K
&lt;/pre&gt;
&lt;h3 id="数据封装与解封装"&gt;数据封装与解封装&lt;/h3&gt;
&lt;p&gt;数据在发送方从上到下逐层封装，每一层都将上层传来的数据视为&lt;strong&gt;载荷（Payload）&lt;/strong&gt;，在其前面添加本层的头部信息（部分层还会添加尾部信息），然后交给下一层处理。接收方则从下到上逐层解封装，每一层剥离本层头部后将载荷交给上层。&lt;/p&gt;</description></item><item><title>包瘦身-App Thinning</title><link>https://amatsuzero.github.io/LastStand/posts/interview/ios-performance/size-appthinning/</link><pubDate>Sat, 02 May 2026 22:32:27 +0800</pubDate><guid>https://amatsuzero.github.io/LastStand/posts/interview/ios-performance/size-appthinning/</guid><description>&lt;p&gt;App Thinning是Apple提供的包体积优化技术，让用户只下载适合其设备的内容。本文详细介绍App Thinning的三个组成部分及其原理。&lt;/p&gt;
&lt;hr&gt;
&lt;h2 id="整体架构"&gt;整体架构&lt;/h2&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-fallback" data-lang="fallback"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;开发者上传：
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;┌─────────────────────────────────────────┐
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;│ Universal IPA │
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;│ ├── arm64 代码 │
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;│ ├── @1x/@2x/@3x 图片 │
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;│ ├── iPhone/iPad 资源 │
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;│ └── Metal GPU资源（OpenGL ES已弃用） │
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;└─────────────────────────────────────────┘
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; ↓
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; App Store处理
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; ↓
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;┌───────────┐ ┌──────────┐ ┌──────────┐
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;│ iPhone 12 │ │ iPhone 8 │ │ iPad Pro │
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;│ 变体 │ │ 变体 │ │ 变体 │
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;│ @3x图片 │ │ @2x图片 │ │ @2x图片 │
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;│ arm64 │ │ arm64 │ │ arm64 │
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;│ A14 GPU │ │ A11 GPU │ │ M1 GPU │
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;└───────────┘ └──────────┘ └──────────┘
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;App Thinning包含三个部分：&lt;/p&gt;</description></item><item><title>包瘦身-分析工具</title><link>https://amatsuzero.github.io/LastStand/posts/interview/ios-performance/size-%E5%88%86%E6%9E%90%E5%B7%A5%E5%85%B7/</link><pubDate>Sat, 02 May 2026 22:32:27 +0800</pubDate><guid>https://amatsuzero.github.io/LastStand/posts/interview/ios-performance/size-%E5%88%86%E6%9E%90%E5%B7%A5%E5%85%B7/</guid><description>&lt;p&gt;在进行包体积优化之前，首先需要了解如何分析包体积。本文介绍常用的分析工具和Mach-O文件结构。&lt;/p&gt;
&lt;hr&gt;
&lt;h2 id="查看ipa构成"&gt;查看IPA构成&lt;/h2&gt;
&lt;p&gt;解压IPA文件分析各部分大小：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;# 解压IPA&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;unzip -q YourApp.ipa -d ./ipa_content
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;# 查看各文件大小&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;find ./ipa_content -type f -exec ls -lh &lt;span style="color:#f92672"&gt;{}&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;\;&lt;/span&gt; | sort -k5 -h -r | head -20
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;hr&gt;
&lt;h2 id="linkmap分析"&gt;LinkMap分析&lt;/h2&gt;
&lt;p&gt;LinkMap文件记录了链接器生成可执行文件的详细信息，可以精确分析二进制大小：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-fallback" data-lang="fallback"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;# Build Settings中设置
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;Write Link Map File = YES
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;Path to Link Map File = $(TARGET_TEMP_DIR)/$(PRODUCT_NAME)-LinkMap-$(CURRENT_VARIANT)-$(CURRENT_ARCH).txt
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h3 id="linkmap文件结构"&gt;LinkMap文件结构&lt;/h3&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-fallback" data-lang="fallback"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;# Path: /path/to/YourApp
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;# Arch: arm64
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;# Object files:
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;[ 0] linker synthesized
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;[ 1] /path/to/ViewController.o
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;[ 2] /path/to/Model.o
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;# Sections:
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;# Address Size Segment Section
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;0x100001000 0x00012345 __TEXT __text
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;0x100013345 0x00001234 __TEXT __stubs
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;# Symbols:
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;# Address Size File Name
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;0x100001000 0x00000100 [ 1] -[ViewController viewDidLoad]
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;0x100001100 0x00000050 [ 2] -[Model init]
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h3 id="解析脚本"&gt;解析脚本&lt;/h3&gt;
&lt;p&gt;可以使用脚本解析LinkMap统计各模块大小：&lt;/p&gt;</description></item><item><title>包瘦身-可执行文件优化</title><link>https://amatsuzero.github.io/LastStand/posts/interview/ios-performance/size-%E5%8F%AF%E6%89%A7%E8%A1%8C%E6%96%87%E4%BB%B6%E4%BC%98%E5%8C%96/</link><pubDate>Sat, 02 May 2026 22:32:27 +0800</pubDate><guid>https://amatsuzero.github.io/LastStand/posts/interview/ios-performance/size-%E5%8F%AF%E6%89%A7%E8%A1%8C%E6%96%87%E4%BB%B6%E4%BC%98%E5%8C%96/</guid><description>&lt;p&gt;可执行文件通常占iOS应用包体积的30-50%，是优化的重点。本文介绍各种可执行文件优化手段及其原理。&lt;/p&gt;
&lt;hr&gt;
&lt;h2 id="编译器优化选项"&gt;编译器优化选项&lt;/h2&gt;
&lt;h3 id="优化级别原理"&gt;优化级别原理&lt;/h3&gt;
&lt;p&gt;编译器优化级别控制了LLVM在编译时应用的优化Pass数量和类型。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;什么是优化Pass？&lt;/strong&gt; Pass是指编译器对代码进行的一次特定优化处理过程。LLVM将优化工作分解为多个独立的Pass，每个Pass负责一种特定类型的优化：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-fallback" data-lang="fallback"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;源代码 → 前端解析 → IR（中间表示）→ Pass1 → Pass2 → Pass3 → ... → 优化后的代码 → 机器码
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;常见的优化Pass包括：&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Pass名称&lt;/th&gt;
&lt;th&gt;作用&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Dead Code Elimination&lt;/td&gt;
&lt;td&gt;删除永远不会执行的代码&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Constant Folding&lt;/td&gt;
&lt;td&gt;编译时计算常量表达式，如&lt;code&gt;3+5&lt;/code&gt;直接变成&lt;code&gt;8&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Function Inlining&lt;/td&gt;
&lt;td&gt;将函数调用替换为函数体本身&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Loop Unrolling&lt;/td&gt;
&lt;td&gt;展开循环，减少循环控制开销&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Common Subexpression Elimination&lt;/td&gt;
&lt;td&gt;消除重复计算的表达式&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;不同的优化级别启用不同数量和类型的Pass：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-fallback" data-lang="fallback"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;# Build Settings
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;Optimization Level = -Os # 级别：-Os 优化大小（推荐用于Release）
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;&lt;strong&gt;-O0（无优化）&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;不应用任何优化Pass，编译速度最快。代码按原样生成，保留所有变量和控制流，便于调试。适用于Debug构建。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;-O1（基础优化）&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;应用不显著增加编译时间的基础优化，包括：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;基本的死代码消除&lt;/li&gt;
&lt;li&gt;简单的常量折叠&lt;/li&gt;
&lt;li&gt;基本块合并&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;死代码消除：&lt;/strong&gt; 死代码消除（Dead Code Elimination）是指编译器自动移除永远不会被执行或执行结果不会被使用的代码。注意：这里的死代码消除是编译阶段的优化，作用于函数内部；而后文提到的Dead Code Stripping是链接阶段的优化，用于移除未被引用的整个函数或类。&lt;/p&gt;
&lt;p&gt;-O1 适合需要一定优化但对编译速度敏感的场景。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;-O2（标准优化）&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;应用大多数优化Pass，是性能和体积的平衡点。包括：&lt;/p&gt;</description></item><item><title>包瘦身-资源优化</title><link>https://amatsuzero.github.io/LastStand/posts/interview/ios-performance/size-%E8%B5%84%E6%BA%90%E4%BC%98%E5%8C%96/</link><pubDate>Sat, 02 May 2026 22:32:27 +0800</pubDate><guid>https://amatsuzero.github.io/LastStand/posts/interview/ios-performance/size-%E8%B5%84%E6%BA%90%E4%BC%98%E5%8C%96/</guid><description>&lt;p&gt;资源文件通常占iOS应用包体积的40-60%，是优化的重要方向。本文介绍各种资源优化手段及其原理。&lt;/p&gt;
&lt;hr&gt;
&lt;h2 id="图片优化"&gt;图片优化&lt;/h2&gt;
&lt;h3 id="asset-catalog原理"&gt;Asset Catalog原理&lt;/h3&gt;
&lt;p&gt;Asset Catalog（&lt;code&gt;.xcassets&lt;/code&gt;）编译后生成&lt;code&gt;Assets.car&lt;/code&gt;文件，这是一个优化过的资源容器：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-fallback" data-lang="fallback"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;编译前：
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;Images.xcassets/
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;├── AppIcon.appiconset/
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;│ ├── icon-60@2x.png
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;│ └── icon-60@3x.png
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;├── Logo.imageset/
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;│ ├── logo@2x.png
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;│ └── logo@3x.png
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;└── Contents.json
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;编译后：
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;Assets.car ← 单一文件，包含所有资源
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;&lt;strong&gt;Assets.car的优化&lt;/strong&gt;：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;图片被重新编码，使用更高效的压缩&lt;/li&gt;
&lt;li&gt;支持App Thinning，按设备分发&lt;/li&gt;
&lt;li&gt;运行时高效加载（内存映射）&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;可以使用&lt;code&gt;assetutil&lt;/code&gt;查看Assets.car内容：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;assetutil --info Assets.car
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h3 id="图片压缩原理"&gt;图片压缩原理&lt;/h3&gt;
&lt;p&gt;&lt;strong&gt;PNG压缩原理&lt;/strong&gt;：&lt;/p&gt;
&lt;p&gt;PNG使用DEFLATE无损压缩，但可以通过以下方式减小体积：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-fallback" data-lang="fallback"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;原始PNG结构：
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;┌────────────────┐
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;│ PNG Header │
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;├────────────────┤
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;│ IHDR (图像信息) │
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;├────────────────┤
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;│ IDAT (图像数据) │ ← 压缩的像素数据
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;├────────────────┤
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;│ 辅助chunks │ ← 可以移除
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;└────────────────┘
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;优化方向：
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;1. 移除不必要的chunks（如tEXt、iTXt）
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;2. 优化DEFLATE压缩参数
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;3. 减少颜色数量（有损）
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;4. 使用更高效的滤波器
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;&lt;strong&gt;有损压缩原理（pngquant）&lt;/strong&gt;：&lt;/p&gt;</description></item><item><title>包瘦身</title><link>https://amatsuzero.github.io/LastStand/posts/interview/ios-performance/size-%E5%8C%85%E7%98%A6%E8%BA%AB/</link><pubDate>Sat, 02 May 2026 22:32:27 +0800</pubDate><guid>https://amatsuzero.github.io/LastStand/posts/interview/ios-performance/size-%E5%8C%85%E7%98%A6%E8%BA%AB/</guid><description>&lt;p&gt;包体积（IPA大小）是iOS应用的重要质量指标。App Store对蜂窝网络下载有200MB的提示阈值，超过这个大小会弹窗询问用户是否使用流量下载（iOS 13之前是强制要求Wi-Fi）。这个弹窗会增加用户的决策成本，影响下载转化率。因此，包体积优化对于用户获取和留存都有重要影响。&lt;/p&gt;
&lt;hr&gt;
&lt;h2 id="包格式介绍"&gt;包格式介绍&lt;/h2&gt;
&lt;p&gt;iOS开发中常见的包格式有三种：&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;格式&lt;/th&gt;
&lt;th&gt;扩展名&lt;/th&gt;
&lt;th&gt;说明&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;.app&lt;/td&gt;
&lt;td&gt;目录&lt;/td&gt;
&lt;td&gt;应用程序包，是一个包含可执行文件和资源的目录结构&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;.xcarchive&lt;/td&gt;
&lt;td&gt;目录&lt;/td&gt;
&lt;td&gt;Xcode归档包，包含.app、dSYM符号文件、构建信息等&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;.ipa&lt;/td&gt;
&lt;td&gt;文件&lt;/td&gt;
&lt;td&gt;安装包，本质是ZIP压缩的.app，用于分发和安装&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;&lt;strong&gt;日常使用场景&lt;/strong&gt;：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;开发调试&lt;/strong&gt;：Xcode直接将&lt;code&gt;.app&lt;/code&gt;安装到模拟器或真机&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;测试分发&lt;/strong&gt;：使用&lt;code&gt;.ipa&lt;/code&gt;通过TestFlight、蒲公英、fir.im等平台分发给测试人员&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;App Store上架&lt;/strong&gt;：通过Xcode或Transporter将&lt;code&gt;.xcarchive&lt;/code&gt;导出并上传到App Store Connect（实际上传的是从xcarchive导出的IPA或直接上传xcarchive中的内容）&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id="appapplication-bundle"&gt;.app（Application Bundle）&lt;/h3&gt;
&lt;p&gt;&lt;code&gt;.app&lt;/code&gt;是macOS/iOS应用的标准格式，实际上是一个目录（Finder中显示为单个文件）。包含：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;可执行文件（Mach-O格式）&lt;/li&gt;
&lt;li&gt;Info.plist配置文件&lt;/li&gt;
&lt;li&gt;资源文件（图片、音频、本地化文件等）&lt;/li&gt;
&lt;li&gt;Frameworks目录（动态库）&lt;/li&gt;
&lt;li&gt;PlugIns目录（App Extension）&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id="xcarchivexcode-archive"&gt;.xcarchive（Xcode Archive）&lt;/h3&gt;
&lt;p&gt;&lt;code&gt;.xcarchive&lt;/code&gt;是Xcode的归档格式，用于保存完整的构建产物。目录结构：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-fallback" data-lang="fallback"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;YourApp.xcarchive/
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;├── Products/
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;│ └── Applications/
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;│ └── YourApp.app # 应用程序包
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;├── dSYMs/
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;│ └── YourApp.app.dSYM # 符号文件（用于崩溃解析）
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;├── Info.plist
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;└── SCMBlueprint/ # 源码管理信息
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;主要用途：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;保存dSYM符号文件，用于线上崩溃日志符号化&lt;/li&gt;
&lt;li&gt;导出不同分发渠道的IPA（App Store、Ad Hoc、Enterprise）&lt;/li&gt;
&lt;li&gt;上传到App Store Connect&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id="ipaios-app-store-package"&gt;.ipa（iOS App Store Package）&lt;/h3&gt;
&lt;p&gt;&lt;code&gt;.ipa&lt;/code&gt;是iOS应用的安装包格式，本质是一个ZIP压缩文件。结构：&lt;/p&gt;</description></item></channel></rss>