美文网首页iOS开发
iOS 循环引用导致内存泄漏

iOS 循环引用导致内存泄漏

作者: BlackStar暗星 | 来源:发表于2020-03-08 20:07 被阅读0次

    首先我们需要先了解什么是循环引用

    • 循环引用
      简单来说循环引用就是 A持有B B持有C C持有A ,因为相互持有,导致无法单独释放某一类的内存 。我们以Block回调为例
    [self.singleton.singleBlock = ^(NSString * _Nonnull des) {
        self.myName = des;
    };
    

    self 持有 singleton , singleton持有Block, Block持有 self ,也可直接理解为 self 持有 singleton , singleton 持有 self,当self需要释放的时候,singleton是不需要释放的,但是 singleton 持有self 导致 self 不能被释放,因此,self 无法被释放,导致内存泄漏。


    其次我们需要了解那些常见的操作会造成内存泄漏,为什么会造成内存泄漏,而我把这些操作大致归为两类

    一、Block 回调造成的循环引用
    二、NSTimer

    一、Block 回调造成的循环引用

    • 网络使用 block 回调强持有self造成的循环引用
      现在对于网络的回调大多数采用两种方式回调:delegate & block
      而大多数使用AFNetworking的时候,通常采用 block 进行回调,block 强持有 self 从而造成 循环引用,最终导致内存泄漏。

    • 其他自定义类使用 block ,和网络一样

    • UITableViewCell cell 使用block ,为什么cell也会造成循环引用呢,因为self 持有tableview ,而 tableview 对 cell 其实是一种强持有的关系,所以在cell使用block的时候,也会造成循环引用

    • 单例 使用 block 强持有 self
      我们都知道单例一旦被创建,整个应用的声明周期都只会创建者一次,而且在应用的寿命周期结束之前是不会被释放的,那么如果单例使用 block 并且 在 block 回调内调用了 self ,那么此 单例 就强持有了 self,而 单例 不会释放,就造成了self无法释放,从而造成内存泄漏

    二、NSTimer 强持有self

    • NSTimer
      timer 为什么会造成内存泄漏,首先我们看 timer 的使用
    NSTimer *timer = [NSTimer scheduledTimerWithTimeInterval:5 target:self selector:@selector(timerMethod) userInfo:nil repeats:YES];
    

    我们发现: timer 的 target 是 self ,其实这一操作是对 self 的强引用,当页面将要释放的时候,由于 timer 强持有 self 从而导致 self 无法被释放,这就导致了内存泄漏。

    注意:如果你觉得 只要在 dealloc 里 去结束 timer ,那你就想错了,因为他们的关系是必须 timer 先结束 dealloc 才会被调用,所以我们是不能在 dealloc 里 调用timer的 invalidate 方法的, 切记、切记


    解决办法,使用 __weak typeof(self)weakSelf = self; 弱化self,打破循环引用(必要的时候我们还需要在block内部声明 strongSelf ,为防止weakSelf因为某种原因在block里提前释放使得weakSelf=nil,变成野指针,导致后边再调用weakSelf 造成崩溃)。示例如下

    __weak typeof(self)weakSelf = self;
    [singleton shareSingleton].singleBlock = ^(NSString * _Nonnull des) {
       weakSelf.myName = des;
    };
    

    相关文章

      网友评论

        本文标题:iOS 循环引用导致内存泄漏

        本文链接:https://www.haomeiwen.com/subject/cxpvrhtx.html