As an optimization, block storage starts out on the stack—just like blocks themselves do. If the block is copied using Block_copy (or in Objective-C when the block is sent a copy), variables are copied to the heap. Thus, the address of a __block variable can change over time.
block创建的时候捕获变量的值,block创建后变量的值改变,block感知不到。
If you access an instance variable by reference, a strong reference is made to self;
If you access an instance variable by value, a strong reference is made to the variable.
官方文档写的很少,还没看过详细介绍的文档。
这篇文章写得很好,深入研究 Block 捕获外部变量和 __block 实现原理
block -> block_struck
外部变量 -> block_struck成员变量block_struck_var
block实现 -> block_method
1. block转化为c++后变成一个struck结构体(后续称block_struck),有isa指针。block方法被做成struck里的一个类方法block_method,外部变量被做成成员变量block_struck_var(如何做后面说),block对外部变量的操作都转化为block_method对block_struck_var的操作。
2. block在创建的时候捕获外部变量:block_struck为每一个“需要捕获”的外部变量都声明了一个成员变量,并且在block初始化也就是block_sturck调用构造函数的时候用外部变量初始化了对应的成员变量。问题是哪些外部变量会变成block_sturck的成员变量呢?变成怎样的成员变量呢?分以下三种情况
第一种globle、static_globle 的变量应为作用域很广,所以不需要“捕获”。
第二种static_local,作用域是local的作用域,需要“捕获”,但捕获的是地址(下面构造函数中的int*_static_k),也就是说block对static_local是指针引用(有retain),在static_local作用域内的改动,block里面都能感知到。
第三种local变量,作用域是local的作用域,需要“捕获”,捕获的方法如下int_val和*_mutable_str,注意,int_val基础数据结构是值传递,*_mutable_str作为对象是拷贝了指针(会retain),block后面对int_val值的改变,以及block_mutable_str换个对象这样的改变,block里面都能感知不到,但是对_mutable_str对象里面的内容的改变是可以被block感知到的。
构造函数:__main_block_impl_0(void*fp,struct__main_block_desc_0*desc,int*_static_k,int_val,NSMutableString*_mutable_str,intflags=0):static_k(_static_k),val(_val),mutable_str(_mutable_str){...}
3. 如何把local变量做成指针引用?__block 的用法:
__block修饰的局部变量(基础类型或对象),都会转化唯一个struct,struct里面有个__forward指针,存的是自身地址,当ARC下把block拷贝到堆上的时候,栈上对象forward指向堆上对象,堆上对象的forward的指针指向堆上对象自己,这样i->forward->i的方式总能访问到当前的对象的。
网友评论