Objective-C Method Swizzling

原文地址:http://www.cocoachina.com/ios/20141002/9819.html


例子

以替换 NSArray 的 lastObject 方法为例:

在 NSArray 中添加需要替换 lastObject 的方法 – xxx_lastObject方法:

1
2
3
4
5
6
7
8
9
10
11
import “NSArray+Swizzle.h”
 
@implementation NSArray (Swizzle)
 
     (id)xxx_lastObject
     {
     id ret = [self xxx_lastObject];
     NSLog(@“ myLastObject *”);
     return  ret;
     }
     @end

注意这里的写法,xxx_lastObject 方法的 IMP 中调用了 [self xxx_lastObject],这样写并不会造成递归,后面会交换 xxx_lastObject 与 lastObject 的 IMP,其实 [self xxx_lastObject] 将会执行 [self lastObject] 。

调换 IMP

1
2
3
4
5
6
#import <objc/runtime.h>  
#import "NSArray+Swizzle.h"
 
Method ori_Method =  class_getInstanceMethod([NSArray class], @selector(lastObject));
Method my_Method = class_getInstanceMethod([NSArray class], @selector(xxx_lastObject));
method_exchangeImplementations(ori_Method, my_Method);

注意这里需要引入 <objc/runtime.h>,否则会报错,因为使用了 runtime 中的 method_exchangeImplementations 方法。

使用 method_exchangeImplementations 交换了 xxx_lastObject 与 lastObject 的 IMP。后面会讲解更深层次的原理。

尝试调用 lastObject

1
2
3
4
5
6
#import <objc/runtime.h>
#import "NSArray+Swizzle.h"
 
NSArray *array = @[@ "0" ,@ "1" ,@ "2" ,@ "3" ];
NSString *string = [array lastObject];
NSLog(@ "TEST RESULT : %@" ,string);

很明显,这里调用 lastObject 方法,其实是调用了我们添加的 xxx_lastObject 方法。

常用 API

相关常用方法,都在<objc/runtime.h>包内: 

1
2
3
4
5
6
7
8
9
10
11
//向类中添加Method 
BOOL class_addMethod(Class cls, SEL name, IMP imp, const char *types)
 
//修改类的Method IMP 
class_replaceMethod(Class cls, SEL name, IMP imp, const char *types)
 
//交换2个方法中的IMP 
void method_exchangeImplementations(Method m1, Method m2)
 
//获取类的某个实例方法 
Method class_getInstanceMethod(Class aClass, SEL aSelector);

底层原理

在运行时,OC 的方法被称为一种叫 Method 的结构体,这种 objc_method 类型的结构体定义为:

1
2
3
4
5
struct objc_method {
    SEL method_name         OBJC2_UNAVAILABLE;
    char *method_types      OBJC2_UNAVAILABLE;
    IMP method_imp          OBJC2_UNAVAILABLE;
}

method_name 是方法的 selector,可以理解为运行时的方法名;

*method_types 是一个参数和返回值类型编码的字符串;

method_imp 是指向方法实现的指针。

Method Swizzling 的实质是在运行时,访问对象的方法结构体,并改变它的底层实现。

我们以上节修改 NSArray 的 lastObject 为例做说明。

初始时,lastObject 与 xxx_lastObject 方法的 Method 结构体:

1
2
3
4
5
6
7
8
9
10
11
Method lastObject {
       SEL method_name = @selector(lastObject)
       char *method_types = “v@:“  //返回值void, 参数id(self),selector(_cmd)
       IMP method_imp = 0x000FFFF  //指向([NSArray lastObject])
}
 
Method xxx_lastObject {
        SEL method_name = @selector(swizzle_originalMethodName)
        char *method_types = “v@:”
        IMP method_imp = 0x1234AABA  //指向([NSArray xxx_lastObject])
}

调用 void method_exchangeImplementations(Method m1, Method m2) ,交换两者的实现:

1
2
3
Method ori_Method =  class_getInstanceMethod([NSArray class], @selector(lastObject));
Method my_Method = class_getInstanceMethod([NSArray class], @selector(xxx_lastObject));
method_exchangeImplementations(ori_Method, my_Method);

调换后的 Method 结构体:

1
2
3
4
5
6
7
8
9
10
11
Method lastObject {
       SEL method_name = @selector(lastObject)
       char *method_types = “@@:“  //返回值id, 参数id(self),selector(_cmd)
       IMP method_imp = 0x1234AABA  //指向([NSArray xxx_lastObject])
}
 
Method xxx_lastObject {
        SEL method_name = @selector(swizzle_originalMethodName)
        char *method_types = “@@:”
        IMP method_imp = 0x000FFFF  //指向([NSArray lastObject])
}

可以看到使用void method_exchangeImplementations(Method m1, Method m2)的实质是交换了xxx_lastObject 与 lastObject 的 IMP,实现了在运行时做方法的替换。使得当执行 [array lastObject] 的时候,实际会去执行 [array xxx_lastObject] 的方法实现。

用处

Method Swizzling 非常强大,主要作用有 * 修改 iOS 系统类库的方法 * 动态添加、修改方法,修复线上 bug(如果 Apple 官方允许的话)

其他提示

+load

Swizzling 的处理,在类的 +load 方法中完成。

因为 +load 方法会在类被添加到 OC 运行时执行,保证了 Swizzling 方法的及时处理。

dispatch_once

Swizzling 的处理,dispatch_once 中完成。保证只执行一次。

prefix

Swizzling 方法添加前缀,避免方法名称冲突。




  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
目录 1. 开始 . 4 1.1.1.1. 基本设置 基本设置 . 4 建立你的 建立你的 SwiftSwift 环境 . 5 理解 SwiftSwift 导入过程 导入过程 . 6 2. 互用性 互用性 . 7 2.1. 2.1. 与 Objective ObjectiveObjective Objective Objective-C API 交互 7 初始化 (Initialization)(Initialization) (Initialization) (Initialization) (Initialization) (Initialization)(Initialization)(Initialization)(Initialization) (Initialization) 7 访问属性 访问属性 (Accessing Properties)(Accessing Properties) (Accessing Properties) (Accessing Properties) (Accessing Properties)(Accessing Properties) (Accessing Properties)(Accessing Properties)(Accessing Properties)(Accessing Properties) (Accessing Properties)(Accessing Properties) (Accessing Properties) . 8 方法 (Working with Methods)(Working with Methods)(Working with Methods)(Working with Methods)(Working with Methods) (Working with Methods) (Working with Methods) (Working with Methods) (Working with Methods) (Working with Methods) (Working with Methods) (Working with Methods) . 9 id 兼容性 兼容性 (id Compatibility)(id Compatibility) (id Compatibility)(id Compatibility) (id Compatibility)(id Compatibility) (id Compatibility)(id Compatibility) (id Compatibility) (id Compatibility) (id Compatibility) 10 使用 nil (Working with nilWorking with nilWorking with nilWorking with nil Working with nil Working with nil Working with nil Working with nil ) . 11 扩展( Extensions Extensions Extensions Extensions ) . 12 闭包( Closures ClosuresClosures Closures ) . 13 比较对象( 比较对象( Object Comparison Object Comparison Object Comparison Object Comparison Object ComparisonObject ComparisonObject ComparisonObject ComparisonObject Comparison) 14 SwiftSwift 类型兼容性( 类型兼容性( 类型兼容性( Swift Type CompatibilitySwift Type Compatibility Swift Type Compatibility Swift Type CompatibilitySwift Type Compatibility Swift Type Compatibility Swift Type CompatibilitySwift Type Compatibility Swift Type Compatibility Swift Type Compatibility Swift Type Compatibility) . 14 Objective Objective Objective Objective-C选择器 选择器 (Selectors)(Selectors)(Selectors) (Selectors)(Selectors)(Selectors)(Selectors) 15 2.2. 2.2. 使用 Objective Objective Objective Objective-C特性编写 特性编写 SwiftSwift 类 16 继承 Objective ObjectiveObjective Objective Objective-C的类 16 采用协议 采用协议 . 17 编写构造器 和析编写构造器 和析编写构造器 和析编写构造器 和析 . 17 集成 Interface Builder Interface BuilderInterface Builder Interface BuilderInterface Builder Interface Builder Interface Builder Interface Builder Interface Builder . 18 指明属性 特指明属性 特指明属性 特 . 19 实现 Core Data Managed Object Subclasses Core Data Managed Object SubclassesCore Data Managed Object SubclassesCore Data Managed Object Subclasses Core Data Managed Object SubclassesCore Data Managed Object Subclasses Core Data Managed Object Subclasses Core Data Managed Object Subclasses Core Data Managed Object Subclasses Core Data Managed Object Subclasses Core Data Managed Object SubclassesCore Data Managed Object Subclasses Core Data Managed Object Subclasses Core Data Managed Object Subclasses Core Data Managed Object Subclasses Core Data Managed Object SubclassesCore Data Managed Object Subclasses 20 2.3. Cocoa2.3. Cocoa 2.3. Cocoa 2.3. Cocoa2.3. Cocoa2.3. Cocoa数据类型 数据类型 . 20 字符串 . 21 数字 . 22 类集合 . 22 FoundationFoundationFoundation Foundation FoundationFoundation Foundation数据类型 . 24 FoundationFoundationFoundation Foundation FoundationFoundation Foundation函数 . 25 Core Foundation Core FoundationCore FoundationCore Foundation Core FoundationCore Foundation Core Foundation Core FoundationCore Foundation Core Foundation 25 2.4. 2.4. 采用 Cocoa CocoaCocoaCocoa设计模式 设计模式 . 27 委托 . 27 延迟初始化 延迟初始化 . 28 错误报告 错误报告 . 28 键值观察 键值观察 . 29 TargetTarget TargetTarget -Action Action Action模式 29 类型匹配与统一规范 类型匹配与统一规范 类型匹配与统一规范 类型匹配与统一规范 . 29 Using Swift with Cocoa and Objective-C 完整中文版(CocoaChina 精校) 3 2.5. 2.5. 与 C 语言交互编程 语言交互编程 语言交互编程 语言交互编程 30 基本数据类型 基本数据类型 基本数据类型 . 30 枚举 . 31 指针 . 32 全局常量 全局常量 . 37 预处理指令 预处理指令 . 37 3.Mix and Match3.Mix and Match 3.Mix and Match 3.Mix and Match 3.Mix and Match3.Mix and Match 3.Mix and Match3.Mix and Match . 39 3.1. 3.1. 在同一工程中使用 在同一工程中使用 在同一工程中使用 在同一工程中使用 SwiftSwift Swift 和 Objective Objective Objective Objective-C . 39 Mix and Match Mix and Match Mix and Match Mix and Match Mix and Match Mix and Match Mix and Match Mix and Match 概述 . 39 在同一个 在同一个 App Target App Target App TargetApp TargetApp TargetApp Target 中进行代码导入 中进行代码导入 中进行代码导入 中进行代码导入 . 40 在同个 在同个 Framework Framework Framework Framework Framework Framework Framework 的 TargetTarget TargetTarget 中导入代码 中导入代码 中导入代码 . 43 将 Swift Swift Swift 导入 Objc Objc . 44 导入外部 导入外部 FramewoFramewoFramewo FramewoFramewoFramework 44 在 Objective Objective Objective Objective-C中使用 中使用 SwiftSwift Swift 45 Product ModuleProduct ModuleProduct ModuleProduct Module Product Module Product Module Product Module Product Module 模块命名 模块命名 . 47 问题解决提示 问题解决提示 问题解决提示 . 47 4. 迁移 . 48 4.1. 4.1. 将 Objective ObjectiveObjective Objective Objective-C代码迁至 代码迁至 代码迁至 SwiftSwift . 48 为你的 为你的 Objective Objective Objective Objective-C代码迁移做好准备 代码迁移做好准备 代码迁移做好准备 代码迁移做好准备 48 迁移过程 迁移过程 . 48 问题解决提示 问题解决提示 问题解决提示 . 50 Using Swift with Cocoa and Objective-C 完整中文版(CocoaChina 精校) 4 1. 开始 1.1.1.1.1.1.1.1.基本 设置 本篇译者: 本篇译者: CreolophusCreolophusCreolophusCreolophus Creolophus Creolophus (githubgithubgithub githubgithub主页 ),敬请勘误。 ),敬请勘误。 ),敬请勘误。 ),敬请勘误。 ),敬请勘误。 重要事项 这篇文章初步介绍了在开发中用到的 API 或技术。苹果公司提供这些信息来帮助您规划本文所说明的技术和接口以用于苹果的产品上。这些信息会改变,并且根据这篇文章所实现的软件应该在最新的操作系统并根据最新的文档测试。本文档的新版本,可能在未来通过技术和 API 的 seeds 版本来提供 Swift 被设计用来无缝兼容 Cocoa 和 Objective-C 。在 Swift 中,你可以使用 Objective-C 的 API(包括系统框架和你自定义的代码),你也可以在 Objective-C中 使用 Swift 的 API。这种兼容性使 Swift 变成了一个简单、方便并且强大的工具集成到你的 Cocoa 应用开发工作流程中。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值