Block 循环引用问题
1.block是封装函数及其上下文的OC对象
2.Block类型 (最终都是继承自NSBlock类型)
- __NSGlobalBlock __ 在数据区
- __NSMallocBlock __ 在堆区
- __NSStackBlock __ 在栈区
- 堆:动态分配内存,需要程序员自己申请,程序员自己管理
- 栈:自动分配内存,自动销毁,先入后出,栈上的内容存在自动销毁的情况
3.block的属性修饰词为什么是copy?
block一旦没有进行copy操作,就不会在堆上
block在堆上,程序员就可以对block做内存管理等操作,可以控制block的生命周期
4.block属性的建议写法(基于MRC、ARC所以一般用copy)
MRC@property (copy, nonatomic) void (^block)(void);
ARC@property (strong, nonatomic) void (^block)(void);
@property (copy, nonatomic) void (^block)(void);
5.在ARC环境下,编译器会根据情况自动将栈上的block复制到堆上的几种情况?
- 1.block作为函数返回值时
- 2.将block赋值给__strong指针时
- 3.block作为Cocoa API中方法名含有usingBlock的方法参数时
- 4.block作为GCD API的方法参数时
6.__block 修饰符作用?
__block可以用于解决block内部无法修改auto变量值的问题
__block不能修饰全局变量、静态变量(static)
编译器会将__block变量包装成一个对象
7.如何解决block循环引用的问题?(现在一般使用__weak解决)
MRC
两种方式:__unsafe_unretained、__block
ARC
三种方法比较
- __weak:不会产生强引用,指向的对象销毁时,会自动让指针置为nil(使用不当会使对象提前释放)
- __unsafe_unretained:不会产生强引用,不安全,指向的对象销毁时,指针存储的地址值不变
- __block:必须把引用对象置位nil,并且要调用该block
8.block循环引用(A与B有持有关系,且在block中调用了彼此的某些变量)
Block一般作为参数 属性 返回值形式 使用
产生循环引用的条件是—— A与B有持有关系,且在block中调用了彼此的某些变量(A、B系统的或者自定义的都可以)
特例1 .block作为Cocoa API中方法名含有usingBlock的方法参数时(编译器会自动处理,我们不需要处理)
// LJYBLOCK: enumerateObjectsUsingBlock; A(self)与B(topArray)有持有关系 但未循环引用 是个例外
// WeakObj(self);
[self.topArray enumerateObjectsUsingBlock:^(id _Nonnull obj, NSUInteger idx, BOOL * _Nonnull stop) {
if (idx == 0) {
ICKTrendAttentionViewController *vc = [[ICKTrendAttentionViewController alloc] init];
vc.view.frame = CGRectMake(0, 0, LL_ScreenWidth, LL_SafeScreenHeight-ICKTopViewHeight);
// [Weakself addChildViewController:vc];
[self addChildViewController:vc];
} else {
ICKTrendSquareViewController *vc = [[ICKTrendSquareViewController alloc] init];
vc.view.frame = CGRectMake(0, 0, LL_ScreenWidth, LL_SafeScreenHeight-ICKTopViewHeight);
[self addChildViewController:vc];
}
}];
特例2
UIAlertController *alerController = [UIAlertController alertControllerWithTitle:@"" message:message preferredStyle:UIAlertControllerStyleAlert];
// LJYBLOCK: UIAlertController A与B没有持有关系 不会循环引用
UIAlertAction *okAction = [UIAlertAction actionWithTitle:@"确定" style:UIAlertActionStyleDefault handler:^(UIAlertAction * _Nonnull action) {
[self pop];
// LJYBLOCK: UIAlertController 系统的未循环引用 自己定义的不行 基本不会出现 仅仅为了测试
// alerController.message = @"123";
}];
参考博客: