iOS block循环引用

iOS使用block需注意循环应用的问题

1,一个对象内互相引用

比如TBViewController2 对象对全局属性block引用,而block内部又引用了TBViewController2 自身对象造成循环引用,内存得不到释放


iOS block循环引用_第1张图片
BDBC5884-1889-472C-92EF-F88090234FBF.png

如下代码(Xcode会发出警告, 比较容易发现)

    self.myBlock = ^() {
        [self doSomething];
    };
    myBlock();

又如,Xcode不会放出警告

    void(^myBlock)() = ^() {
        [self doSomething];
    };
    self.myBlock = myBlock;
    myBlock();

解决方案,关键字__weak 修饰self,使block不再持有self

    __weak typeof (self) weakSelf = self;
    self.myBlock = ^() {
        [weakSelf doSomething];
    };
    self.myBlock();
iOS block循环引用_第2张图片
652F3493-5C72-4B5E-985D-390D2B9ED53D.png

2,多个对象互相引用

TBViewController2 类实例对象属性持有TBBlockObject对象,TBBlockObject内部属性block又持有了TBViewController2对象,也会造成相互引用,内存得不到释放,而这错种错误编译器很难发现,不会发处警告。

iOS block循环引用_第3张图片
![Uploading 111C16BA-7D03-4EDA-8F2C-519AA42823E9_429985.png . . .]

代码如下:

    TBBlockObject *tbObject = [[TBBlockObject alloc] init];
    self.tbObject = tbObject;
    tbObject.myBlock = ^{
        [self doSomething];
    };

解决方案: __weak 修饰TBViewController2 self对象,使block不再持有TBViewController2 self对象:

    TBBlockObject *tbObject = [[TBBlockObject alloc] init];
    self.tbObject = tbObject;
    __weak typeof (self) weakSelf = self;
    tbObject.myBlock = ^{
        [weakSelf doSomething];
    };
iOS block循环引用_第4张图片
111C16BA-7D03-4EDA-8F2C-519AA42823E9.png

3,绝大部分GCD都不会产生循环引用

因为对象(TBViewController2)本身并没有对block进行持有,所以不会产生循环引用。

    // CGD 绝大部分都不会产生循环引用
    dispatch_async(dispatch_get_main_queue(), ^{
        [self doSomething];
    });

下列代码会产生循环引用

    // 如果对对象本身对 block持有,也会出现循环引用
    void(^myBlock)() = ^{
        [self doSomething];
    };
    self.myBlock = myBlock;
    dispatch_async(dispatch_get_main_queue(), myBlock);

解决方案,原理同上,利用__weak不让对象block持有对象本生

    // 如果对对象本身对 block持有,使用weakSelf
    __weak typeof (self) weakSelf = self;
    void(^myBlock)() = ^{
        [weakSelf doSomething];
    };
    self.myBlock = myBlock;
    dispatch_async(dispatch_get_main_queue(), myBlock);

4,2个对象拥有同一个block

假设TBViewController2对象和TBBlockObject同时拥有同一个block, 而block里面持有对象TBViewController2,但是某个时刻TBViewController2释放了,就会导致在运行TBBlockObject的block的时候出错。

    TBBlockObject *tbBlockObject = [[TBBlockObject alloc] init];
    self.tbBlockObject = tbBlockObject;
    
    TBViewController2 *vc2 = [[TBViewController2 alloc] init];
    // 注意weak,否则会循环引用
    __weak typeof(vc2) weakVC2 = vc2;
    void(^myBlock)() = ^() {
        [weakVC2 doSomething];
    };
    
    // 赋值block
    vc2.myBlock = myBlock;
    tbBlockObject.myBlock = myBlock;
    
    // 执行
    vc2.myBlock();
    tbBlockObject.myBlock();
    
    [self.navigationController pushViewController:vc2 animated:YES];

当退出vc2的时候,再执行

    [self.tbBlockObject excuteTBBlockObject];

就会出错了(无输出日志)

你可能感兴趣的:(iOS block循环引用)