weak指针指向stackBlock并不会随stackBlock被回收而指向nil

· 前言

无意中写的demo遇到了这个问题,引出了block的三种类型以及编译器在ARC环境下对block进行优化的知识点,让自己对block以及ARC的内存管理有了更深刻的印象,特此写下来给需要帮助的iOSCoder

· 问题描述

如下所示,在一个UIButton中,我用了一个weak指针和一个strong指针接收一个block,在clickActionHandle方法执行block之前,将strong指针置为nil。

理想情况:随着strong指针的销毁,weak指针也会随之置为nil而不执行block。

实际情况:weakCCBack发生坏内存访问崩溃

#import "CallBackButton.h"

@interface CallBackButton ()

@property (nonatomic,weak) void(^weakCCBack)(void);

@property (nonatomic,strong) void(^strongCCBack)(void);

@end

@implementation CallBackButton

-(instancetype)initWithCallBack:(void(^)(void))callBack{
    if (self = [super init]) {
        self.strongCCBack = callBack;
        self.weakCCBack = callBack;
        NSLog(@"self.strongCCBack = %@ self.weakCCBack =%@",self.strongCCBack,self.weakCCBack);
        [self addTarget:self action:@selector(clickActionHandle) forControlEvents:UIControlEventTouchUpInside];
    }
    return self;
}

-(void)clickActionHandle{
    self.strongCCBack = nil;
    if (self.weakCCBack != nil) {
        self.weakCCBack();
        self.strongCCBack = nil;
    }
}

· 原因解释

同时用一个weak指针和一个strong指针指向init方法传过来的block时,当strong指针置为nil后,weak指针没有自动置为nil导致执行clickActionHandle方法时,发生了坏内存访问的错误。打印了两个指针的地址才发现时ARC对block的赋值进行了优化。

self.strongCCBack = <__NSMallocBlock__: 0x600002617b40>
 self.weakCCBack =<__NSStackBlock__: 0x7ffee6405200>
callBack = <__NSStackBlock__: 0x7ffee6405200>

·使用strong指针接收栈类型的block,编译器会将栈block进行一次拷贝操作生成一个新的堆Block保存在strong指针中。这么做的原因很容易理解:因为存储在栈中的值出了作用域以后会被系统自动回收,而block是一个等待着被执行的代码块,如果init方法结束后参数中的block(此block为栈block)会被立即回收,那么在执行block的时候会发生坏内存访问的情况,为了保证安全执行block,strong指针指向stackBlock(栈)的时候会生成一个mallocBlock(堆)副本,以确保能安全执行block。
·而使用weak指针指向栈block时,编译器未做任何优化,即便栈block被回收,weak指针也不会指向nil,继而导致执行block的时候会产生坏内存访问。

你可能感兴趣的:(weak指针指向stackBlock并不会随stackBlock被回收而指向nil)