Block内部的数据结构类型

本文会记录下最近对B lock 的一些探究,先从 block 是如何对局部变量捕获开始讲起.

image.png

上边的代码 auto变量的值改变时,block 内部输出结果还是10,而 static 的局部变量 值变成了50. 那么 block 内部是如何对age height 进行处理的呢?

可以通过 xcrun -sdk phones clang -arch arm64 -rewrite-objc main.c -o main.cpp 将OC代码转成C++代码实现

void testBlock() {
    auto int age = 10;
    static int height = 100;
    void(*block)(void) = &__testBlock_block_impl_0(
                                                   &__testBlock_block_func_0,
                                                   &__testBlock_block_desc_0_DATA, age, &height));
    age = 20;
    height = 50;
    block->FuncPtr(block);
    
    __testBlock_block_func_0  block实现部分的代码
    __testBlock_block_desc_0_DATA block 内存占用大小 描述信息
    
    __testBlock_block_impl_0 构造方法 返回一个  __testBlock_block_impl_0 结构体对象 并且取地址 复制给 *block 变量
    block->FuncPtr 实质就是 block->impl.FuncPtr 由于结构体内部第一个成员就是该结构体的内存地址 ,所以 __testBlock_block_impl_0 可以看成 __block_impl 因为它的指针地址就是指向第一个成员 __block_impl的地址 ,所以通过强制转换后 可以  block->FuncPtr(block); 调用 block
}

上边的代码还可以简化为


void testBlock() {
    auto int age = 10;
    static int height = 100;
    void(*block)(void) = &__testBlock_block_impl_0(__testBlock_block_func_0, &__testBlock_block_desc_0_DATA, age, &height));
    age = 20;
    height = 50;
  block->FuncPtr(block);  调用 block对应的函数指针 

__testBlock_block_func_0 ///block 代码的实现 相当于一个函数变量

}

我们写的block 最终被转成一个 struct __testBlock_block_impl_0 结构体 ,并将 block 快代码方法实现 封装到一个 __block_impl 结构体里的 void *FuncPtr;
以下对 block 的数据类型进行详细的说明

struct __testBlock_block_impl_0 {
  struct __block_impl impl; ///block函数回调 和 调用环境
  struct __testBlock_block_desc_0* Desc; ///描述了 block 占用多少内存
  int age; ///对局部变量age的捕获
  int *height;  ///对局部变量height的捕获
///结构体构造方法 会对结构体内部所有成员进行赋值 相当于 init方法 
  __testBlock_block_impl_0(void *fp, struct __testBlock_block_desc_0 *desc, int _age, int *_height, int flags=0) : age(_age), height(_height) {
    impl.isa = &_NSConcreteStackBlock; ///block 内部 isa 指针 block 实质就是一个OC对象 封装了函数调用和函数调用的环境 
    impl.Flags = flags;
    impl.FuncPtr = fp; /// 函数指针 我们 block 里边的实现代码 都保存到这个函数地址里 ,将来执行 block 代码块 就是执行函数指针指向的函数实现
    Desc = desc; ///对 block 大小的描述
  }
};

auto变量 随用随开用完即销 因此 block 捕获 auto 变量时 只把值传递进去进来了保存 ,当 auto 变量销毁的时候 也不影响 block 内部对这个 auto 变量的使用.

static局部变量 并不随着函数作用域结束而销毁 它会一直存在内存中直到程序声明周期结束才释放掉,因此 block 对局部静态变量的捕获是以指针地址进行传递,由于是指针赋值而不是值传递 所以 height 改变时 block 内部输出的值时最新的 height 的值.

这个函数封装了 block代码的实现 即 ^{
NSLog(@"age = %d height = %d",age,height);
};
由FuncPtr 函数指针调用该函数


static void __testBlock_block_func_0(struct __testBlock_block_impl_0 *__cself) {
  int age = __cself->age; // bound by copy
  int *height = __cself->height; // bound by copy

  NSLog((NSString *)&__NSConstantStringImpl__var_folders_hj_pwgsq9614nb0vq4zd315tcx80000gn_T_main_a95244_mi_0,age,(*height));
 }

还可以将 block 强制转换成 __block_impl 结构体 进行函数的调用

image.png

输出结果跟 block() 是一样的

由于 block 内部会对局部变量进行捕获 所以就会造成循环引用的问题 ,比如 self 持有 block ,而 block 内部会使用到 self ,这种情况下就会造成 block 和OC对象内存泄露问题

image.png

OC的方法能够使用到 self _cmd 是因为有两个 匿名参数 id self , SEL _cmd ,所以 self 在方法里边也是一个局部的变量 这个时候 block 就会捕获这个 self ,而 self 又持有 block 因此造成了循环引用 我们通过C++代码一探究竟

image.png
image.png

可以看出来 block 内部有一个Person *self 的指针 , 在给 block 赋值的时候 将 self 的内存地址传递进去 ,这样就造成了 互相持有,所以 block 使用过程中需要注意循环引用的问题

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 216,544评论 6 501
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 92,430评论 3 392
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 162,764评论 0 353
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 58,193评论 1 292
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 67,216评论 6 388
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 51,182评论 1 299
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 40,063评论 3 418
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 38,917评论 0 274
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 45,329评论 1 310
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,543评论 2 332
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,722评论 1 348
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,425评论 5 343
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 41,019评论 3 326
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,671评论 0 22
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,825评论 1 269
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 47,729评论 2 368
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,614评论 2 353

推荐阅读更多精彩内容