JRSwizzle源码逐行解读:method_exchangeImplementations与方法交换全机制解析
JRSwizzle源码逐行解读method_exchangeImplementations与方法交换全机制解析【免费下载链接】jrswizzleone-stop-shop for all your method swizzling needs项目地址: https://gitcode.com/gh_mirrors/jr/jrswizzleJRSwizzle 是 Objective-C 开发中处理**方法交换Method Swizzling**的一站式开源库核心代码仅两个文件、不到 200 行。本文将逐行解读它的源码带你彻底搞懂method_exchangeImplementations的工作原理、继承场景下的方法提升技巧以及它与class_addMethod的经典配合机制——即使你是运行时新手也能轻松读懂。一、方法交换解决什么问题在 Objective-C 中[obj doSomething]这行消息发送的本质是在类的方法列表里根据选择器SEL找到对应方法的实现函数指针IMP然后跳转执行。方法交换就是在运行时把两个方法的 IMP 对调。交换之后方法名和签名不变但实际执行的是对方的代码。常见用途给第三方库的方法无侵入加日志、埋点A/B 测试中临时替换业务逻辑监控或拦截系统框架的调用但方法交换有一个新手最容易踩的坑继承。如果子类的某个方法是从父类继承来的直接对父类方法动手会把整条继承链全部改坏。JRSwizzle 存在的最大意义就是在任意系统版本上正确处理这个继承问题。二、项目结构一览核心代码就两个文件 文件作用JRSwizzle.h公开 API 声明只有 4 个类方法JRSwizzle.m全部核心实现约 166 行JRSwizzleTest/JRSwizzleTest.m继承/直接实现的正确性测试JRSwizzleTest/MethodSwizzle.m早期 Ballard 实现的对照参考JRSwizzle.podspecCocoaPods 描述文件iOS 4.3 / macOS 10.6整个库不依赖任何第三方只依赖Foundation和 ObjC 运行时头文件。三、四种交换 API 速览 ⚡JRSwizzle.h 中通过NSObject的类别暴露了 4 个 APIAPI用途jr_swizzleMethod:withMethod:error:交换两个实例方法最常用jr_swizzleClassMethod:withClassMethod:error:交换两个类方法jr_swizzleMethod:withBlock:error:用Block 注入替换实例方法jr_swizzleClassMethod:withBlock:error:用 Block 注入替换类方法最基础的使用方式一行搞定[SomeClass jr_swizzleMethod:selector(foo) withMethod:selector(my_foo) error:error];所有 API 都返回NSError**出参找不到方法时会写入高质量诊断信息这是它在鲁棒性上优于早期实现的体现。四、核心源码逐行解读jr_swizzleMethod 三步走 下面是对 JRSwizzle.m 中jr_swizzleMethod:withMethod:error:的逐步拆解现代运行时路径即OBJC_API_VERSION 2。第 0 步兼容性预处理文件开头有两处为兼容老系统服务的定义JRSwizzle.miOS 与 macOS 需要的运行时头文件不同objc/runtime.hvsobjc/objc-class.hJRSwizzle.m老运行时没有object_getClass用obj-isa兜底取类。这正是 README 所说在 Mac OS X v10.3 到 iOS 2.0 全部版本都能工作的原因。第 1 步查找两个方法L34–L52用class_getInstanceMethod分别取出原始方法和替身方法的Method结构体。任何一个查不到就通过 SetNSError 宏 写入带函数名和描述的错误信息并返回NO——先校验、后动手保证不会留下改了一半的脏状态。第 2 步关键技巧——把方法提升到目标类L54–L61⭐这是整个库最精髓的地方源码只有两次class_addMethodclass_addMethod(self, origSel_, class_getMethodImplementation(self, origSel_), method_getTypeEncoding(origMethod)); class_addMethod(self, altSel_, class_getMethodImplementation(self, altSel_), method_getTypeEncoding(altMethod));class_addMethod的特性是类上如果已有该方法什么都不做没有才添加。所以这两行代码的实际效果是方法本来就是目标类自己定义的→ 无操作直接通过方法是从父类继承来的 → 把它复制一份连同 IMP 和类型编码挂到目标类上变成类自己的方法。这一步叫方法提升hoisting。它保证了第 3 步交换的永远是目标类自己的两份方法记录绝不会误伤父类和其它兄弟子类。第 3 步交换实现L63method_exchangeImplementations(class_getInstanceMethod(self, origSel_), class_getInstanceMethod(self, altSel_));到这里两个方法已确定都住在同一个类的方法列表里可以放心交给method_exchangeImplementations完成对调返回YES。五、method_exchangeImplementations 底层机制剖析 这个运行时 API 的语义非常纯粹把两个Method记录里的method_imp字段互换仅此而已。它不修改方法名、不改类型编码、不动方法列表结构。理解它有三个要点前提是同一类——两个方法必须位于同一个类或元类的方法列表中否则行为未定义。这就是为什么 JRSwizzle 要先做第 2 步的提升交换的是实现不是名字——交换后[obj foo]依然按foo的签名去调用只是执行到了my_foo的函数体所以两边签名不一致时仍有风险它是原子级的安全原语——只做一次指针互换比手动改写method_imp少出错这也是 macOS 10.5 / iOS 2.0 之后官方推荐的做法。六、旧版兼容路径手动交换的 Ballard 实现 ️对于OBJC_API_VERSION 2的老系统没有method_exchangeImplementationsJRSwizzle.m 走一条完全手工的路径致敬的是 Kevin Ballard 的经典实现遍历方法列表L70–L84用class_nextMethodList只找目标类直接拥有的方法刻意排除继承方法提升继承方法L112–L127缺哪个就用class_getInstanceMethod从继承链取出手工拼一个objc_method_list再class_addMethods挂上去——注释里还特意把obsolete字段置空来安抚 valgrind手动交换L130–L132IMP temp directOriginalMethod-method_imp; directOriginalMethod-method_imp directAlternateMethod-method_imp; directAlternateMethod-method_imp temp;三步逻辑与现代路径完全同构先提升再交换。测试目录里的 MethodSwizzle.m 保留了这一实现的完整对照版本可结合阅读。七、类方法与 Block 注入进阶 API 类方法交换只有一行JRSwizzle.mreturn [GetClass((id)self) jr_swizzleMethod:origSel_ withMethod:altSel_ error:error_];原理一句话类方法是元类metaclass的实例方法。GetClass((id)self)取出元类后类方法交换就退化成了普通的实例方法交换。Block 注入JRSwizzle.m则更巧妙分四步imp_implementationWithBlock把 Block 包装成一个 IMP用方法名 Block 地址拼出唯一选择器如_jr_block_foo_0x1005避免重名class_addMethod把 Block 方法挂上类再走标准流程与原方法交换返回一个NSInvocation在 Block 内部可以调它来执行原始实现——实现执行我的逻辑后再补刀原方法的经典模式。注意 JRSwizzle.h 的注释示例Block 里通过__block NSInvocation *invocation引用自身先打日志、再invoke原方法、最后取返回值。版本历史显示该 API 是 v1.1.0 加入的作者也坦承NSInvocation不是最快的路径性能敏感场景请谨慎。八、测试用例如何验证继承也正确 ✅JRSwizzleTest.m 里两个场景测试恰好对应 README 对比表中的第 7、8 行其余实现各有一行是 NO场景 7直接实现父类A7定义foo7子类B7重写了它类别里加了altFoo7。对B7交换后——b foo7走altFoo7而父类实例a foo7完全不受影响L41-L78场景 8继承实现B8没有重写foo8是从父类继承的。交换后B8走altFoo8A8依然走原foo8L114-L151。第二个场景就是提升技巧的用武之地foo8本来在A8的方法列表里先被复制到B8再交换所以父类安然无恙。两个测试断言里那句// CORRECT BEHAVIOR注释正是整个库的立身之本。九、上手指南如何安装使用 方式一CocoaPods推荐根据 JRSwizzle.podspec直接pod JRSwizzle方式二手动引入clone 仓库后把 JRSwizzle.h 和 JRSwizzle.m 加入工程即可git clone https://gitcode.com/gh_mirrors/jr/jrswizzle使用建议把交换调用放在load或initialize中执行且只交换一次——重复交换等于把实现换回去是最常见的自伤操作。十、总结一张表看懂全部机制 机制对应源码一句话解释查找方法L34-L52先校验找不到就报 NSError绝不留脏状态方法提升L54-L61两次class_addMethod把继承方法复制成类自己的实现交换L63method_exchangeImplementations只互换 IMP 指针旧系统兼容L66-L135无该 API 时手工提升 手动交换类方法交换L138-L140取元类后委托给实例方法交换Block 注入L142-L164Block → IMP → 挂类 → 交换NSInvocation 保留原实现JRSwizzle 的源码不长却把方法交换的每个坑都填平了先提升、再交换的六字心法配合完善的错误诊断和跨版本兼容让它成为学习 Objective-C 运行时方法交换机制的最佳活教材。读懂这 200 行代码你就真正掌握了method_exchangeImplementations的全套使用姿势。【免费下载链接】jrswizzleone-stop-shop for all your method swizzling needs项目地址: https://gitcode.com/gh_mirrors/jr/jrswizzle创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

相关新闻

嵌入式数字系统设计

嵌入式数字系统设计

概述说明 一直从事嵌入式系统相关的开发工作,学习了很多的嵌入式编程的方法以及框架,但是一直无法将其统一为一个标准的设计方法学,阻碍了设计的统一性以及拓展性。为了提高嵌入式系统设计的标准化和精准化的设计能力,这里准备创建…

2026/10/26 16:06:54 阅读更多 →
AnyPS5 NID系统揭秘:PS5的SHA-1符号哈希如何在Linux/Windows上被解析与重绑定

AnyPS5 NID系统揭秘:PS5的SHA-1符号哈希如何在Linux/Windows上被解析与重绑定

AnyPS5 NID系统揭秘:PS5的SHA-1符号哈希如何在Linux/Windows上被解析与重绑定 【免费下载链接】AnyPS5 Tool for automatic PS5 executables porting to Linux and Windows 项目地址: https://gitcode.com/gh_mirrors/an/AnyPS5 AnyPS5 是一款自动移植 PS5 可…

2026/10/24 23:13:54 阅读更多 →
供应商成了出资方:从Anthropic招股书自曝的潜在利益冲突看谈判力

供应商成了出资方:从Anthropic招股书自曝的潜在利益冲突看谈判力

供应商同时是出资方,这种双重身份被Anthropic自己写进了招股书,叫潜在利益冲突。对大客户销售来说,这是一份公开的力量对比说明书。 事件本身说了什么 据东方财富报道,Anthropic在招股书中承认,博通同时作为硬件供应商…

2026/11/5 20:31:54 阅读更多 →

最新新闻

Electron桌面应用开发实战:从环境搭建到打包发布全流程

Electron桌面应用开发实战:从环境搭建到打包发布全流程

做前端这些年,我大部分时间都在跟浏览器标签页打交道,直到第一次把桌面应用跑起来,才发现原来自己一直被限制在地址栏和刷新按钮围起来的框框里。Electron这个词,最开始是在某段时间频繁出现在同事的讨论里,一个用HTML…

2026/11/10 23:32:01 阅读更多 →
滑盖智能锁T109深度解析:结构原理、安装调试与故障排查

滑盖智能锁T109深度解析:结构原理、安装调试与故障排查

简介:亚太天能T109滑盖智能锁产品说明书是一份PDF格式的官方技术文档,主要面向智能锁安装人员、终端用户及售后维护者,帮助快速掌握产品安装、配置与常见故障处理。全包仅1个PDF文件,大小4.37MB,内容结构清晰&#xff…

2026/11/10 23:32:03 阅读更多 →
PMSM弱磁控制原理与Simulink建模:高速AGV驱动系统设计指南

PMSM弱磁控制原理与Simulink建模:高速AGV驱动系统设计指南

上个月我在调试一台高速AGV的驱动系统,整车要求空载跑到8m/s,电机转速已经拉到额定点,驱动器的输出电压也顶到了母线电压极限附近。再往上踩速度指令,转速纹丝不动,三相电流反而开始震荡。那会儿我的第一反应就是&…

2026/11/11 2:31:33 阅读更多 →
C++核心知识点:从内存管理到STL的实战指南

C++核心知识点:从内存管理到STL的实战指南

C 这门语言我前前后后折腾了十几年,用它写过嵌入式驱动、做过游戏服务端,也搭过基础组件库。每次看到新人一头扎进"C 核心知识点"这个搜索词,我其实挺感慨的——这门语言的难点从来不是语法多,而是知识点之间的耦合太深…

2026/11/10 16:14:15 阅读更多 →
T109滑盖智能锁怎么装?安装调试与故障排查全攻略

T109滑盖智能锁怎么装?安装调试与故障排查全攻略

简介:亚太天能T109滑盖智能锁产品说明书以PDF格式发布,适合智能锁用户、安装人员与售后维修人员阅读。内容围绕T109系列指纹密码刷卡锁展开,先介绍前面板、后面板、锁体、机械钥匙、电池盒盖等部件名称与功能,再给出完整安装步骤&…

2026/11/10 12:51:50 阅读更多 →
LLM知识降熵:从信息垄断到理解权下放

LLM知识降熵:从信息垄断到理解权下放

你有没有过这种经历:翻开源码注释、论文摘要或者一份专业报告,每个字都认识,连在一起却像天书。想找人聊聊,身边要么没人懂,要么懂的懒得跟你解释。后来我试着把同一段内容丢给一个大语言模型,几秒钟之后&a…

2026/11/10 23:32:10 阅读更多 →

日新闻

周新闻

月新闻