objective c下的block模型
2016-01-05 15:14
495 查看
前言
通过clang将objective c代码翻译成cpp代码,阅读代码的实现去理解objc中block模型。objective c代码
#import <Foundation/Foundation.h> void foo_() { int i = 2; NSNumber *num = @3; long (^myBlock)(void) = ^long() { return i * num.intValue; }; long r = myBlock(); }
clang翻译objective c代码块
clang -rewrite-objc block.m
Objective c的block模型
首先我们简化一下cpp代码,大致如下:struct __block_impl { void *isa; int Flags; int Reserved; void *FuncPtr; }; static struct __foo__block_desc_0 { size_t reserved; size_t Block_size; void (*copy)(struct __foo__block_impl_0*, struct __foo__block_impl_0*); void (*dispose)(struct __foo__block_impl_0*); } __foo__block_desc_0_DATA = { 0, sizeof(struct __foo__block_impl_0), __foo__block_copy_0, __foo__block_dispose_0}; struct __foo__block_impl_0 { struct __block_impl impl; struct __foo__block_desc_0* Desc; int i; NSNumber *num; __foo__block_impl_0(void *fp, struct __foo__block_desc_0 *desc, int _i, NSNumber *_num, int flags=0) : i(_i), num(_num) { impl.isa = &_NSConcreteStackBlock; impl.Flags = flags; impl.FuncPtr = fp; Desc = desc; } }; static long __foo__block_func_0(struct __foo__block_impl_0 *__cself) { int i = __cself->i; // bound by copy NSNumber *num = __cself->num; // bound by copy return i * ((int (*)(id, SEL))(void *)objc_msgSend)((id)num, sel_registerName("intValue")); } void foo_(){ int i = 2; NSNumber *num = ((NSNumber *(*)(id, SEL, int))(void *)objc_msgSend)(objc_getClass("NSNumber"), sel_registerName("numberWithInt:"), 3); long (*myBlock)(void) = ( (long (*)()) & __foo__block_impl_0((void *)__foo__block_func_0, &__foo__block_desc_0_DATA, i, num, 570425344)); long r = ( (long (*)(__block_impl *)) ((__block_impl *)myBlock)->FuncPtr)((__block_impl *)myBlock); }
myBlock对象:在转换过后被转换为结构体struct __foo__block_impl_0,而struct __foo__block_impl_0结构体中含有isa指针,实际上它是一个对象,说明block其实是一个对象,有不同的存储形式,而在struct __foo__block_impl_0中有一句:impl.isa = &_NSConcreteStackBlock; 说明上述代码中myBlock对象实际上是存储在stack上的对象。
foo_函数: 在转换过后形成静态函数static long __foo__block_func_0,函数的参数正是myBlock对象,在long __foo__block_func_0函数中直接操作myBlock对象的属性。
如果我们在myBlcok中修改i或者num的值,编译器会提示警告,通过struct __foo__block_impl_0的狗仔函数__foo__block_impl_0(void *fp, struct __foo__block_desc_0 *desc, int _i, NSNumber *_num, int flags=0) : i(_i), num(_num),可以看出实际上
4000
i和num值实际上赋值给了myBlock对象,所以在myBlock里面修改i或者num的值,修改的是block的成员变量,而不是通过参数传递进来的i,num,实际上就是c语法中的传递值和指针的区别。
这么说如果我们想修改i的值,参数传递指针就可以了嘛,说的没错,继续往下看你。
在block中如果我们想要修改 block外的值,只需要在值申明之前加上__block关键字即可。
下面接着分析含有__block变量的block模型
objective c代码
#import <Foundation/Foundation.h> void foo_(){ __block int i = 2; NSNumber *num = @3; long (^myBlock)(void) = ^long() { return i * num.intValue; }; long r = myBlock(); }
clang翻译objective c代码块
clang -rewrite-objc block2.m
Objective c的block模型
struct __Block_byref_i_0 { void *__isa; __Block_byref_i_0 *__forwarding; int __flags; int __size; int i; }; struct __foo__block_impl_0 { struct __block_impl impl; struct __foo__block_desc_0* Desc; NSNumber *num; __Block_byref_i_0 *i; // by ref __foo__block_impl_0(void *fp, struct __foo__block_desc_0 *desc, NSNumber *_num, __Block_byref_i_0 *_i, int flags=0) : num(_num), i(_i->__forwarding) { impl.isa = &_NSConcreteStackBlock; impl.Flags = flags; impl.FuncPtr = fp; Desc = desc; } }; struct __block_impl { void *isa; int Flags; int Reserved; void *FuncPtr; }; static long __foo__block_func_0(struct __foo__block_impl_0 *__cself) { __Block_byref_i_0 *i = __cself->i; // bound by ref NSNumber *num = __cself->num; // bound by copy return (i->__forwarding->i) * ((int (*)(id, SEL))(void *)objc_msgSend)((id)num, sel_registerName("intValue")); } void foo_(){ __attribute__((__blocks__(byref))) __Block_byref_i_0 i = {(void*)0,(__Block_byref_i_0 *)&i, 0, sizeof(__Block_byref_i_0), 2}; NSNumber *num = ((NSNumber *(*)(id, SEL, int))(void *)objc_msgSend)(objc_getClass("NSNumber"), sel_registerName("numberWithInt:"), 3); long (*myBlock)(void) = ((long (*)())&__foo__block_impl_0((void *)__foo__block_func_0, &__foo__block_desc_0_DATA, num, (__Block_byref_i_0 *)&i, 570425344)); long r = ((long (*)(__block_impl *))((__block_impl *)myBlock)->FuncPtr)((__block_impl *)myBlock); }
myBlock对象:在转换过后被转换为结构体struct __foo__block_impl_0,不同于前面,多了一个__Block_byref_i_0的结构体,用来保存i的值
这里多了一个__Block_byref_i_0的结构体,而__Block_byref_i_0的结构体实际上也是一个对象,含有isa指针,在__foo__block_impl_0的构造函数中传递的是__Block_byref_i_0的指针,这样我们就可以直接在myBlock中对i的值进行修改,正如我们前面提到的指针传递。
希望通过本文,可以加深你对objective c的block模型的理解,如有错误,请提出,我会及时改正,大家共同学习。
相关文章推荐
- WaitForMultipleObjects返回错误码87
- JsonArray和JsonObject的使用
- Objective-C获取应用是否允许消息通知的方法
- Objective C运行时(runtime)技术的几个要点总结
- Objective-C汉字转换成拼音的方法
- Objective-C语法概述
- Objective-C语法概述
- hbuider 中点击就显示出一个单选的列表 ,然后后台跨域向里面动态添加数据,注意里面的格式是json object
- Photos(PHObject)
- Objective-C之内存管理
- Objective-C利用AFN实现图片下载,支持断点续传,显示下载进度
- setObjectForKey和setValueForKey的用法和区别
- Jsp中request.getParameter("@param")值为[object HTMLInputElement]
- 通知中心(NSNotificationCenter)
- 论文笔记:Faster R-CNN:Towards Real-Time Object Detection with Region Proposal Networks
- RegExp Object
- 151220ObjectDemo
- Objective-C 内存管理机制
- objective-c 我的美图软件
- OObjective-c 二维码(第三方库ZXing)