博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
Block深入学习,授人以渔。—— Block与各种变量
阅读量:7098 次
发布时间:2019-06-28

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

前言

Block的文章看了很多,但是都不得要领。最近看了霜神的文章(https://juejin.im/post/57ccab0ba22b9d006ba26de1),然后又重读了一遍《Objective-C高级编程》,根据文章和书中的内容,用clang把OC转成C,然后才懂了很多原来似是而非的问题。

欢迎讨论,更欢迎大佬指点。

怎么才能真正了解Block

1.知道clang的几个指令

2.有C的基础

3.亲自动手去试

需要用到的clang指令与操作 我是先转c文件,看的差不多了,然后转oc文件。循序渐进。

0.cd 进入目标文件的文件夹 clang -rewrite-objc xxxx.c 在文件夹下找.cpp文件 建议先用c文件来尝试。

1.cd 进入目标文件的文件夹clang -x objective-c -rewrite-objc -isysroot /Applications/Xcode.app/Contents/Developer/Platforms/iPhoneSimulator.platform/Developer/SDKs/iPhoneSimulator.sdk xxx.m xxx是OC文件的名。

先创建一个c文件 写如下代码

int test(void){     void (^studyBlock)(void) = ^{     printf("这是 studyBlock");};studyBlock();}复制代码

**通过clang -rewrite-objc xxxx.c 得到了一个接近600行的cpp文件。很多代码是与Block无关的。相关代码如下:请注意区分大小写。

//Block 结构体 相当于Foundation框架中的NSObject对象,因为有isa指针,所以Block也可看做对象的一种。;struct __block_impl { void *isa;  int Flags;  int Reserved; void *FuncPtr;};//这是我们声明的block( void(^block)(void) ),这是一个block声明,转换完之后代码有这么多。。struct __test_block_impl_0 {    struct __block_impl impl;    struct __test_block_desc_0* Desc;    __test_block_impl_0(void *fp, struct __test_block_desc_0 *desc, int flags=0) {  impl.isa = &_NSConcreteStackBlock;  impl.Flags = flags;  impl.FuncPtr = fp;  Desc = desc;  }};//studyBlock体中的内容^{ printf("这是 studyBlock"); };static void __test_block_func_0(struct __test_block_impl_0 *__cself) {    printf("这是 studyBlock");}//每个Block转化之后都有这样的结构体,用于记录版本和大小static struct __test_block_desc_0 {    size_t reserved;    size_t Block_size;} __test_block_desc_0_DATA = { 0, sizeof(struct __test_block_impl_0)};int test(void){    //studyBlock调用 studyBlock();     void (*studyBlock)(void) = ((void (*)())&__test_block_impl_0((void *)__test_block_func_0, &__test_block_desc_0_DATA));    ((void (*)(__block_impl *))((__block_impl *)studyBlock)->FuncPtr)((__block_impl *)studyBlock);  return 0;}复制代码

好了现在知道了 Block的真面目了。下面加入一些变量。代码如下。

//加入了全局变量 全局静态变量 局部静态变量 __block变量 局部变量(自动变量)int globelVal = 0;static int staticGlobelVal = 1;int test(void){     static int staticVal = 2;     __block int blockVal = 3;     int val = 4;     void (^studyBlock)(void) = ^{            printf("%d===%d===%d===%d===%d",globelVal,staticGlobelVal,staticVal,blockVal,val);        };     studyBlock();     return 0;}复制代码

代码很少 也很好理解,下面我们转换一下

struct __block_impl {     void *isa;     int Flags;     int Reserved;     void *FuncPtr; }; int globelVal = 0; static int staticGlobelVal = 1;     //__block类型的变量 //结构体中的 isa指针,指向原变量isa,用于保存变量类型。 //__Block_byref_blockVal_0 。__Block_byref_blockVal_0结构中的__Block_byref_blockVal_0。为什么要有这样的结构呢。是因为Block有可能从栈中复制到堆中。 //当Block从栈中复制到堆中,结构体中的__forwarding指向栈中的__Block_byref_blockVal_0结构体。然后通过__forwarding->blockVal来操作变量的值。 //如果没有复制到栈中的操作。__forwarding指向栈中的__Block_byref_blockVal_0结构体。 struct __Block_byref_blockVal_0 {     void *__isa;     __Block_byref_blockVal_0 *__forwarding;     int __flags;     int __size;     int blockVal; }; struct __test_block_impl_0 {     struct __block_impl impl;     struct __test_block_desc_0* Desc;     //我们可以看到静态局部变量和局部变量的区别了。     //静态局部变量被引入studyBlock结构体的时候,是通过指针的方式引入的。通过指针可以修改内存中该变量的值。那么再看局部变量,只是一个值被引入了,所以不能修改局部变量的值。     //__Block_byref_blockVal_0 *blockVal;这个是__blockVal;     //被引入studyBlock结构体之后,变成了一个__Block_byref_blockVal_0型的结构体变量。     int *staticVal;     int val;     __Block_byref_blockVal_0 *blockVal; // by ref     __test_block_impl_0(void *fp, struct __test_block_desc_0 *desc, int *_staticVal, int _val, __Block_byref_blockVal_0 *_blockVal, int flags=0) : staticVal(_staticVal), val(_val), blockVal(_blockVal->__forwarding) {     impl.isa = &_NSConcreteStackBlock;     mpl.Flags = flags;     impl.FuncPtr = fp;     Desc = desc;    }}; static void __test_block_func_0(struct __test_block_impl_0 *__cself) {     __Block_byref_blockVal_0 *blockVal = __cself->blockVal; // bound by ref     int *staticVal = __cself->staticVal; // bound by copy     int val = __cself->val; // bound by copy     printf("%d===%d===%d===%d===%d",globelVal,staticGlobelVal,(*staticVal),(blockVal->__forwarding->blockVal),val);} static void __test_block_copy_0(struct __test_block_impl_0*dst, struct __test_block_impl_0*src) {_Block_object_assign((void*)&dst->blockVal, (void*)src->blockVal, 8/*BLOCK_FIELD_IS_BYREF*/);} static void __test_block_dispose_0(struct __test_block_impl_0*src) {_Block_object_dispose((void*)src->blockVal, 8/*BLOCK_FIELD_IS_BYREF*/);} static struct __test_block_desc_0 {     size_t reserved;     size_t Block_size;     void (*copy)(struct __test_block_impl_0*, struct __test_block_impl_0*);     void (*dispose)(struct __test_block_impl_0*); } __test_block_desc_0_DATA = { 0, sizeof(struct __test_block_impl_0), __test_block_copy_0, __test_block_dispose_0};   int test(void){     static int staticVal = 2;     __attribute__((__blocks__(byref))) __Block_byref_blockVal_0 blockVal = {(void*)0,(__Block_byref_blockVal_0 *)&blockVal, 0, sizeof(__Block_byref_blockVal_0), 3};     int val = 4;     void (*studyBlock)(void) = ((void (*)())&__test_block_impl_0((void *)__test_block_func_0, &__test_block_desc_0_DATA, &staticVal, val, (__Block_byref_blockVal_0 *)&blockVal, 570425344));     ((void (*)(__block_impl *))((__block_impl *)studyBlock)->FuncPtr)((__block_impl *)studyBlock);return 0;}复制代码

补充 Block的isa指针分为三种类型。_NSConcreteStackBlock栈。_NSConcreteGlobalBlock数据区。_NSConcreteMallocBlock堆。

课后题

1.为什么普通变量不能再Block中修改。

2.Block分为几种类型

3.__block类型为什么能够在Block中修改值。

下一节 探究weakSelf,strongSelf。

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

你可能感兴趣的文章
决心书
查看>>
搭建DNS域名解析
查看>>
linux下解压zip文件
查看>>
动态路由实现OSPF和RIP协议实现全网互连互通
查看>>
根据Fragment布局高度来自动适应的Viewpager
查看>>
“互联网+”时代,办公必“上云”?
查看>>
如何快速将Excel表格转换成PDF
查看>>
云计算在未来一年的发展预测
查看>>
kafka实战
查看>>
服务器常用命令及使用
查看>>
报错:Socket connection closed by the other side (how rude!)
查看>>
iOS之RunLoop
查看>>
去除titleBar
查看>>
CentOS下快速yum安装LAMP环境
查看>>
sysbench-0.5的安装和做性能测试
查看>>
Linux内核调优部分参数说明
查看>>
Linux之部署Zabbix监控系统
查看>>
Sharepoint 2013 整合 Office Web Apps Server 2013
查看>>
gcc 不支持__attribute__((naked)
查看>>
C语言基础之类型,运算符,表达式
查看>>