先看下block直接访问auto基本数据类型
![](https://img.haomeiwen.com/i5748238/4b450704bf63a006.png)
![](https://img.haomeiwen.com/i5748238/7320b1edc7b9f32f.png)
可以看到block内部访问外部auto变量时,会在block内部定义一个新的const只读变量来保存外部变量的值,两个独立的变量,互补干扰,而且内部的height是在堆上,外面的height变量是在栈上,调用block时是到__main_block_impl_0结构体中取出的height变量的值进行打印,所以外部不管怎么修改对block内部的height变量都不会造成影响,至于block内部的height变量设置为只读,这里猜测是苹果为了代码的可读性和维护性,如果设置为读写,那么会造成block函数栈中可以访问main函数中的局部变量,这样肯定是不被允许的。
再看下block内部访问外部__block修饰的基本数据类型
![](https://img.haomeiwen.com/i5748238/95c7ac62e98ae6da.png)
![](https://img.haomeiwen.com/i5748238/080d553e7c4577a8.png)
这里面的__main_block_desc_0结构体其实也发生变化了,和访问外部对象类型的时候差不多,可以查看这里
可以看到__block定义的变量刚开始是在栈上的,当block内部访问了height变量后,height就变为了堆上的变量了,不管在block里面还是block外面访问的都是堆上的height变量了,从c++代码可以看出block内部有一个指向__Block_byref_height_0结构体对象的指针,该结构体里面有个成员height,还有一个指向自己的__Block_byref_height_0结构体指针(这里先不说为什么这样设计)
与上面访问auto变量不同的是,没有被__block修饰的变量只能访问,不能修改,而被__block修饰的额变量是可以修改的,我的理解是如果没有被__block修饰的变量也可以修改的话,那是访问堆上的变量还是栈上的变量呢?而被__block修饰的变量不管block内部还是外部都是访问的同一个堆上的变量,所以才让它进行修改
很多人有个疑惑,既然外部的height变量被copy到堆上了,而且后面的访问height都是在堆上的,那之前栈上的height变量去哪了呢?
![](https://img.haomeiwen.com/i5748238/7851782261d0b19a.png)
可以看出之前栈上的height的内存还是在的,只是没有被使用,并且出了当前作用域后就会自动销毁
接着看下访问auto变量的对象类型
![](https://img.haomeiwen.com/i5748238/20f6573b2ddbc953.png)
可以看出block内部使用的p指针也是在堆空间的,和外部的p指针互补干扰,这和上面访问auto基本数据类型类似,不同的是block内部和外部的指针都是指向堆区域的同一块内存
再看修改block内部的p指针
![](https://img.haomeiwen.com/i5748238/b47f0e9b091de81e.png)
直接修改p指针的内容就会报错,如果修改p指针指向的堆空间的数据,看下面
![](https://img.haomeiwen.com/i5748238/00f9c1d796ef7702.png)
可以看出直接修改p指向的堆内存数据是可以修改的,所以block访问外部auto对象类型时,指针变量p本身的值不能被修改,也就是不能修改p内存存储的数据,但指针p所指向的堆空间的数据是可以被修改的
再看下block内部访问外部__block修饰的对象类型
![](https://img.haomeiwen.com/i5748238/bdc63d3531287a1b.png)
可以看出block访问外部__block修饰的对象类型,p本身的内存数据可以被修改,而且p指向的堆空间的内存数据也可以被修改,并且block内部和外部访问的p指针都是在堆上了,和上面访问__block修饰的基本数据类型类似
再看下生成的c++代码
![](https://img.haomeiwen.com/i5748238/e8771a1f0c67a087.png)
和上面block访问外部__block修饰的基本数据类型类似,block内部有一个结构体指针p指向了结构体__Block_byref_p_0,该结构体中有个成员p指向了堆空间的Person对象,block内部打印的时候通过block结构体中的p找到__Block_byref_p_0结构体,然后再通过__Block_byref_p_0找到__forwarding中的Person对象,也就是这里的p是最里面__Block_byref_p_0结构体中的p指针
网友评论