.
block的本质
__weak与源码编译问题解决
block的类型
根据block存放的位置不同,block分为不同的类型。
block有三种类型,可以通过调用class方法或者isa指针来查看具体类型,最终都是继承自NSblock类型。
不同类型间的拷贝
我们在分析block拷贝的时候,可以把block当作是变量。因为在某些情况下,我们不想让block变量随着函数执行的结束而销毁,这个时候我们就需要把block变量转而存储到堆里面,这个时候就涉及到不同block类型之间的拷贝,这个我们需要详细说的就是栈上的block拷贝到堆上。
会触发block从栈上拷贝到堆上的情况:
ARC下block会赋值到堆上的各种情况。NSGLobalblock的意义不是很大,因为直接就可以把他写成函数。
block变量捕获
block捕获的本质就是block在编译器编译后,其实和原来运行的函数是在两个函数里面,所有捕获的问题都是围绕在不同的函数里访问相同的值的问题,也就是怎样让两个函数都能访问到这个值的问题。
- 局部变量:所以局部变量在auto的时候是值传递,因为局部变量在函数运行结束以后,就会被释放,要捕获值是多少,所以就会导致一个问题就是block里面修改该值不会导致外面的值也更改,因为是值传递。
- static变量:static因为值是一直存在内存中的,但是只有在当前的函数才能访问,所以block捕获的是static的变量的指针,因为值一直存在,所以block中也能修改static修饰的值。
- 全局变量:全局变量因为作用域在整个项目中,所有即使是编译以后是不同的函数,所有的函数都可以直接访问它,所以block也不需要对这种情况进行值捕获。
从上面的总结我们可以看到,static和全局变量的变量,因为随着函数的结束并不会销毁,所以在捕获的时候不涉及到太多的考虑,直接捕获到他们的指针即可。但是auto变量值在函数的结束而销毁,所以block需要单独处理这种情况。
变量前面没有任何修饰符的时候,默认就是auto类型。
auto变量的捕获
当我们不给block外部的变量加任何修饰符的时候,默认就是auto类型。不管是对象类型还是值类型,都是值捕获(值捕获可以理解为值拷贝),也就是block内部修改改变量都无法导致外面的变量跟着一起修改。但是是对象类型的时候,其实你捕获的是指向这个对象的指针,你修改block内的指针指向无法导致外部的指针也跟着指向新的对象,但是你是可以修改对象内容的,因为你和外面的指针变量都指向了相同的对象。既然两个指针都指向了相同的对象,那么block内部的指针不会增加block的引用计数呢?
__block修饰符
根据上面auto变量的捕获
章节,我们知道block在捕获auto变量的时候,是值拷贝。那如果我们就是想达到block内部的修改,也会导致外面变量内容的修改呢?这时候我们就需要用到__block
修饰符。
__block无法修饰全局变量和静态变量。