<?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>Runtime on Last Stand</title><link>https://amatsuzero.github.io/LastStand/tags/runtime/</link><description>Recent content in Runtime on Last Stand</description><generator>Hugo</generator><language>zh-cn</language><lastBuildDate>Tue, 16 Jun 2026 09:06:27 +0800</lastBuildDate><atom:link href="https://amatsuzero.github.io/LastStand/tags/runtime/index.xml" rel="self" type="application/rss+xml"/><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>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>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>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>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>+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>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>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>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>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>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>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>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>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>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>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>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></channel></rss>