博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
Foundation中的类簇和Swizzle
阅读量:7023 次
发布时间:2019-06-28

本文共 2303 字,大约阅读时间需要 7 分钟。

参考链接:

我们都知道swizzle method在OC中是一种有趣又实用的技巧,现在假设我们想hook掉NSMutableArray的insertObject:atIndex:方法,我们会在NSMutableArray的分类中这样写:

swizzleInstanceMethod([self class], @selector(insertObject:atIndex:), @selector(swizzle_insertObject:atIndex:));复制代码

然而我们会发现虽然swizzle成功了,但是实际上并没有执行swizzle_insertObject:atIndex:方法,这是为什么呢?

我们先写个测试代码:

NSString *nilStr = nil;[[NSMutableArray array] addObject:nilStr];复制代码

看下下面的错误信息:

*** Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: '*** -[__NSArrayM insertObject:atIndex:]: object cannot be nil'复制代码

__NSArrayM 是个什么鬼?这就是导致我们上面swizzle method后,swizzle_insertObject:atIndex:不执行的原因。

再来看以下的打印信息:

(lldb) po [[NSMutableArray alloc] init]<__NSArrayM 0x7fb452e04a20>()(lldb) po [NSMutableArray array]<__NSArrayM 0x7fb452d0ba30>()(lldb) po [NSMutableArray arrayWithObject:@""];<__NSArrayM 0x7fb452d0baf0>()(lldb) po [[NSMutableArray alloc] class]__NSPlaceholderArray(lldb) po [NSArray array]<__NSArray0 0x7fb452d05910>()(lldb) po [[NSArray alloc] init]<__NSArray0 0x7fb452d05910>()(lldb) po @[]<__NSArray0 0x7fb452d05910>()(lldb) po [[NSArray alloc] class]__NSPlaceholderArray(lldb) po [[NSArray alloc] initWithObjects:@"", nil];<__NSArrayI 0x7fb452f059c0>()(lldb) 复制代码

仔细看其中的端倪,

[NSMutableArray array]  // __NSArrayM 类型(mutable)[NSArray array]         // __NSArray0 类型 (空 immutable)[[NSArray alloc] initWithObjects:@"", nil] // __NSArrayI 类型(immutable)[[NSArray alloc] class] // __NSPlaceholderArray[[NSMutableArray alloc] class]  // __NSPlaceholderArray复制代码

可以看出,这些打印的类型是苹果隐藏起来的Array的实际类型,因此我们在文章开头的hook掉的是 [NSMutableArray class] 中的方法,并不是我们真正在项目中调用的 __NSArrayM 的 方法,所以并没有执行我们的swizzle_method。(有个小细节,3种方式打印的空不可变数组__NSArray0指向同一个地址

那该怎么解决这个问题?方法也很简单,现在知道了源方法属于哪个类型,那么我们就对这个类型实用swizzleMethod:

NSMutableArray *mutArray = [NSMutableArray array];swizzleInstanceMethod([mutArray class], @selector(insertObject:atIndex:), @selector(swizzle_insertObject:atIndex:));复制代码

上面还有一个奇怪的类型 __NSPlaceholderArray,这个又是干嘛的,在上面的参考链接中有它的解释,我们这里讨论它和swizzle method有什么关联,其实如果我们想hook掉NSArray的 init 方法的话就需要用到它了,代码如下:

NSArray *placeholderArray = [NSArray alloc];swizzleInstanceMethod([placeholderArray class], @selector(initWithObjects:count:), @selector(swizzle_initWithObjects:count:));复制代码

不止 NSArray,在Foundation中这样的类簇还有 NSDictionaryNSStringNSNumber,所以如果想hook这些类型的方法,就要注意源方法实际属于哪个子类型上。

转载地址:http://zivxl.baihongyu.com/

你可能感兴趣的文章
hadoop零基础系列之一:虚拟机下的Linux集群构建
查看>>
近 100 个 Linux 常用命令大全
查看>>
Bootstrap CSS
查看>>
Entity FrameWork 单表对多实体
查看>>
实验一框架的原因及说明
查看>>
第二次测试
查看>>
c语言编程之栈(链表实现)
查看>>
[leetcode-299-Bulls and Cows]
查看>>
python import
查看>>
hdu 1556 Color the ball
查看>>
第二次作业
查看>>
将用户输入的字符串反向输出到页面上,并且要求将其中的小写字母转换成大写字母。...
查看>>
somatic和germline突变有什么区别
查看>>
Android的TextView使用Html来处理图片显示、字体样式、超链接等
查看>>
python re的findall和finditer
查看>>
Feign 第一个Feign程序 一
查看>>
入门知识
查看>>
configparser 文件的生成和读写
查看>>
20个PHP程序性能优化的方法
查看>>
【BZOJ】3991: [SDOI2015]寻宝游戏 虚树+DFS序+set
查看>>