block的本质
block本质上也是一个OC对象,它内部也有个isa指针。block是封装了函数调用以及函数调用环境的OC对象。block的变量捕获(capture)
为了保证block内部能够正常访问外部的变量,block有个变量捕获机制。例子:
block的类型
block有3种类型,可以通过调用class方法或者isa指针查看具体类型,最终都是继承自NSBlock类型。
1、NSGlobalBlock ( _NSConcreteGlobalBlock )全局区
2、NSStackBlock ( _NSConcreteStackBlock )堆区
3、NSMallocBlock ( _NSConcreteMallocBlock )栈区
每一种类型的block调用copy后的结果如下所示
对象类型的auto变量
当block内部访问了对象类型的auto变量时:
如果block是在栈上:将不会对auto变量产生强引用。
如果block被拷贝到堆上:
1、会调用block内部的copy函数。
2、copy函数内部会调用_Block_object_assign函数。
3、_Block_object_assign函数会根据auto变量的修饰符(__strong、__weak、__unsafe_unretained)做出相应的操作,形成强引用(retain)或者弱引用。
如果block从堆上移除
1、会调用block内部的dispose函数。
2、dispose函数内部会调用_Block_object_dispose函数。
3、Block_object_dispose函数会自动释放引用的auto变量(release)。
__block修饰符
__block可以用于解决block内部无法修改auto变量值的问题,__block不能修饰全局变量、静态变量(static),编译器会将__block变量包装成一个对象。
__block的内存管理
当block在栈上时,并不会对__block变量产生强引用。
当block被copy到堆时,会调用block内部的copy函数,copy函数内部会调用_Block_object_assign函数,_Block_object_assign函数会根据所指向对象的修饰符(__strong、__weak、__unsafe_unretained)做出相应的操作,形成强引用(retain)或者弱引用(注意:这里仅限于ARC时会retain,MRC时不会retain)。
__block的__forwarding指针
循环引用问题
ARC
用__weak、__unsafe_unretained解决MRC
用__unsafe_unretained解决
用__block解决