在微信上做网站,黑龙江建设人力资源网站,牡丹菏泽网站建设,网图素材库来源http://www.wtoutiao.com/p/11dgbk4.html 先来简单介绍一下Block Block是什么#xff1f; 苹果推荐的类型#xff0c;效率高#xff0c;在运行中保存代码。用来封装和保存代码#xff0c;有点像函数#xff0c;Block可以在任何时候执行。 Block和函数的相似性#xf… 来源http://www.wtoutiao.com/p/11dgbk4.html 先来简单介绍一下Block Block是什么 苹果推荐的类型效率高在运行中保存代码。用来封装和保存代码有点像函数Block可以在任何时候执行。 Block和函数的相似性1可以保存代码2有返回值3有形参4调用方式一样。 Block 底层实现 定义一个简单的block 我们再给a赋值为20此时打印出来a 的值还是10 但当我们在第一次给a 赋值时前面加上__block 的时候则打印出来20。 那么为什么加上__block 后 就打印出20了呢这个原理是什么呢 其实可以用两个词来概括传值 和传址。 可能这样说大家觉得有点扯接下来 用C 代码进行编译。 打开终端做如下操作 在当前文件夹下会得到一个.cpp 文件。 此时打开当前的.cpp 文件(会有差不多10万行代码)前面我们都忽略只需要滚动到最后此时你会发现block跟OC中的变化。 接下来我们一个个来看这个block先来看等号左边的。 void(*block)() 这是一个没有参数没有返回值的函数指针既然是一个函数指针那它就是一个变量变量里面只能保存函数地址然后它又在等号的左边是不是意味着右边返回的是一个函数地址(自己推断)。 再看等号右边 ((void (*)())__main_block_impl_0((void *)__main_block_func_0, __main_block_desc_0_DATA, a)); 参数(自我推断) ((void (*)()) 强转(自己理解其实没有实际含义不影响自己本身的类型) 取址 后面都是函数的调用如果不是也不会得到一个函数指针的。 __main_block_impl_0 这是一个函数名这个函数有三个参数 comF 搜索一下又会发现这是一个结构体结构体如下 struct __main_block_impl_0 {struct __block_impl impl;struct __main_block_desc_0* Desc;int a; 可能你会疑惑刚刚说这是一个函数而现在是一个结构体。其实在 c 里面结构体相当于OC的类c 里面结构体拥有自己的属性以及构造方法和方法。那么为什么取一个结构体的地址呢 其实它取得是下面这段代码的地址 __main_block_impl_0(void *fp, struct __main_block_desc_0 *desc, int _a, int flags0) : a(_a) {impl.isa _NSConcreteStackBlock;impl.Flags flags;impl.FuncPtr fp;Desc desc;} 那么在上面个方法实现里又有四个参数。而在刚刚调用的时候只有三个参数多了一个参数 flags 0这个参数其实就相当于Swift中指定了一个默认值不传也有值可以忽略。那么后面继续 a(_a) : 在 c 里面 指定_a(形参) 将来赋值给a 这个实参也就是这个__main_block_impl_0 结构体中的 int a;在这里 int a 10; impl.FuncPtr fp; 将fp赋值给了 impl 结构体的 FuncPtr 参数, 在这个参数里面存放的是下面这段代码的地址 static void __main_block_func_0(struct __main_block_impl_0 *__cself) {int a __cself-a; // 这里 int a 10;printf(%d\\\\\\\\n,a); // 打印出a}__main_block_desc_0_DATA com F 搜索 定义的就是与大小相关的信息代码如下static struct __main_block_desc_0 {size_t reserved;size_t Block_size;} __main_block_desc_0_DATA { 0, sizeof(struct __main_block_impl_0)}; a 直接放a 其实就相当于把a 当前的值拿过来如果是a, 就是a的地址。请看下图 接下来又重新给 a赋值为 20但是Block 最终要找到 FuncPtr 里面存放的是值来执行 在这里才会最终执行打印a 的值的代码但是这段代码里 a 是 10 了。所以最终打印的还是10。 最后可以概括为block 底层实现 分两种刚刚上面的就是第一种不加__block), 会创建一个结构体实现构造方法来接收三个参数。 接下来看加上__block 的实现。 修改我们的代码: 再次在终端里面进行编译你会发现生成的结构体会变化。 等号左边会封装一个__Block_byref_a_0 结构体类型的变量a下面是结构体的声明 truct __Block_byref_a_0 {void *__isa; //isa 类型的指针 自己的类型__Block_byref_a_0 *__forwarding; //与自己结构体同名是一个自己类型的结构体的指针存放的是自己的地址int __flags; // 标记int __size; // 类型的大小int a; // a 属性 保存变量的值}; 等号右边 {(void*)0,(__Block_byref_a_0 *)a, 0, sizeof(__Block_byref_a_0), 10}; 参数 (void*)0 : 一个指针直接存到isa里面(__Block_byref_a_0 *)a: 强转 存放的是自己的地址0 : 会传给 flagssizeof(__Block_byref_a_0), 10: 类型的大小10: a 的值 仅仅是创建。 这 里仅仅是创建因为使用了__block 所以创建了一个block 类型的结构体接下来会才是调用block你会发现其余参数和第一种实现都一样唯一不同的是再去取值的时候拿到的是结构体的地址只要把地址传递过 去就有了最高的操作权限到时候再去取值就可以取到内存中最新的值。 接下来(a.__forwarding-a) 20; 这句代码是拿到结构体里面的地址去修改a的值为20。 后面再去打印打印的就是内存地址中最新的值所以就是20。 作者Liwjing
地址http://www.jianshu.com/users/8df89a9d8380/latest_articles 转载于:https://www.cnblogs.com/sundaysgarden/p/5602456.html