面试题:__block的作用是什么?有什么使用注意点?
使用__block,编译器会将__block变量包装成为一个对象,可以解决block内部无法修改auto变量值的问题。
注意点:内存管理方面,在mrc环境下是不会对oc对象产生强引用。
面试题:block的属性修饰词为什么是copy?使用block有哪些使用注意?
block一旦没有进行copy操作,就在栈上或者全局区,就不会在堆上,保证在堆上可以控制它的生命周期。
使用注意:循环引用问题
面试题:block在修饰NSMutableArray,需不需要添加_block?
不需要
在ARC环境下,编译器会根据情况自动将栈上的block复制到堆上,比如以下情况
1)block作为函数返回值时。
2)将block赋值给__strong指针时。
3)block作为Cocoa API中方法名含有usingBlock的方法参数时。
4)block作为GCD API的方法参数时。
对象类型auto变量
当block内部访问了对象类型的auto变量时
如果block在栈上
将不会对auto变量产生强引用。
如果block被拷贝到堆上:
会调用block内部的copy函数
copy函数内部会调用_Block_Object_assign函数
_Block_object_assign函数会根据auto变量的修饰符(__strong、__weak、__unsafe_unretained)做出相应的操作,类似retain(形成强引用,弱引用)
如果block从堆上移除
会调用block内部的dispose函数
dispose函数内部会调用_Block_object_dispose函数
_Block_object_dispose函数会自动释放引用的auto变量,类似release
栈上的Block复制到堆时,会调用copy函数
堆上的Block被废弃时,会调用dispose函数
什么时候释放,看强引用在哪儿。
block内部不能直接修改外部的auto变量,要修改需要以下:
方法1:可以用static修饰变量;
方法2:改成全局变量(永久占内存);
方法3:用__block修饰(而且没有修改变量的性质,即还是auto变量)。
__block修饰符
__block可以用于解决block内部无法修改auto变量值的问题。
__block不能修饰全局变量,静态变量(static)。
编译器会将__block变量包装成一个对象。(因为里面有一个isa指针,_forwording地址指向自己)
__weak问题解决
在使用clang转化OC为C++代码时,可能会遇到以下问题:
cannot create __weak reference in file using manual reference
解决方案:支持ARC,指定运行时系统版本,比如xcrun -sdk phones clang arch arm64 -objc -fobjc -arc -fobjc -runtime=iOS-8.0.0 main.m
__block的内存管理
当block在栈上时
并不会对__block变量产生强引用
当block被copy到堆时
会调用block内部的copy函数
copy函数内部会调用_Block_object_assign函数
_Block_object_assign函数会对__block变量形成强引用(retain)
当block从堆中移除时:
会调用block内部的dispose函数
dispose函数内部会调用_Block_object_dispose函数
_Block_object_dispose函数会自动释放引用的__block变量(release)
对象类型的auto变量、__block变量
eg:__block int age = 10; //对象类型__block变量
NSObject *obj = [[NSObject alloc]init];//对象类型auto变量
__weak NSObject *weakObj = obj;
int型的变量是不能用__weak修饰的(__block __weak int age = 10;是错误的 ),只用于OC对象。
当block在栈上时,对它们都不会产生强引用。
当block拷贝到堆上时,都会通过copy函数来处理它们
__block变量(假设变量名为a)
__Block_object_assign((void *)&dst->a), (void *)src->a, 8 /* BLOCK_FIELD_IS_BYREF*/);
对象类型的auto变量(假设变量名为p)
__Block_object_assign((void *)&dst->p), (void *)src->p, 3 /* BLOCK_FIELD_IS_OBJECT*/);
当block从堆上移除时,都会通过dispose函数来释放它们。
__block变量(假设变量名为a)
__Block_object_dispose((void *)src->a), 8 /* BLOCK_FIELD_IS_BYREF*/);
对象类型的auto变量(假设变量名为p)
__Block_object_dispose((void *)src->p, 3 /* BLOCK_FIELD_IS_OBJECT*/);
auto变量、__block变量两者之前的相似差异:
相似:当block在栈上时,对它们都不会产生强引用;当block拷贝到堆上时,都会通过copy函数来处理它们;当block从堆上移除时,都会通过dispose函数来释放它们。
不同:在引用的问题上,__block产生的就是强引用,而如果是oc对象取决于当初怎么访问的,如果是弱引用访问就是弱引用,强引用访问就是强引用。
被__block修饰的对象类型
当__block变量在栈上时,不会对指向的对象产生强引用
当__block变量被copy到堆时
会调用__block变量内部的copy函数
copy函数内部会调用__Block_object_assign函数
__Block_object_assign函数会根据所指向对象的修饰符(__strong, __weak, __unsafe_unretained)做出相应操作,形成强引用(retain)或者弱引用(注意:这里仅限于ARC时会retain,MRC时不会retain)
如果__block变量从堆上移除
会调用__block变量内部的dispose函数
dispose函数内部会调用_Block_object_dispose函数
_Block_object_dispose函数会自动释放指向的对象(release)
网友评论