大家经常说blcok是个结构体,每次看到都一堆编译成类c++代码。看着还是很难受。时间久了会不会自己迷糊了。一堆抽象的东西很难受。过一段时间可能忘记了。(现在的面试就有点像应试考试一样。没有实践,没有深入了解)
在我看来block就只有两种一种是在栈上的,一种在全局区。
NSConcreteGlobalBlock 全局
NSConcreteStackBlock 栈上
NSConcreteMallocBlock 堆上(现在我基本没遇到过直接可以创建,由NSConcreteStackBlock copy,产生)
既然结构体能在栈上生成么什么异议了。但是也能在堆上创建,但是NSConcreteMallocBlock在堆上的目前我还是没见到的。
(题话外,object-c 类本质是结构体,苹果却上让他直接alloc new 在堆上(既然是结构体肯定能在栈上))。
所以,今天我们直接来 NSConcreteGlobalBlock和NSConcreteStackBlock就够了。
也许大家在用Hopper找一个block函数地址非常头疼,今天看完这个你就不会头疼了。我们就是从hopper里面看block的。
先来个非常的简单的NSConcreteGlobalBlock
self.test1 = ^{
NSLog(@"2222");
};
NSLog(@"block: self.test1 class is %@",[self.test1 class]);
打印结果:
2018-12-03 12:21:53.993461+0800 3333[40992:2030730] block: self.test1 class is __NSGlobalBlock__
Hopper反汇编代码:
WX20181203-123204@2x.png我们只要看___block_literal_global就够了,点击去看看:
WX20181203-122905@2x.png这个第三行0x0000000100001250就是代码函数地址(未在程序载入偏移后),就是代码段的偏移地址,点进去找到看看就是了
WX20181203-122709@2x.png
画红线的地方是不是上文的地方对应上了,
最后一个参数就是描述结构体,这个不用看了。
————————————————————————————
下面来看看NSConcreteStackBlock的这个有点难,
代码:
__weak typeof(self)weakself = self;
void (^pp)(void) = ^{
NSLog(@"1111");
NSLog(@"%@",weakself);
};
NSLog(@"block: pp class is %@",[pp class]);
pp();
打印结果:
2018-12-03 12:37:13.176667+0800 3333[41749:2041280] block: pp class is __NSStackBlock__
为了更好演示查看别的代码和分析NSConcreteStackBlock,我选择不生成符号变文件和采用release模式来编译这样产生文件
WX20181203-124641@2x.png WX20181203-124712@2x.png
在用Hopper查看:
WX20181203-125742@2x.pngobjc_initWeak 是weakself 的实现。
点0x100008008进去
WX20181203-125935@2x.png
这个玩意就是stackBlock的。被储存在sp+x10的位置
紧接着是0x100007dc0这个地址,进去你会发现这是会初始化的flag,在全局区。被存储sp+0x18的位置了,和上面只相差8字节,不截图了。从寄存器来看,他只占有2个字节。
在往下看0x100006654,储存在sp+0x20的位置,点进去才发现这是Block要调用的函数
是不是上下文地址对上了。
下面还有还有个地址0x100008100,是blcok的相关描述。这里不用管了。
从这个分析过程来看stackBlock是在栈区一块连续的内存,依次储存:
&NSConcreteStackBlock,
flag,
funck(blcok要调用的函数),
block相关表述结构体
至于堆上的blcok就是栈上copy过去,并不能直接创建,这里不做研究。
希望这篇文章对你找blcok要调用函数的函数地址有帮助。
好久都没时间来写东西了,现在把这东西抽空写出来了。
尊重别人的劳动成果,请不要随便拿去夸夸其谈
demo:https://github.com/LoveSVN/block-Explore
网友评论