循环引用

作者: 神采飞扬_2015 | 来源:发表于2017-01-08 23:32 被阅读369次
  • 常见的循环引用

如下代码所示,EOCClassA实例的other属性设置成某个EOCClassB 实例,而EOCClassB实例的other属性设置成某个EOCClassA 实例,保留环会导致内存泄漏,解决方法就是将某一个引用设置为weak(即非拥有关系)。

Paste_Image.png Paste_Image.png
#import <Foundation/Foundation.h>

@class EOCClassA;
@class EOCClassB;

@interface EOCClassA : NSObject
@property (nonatomic, strong) EOCClassB *other;
@end

@interface EOCClassB : NSObject
@property (nonatomic, strong) EOCClassA *other;
@end
  • 代理属性设置为weak

协议:用来指定代理双方可以做什么,必须做什么。
代理:根据指定的协议,完成委托方需要实现的功能。
委托:根据指定的协议,指定代理去完成什么功能。

Paste_Image.png

代理的本质就是代理对象内存的传递和操作,我们在委托类设置代理对象后,实际上只是用一个id类型的指针将代理对象进行了一个弱引用。委托方让代理方执行操作,实际上是在委托类中向这个id类型指针指向的对象发送消息,而这个id类型指针指向的对象,就是代理对象。

Paste_Image.png

实委托方的代理属性本质上就是代理对象自身,设置委托代理就是代理属性指针指向代理对象,相当于代理对象只是在委托方中调用自己的方法,如果方法没有实现就会导致崩溃。

举例:在tableViewController中,控制器的view就是tableView,这就相当于tableViewController强引用着tableView,然后当我们设置delegate的时候,一般都是让tableViewController成为代理,这个时候代理如果也使用strong,那么tableView的delegate又强引用着tableViewController,所以导致循环引用,因此代理得用weak。

Paste_Image.png
  • block中为避免循环引用,常见写法

__weak typeof(self) weakSelf = self;
[self doSomeBlockJob:^{   
   __strong typeof(weakSelf) strongSelf = weakSelf;   
   if (strongSelf) { 
     ...    
  }
}];
  • 什么时候在 block 里面用 self,不需要使用 weak self

当 block 本身不被 self 持有,而被别的对象持有,同时不产生循环引用的时候,就不需要使用 weak self 了。如: UIView动画block不会造成循环引用是因为这是类方法,不可能强引用一个类,所以不会造成循环引用。

[UIView animateWithDuration:0.2 animations:^{
  self.alpha = 1;
}];
  • 为什么 block 里面还需要写一个 strong self,不写会怎么样

在 block 中先写一个 strong self,其实是为了避免在 block 的执行过程中,突然出现 self 被释放的尴尬情况。通常情况下,如果不这么做的话,很容易出现一些奇怪的逻辑,甚至闪退。以 AFNetworking 中 AFNetworkReachabilityManager.m
的一段代码举例:

__weak __typeof(self)weakSelf = self;
AFNetworkReachabilityStatusBlock callback = ^(AFNetworkReachabilityStatus status) {   
   __strong __typeof(weakSelf)strongSelf = weakSelf; 
  strongSelf.networkReachabilityStatus = status;   
  if (strongSelf.networkReachabilityStatusBlock) {  
    strongSelf.networkReachabilityStatusBlock(status);
    }
};

如果没有 strongSelf 的那行代码,那么后面的每一行代码执行时,self 都可能被释放掉了,这样很可能造成逻辑异常。特别是当我们正在执行 strongSelf.networkReachabilityStatusBlock(status);
这个 block 闭包时,如果这个 block 执行到一半时 self 释放,那么多半情况下会 Crash。

  • 有没有这样一个需求场景,block会产生循环引用,但是业务又需要你不能使用 weak self

场景:在网络请求API会持有回调的block,回调的block会持有self,而self也持有网络请求API的话,我们就构造了一个循环引用。虽然我们构造出了循环引用,但是因为网络请求结束时,网络请求API会主动释放对block的持有,因为整个循环链条被解开,循环应用就被打破了,所以不会存在内存泄露问题。

- (void)clearCompletionBlock{
  //nil out to break the retain cycle 
  self.successCompletionBlock = nil; 
  self.failureCompletionBlock = nil;
}

解决思路:
1、事前避免,我们在会产生循环引用的地方使用 weak 弱引用,以避免产生循环引用。
2、事后补救,我们明确知道会存在循环引用,但是我们在合理的位置主动断开环中的一个引用,使得对象得以回收。

相关文章

  • 4-8 循环引用

    3种循环引用 自循环引用 相互循环引用 多循环引用 Block的循环引用 NSTimer 的循环引用 破除循环引用...

  • 循环引用的相关问题

    1、循环引用的种类(1)自循环引用(2)相互循环引用(3)多循环引用 如何破除循环引用?(1)避免产生循环引用(2...

  • iOS 内存管理面试题(循环引用)

    循环引用 循环引用的实质:多个对象相互之间有强引用,不能释放让系统回收。 如何解决循环引用? 1、避免产生循环引用...

  • 内存管理-循环引用

    三种类型循环引用 自循环引用 相互循环引用 多循环引用 自循环引用 假如有一个对象,内部强持有它的成员变量obj,...

  • iOS 循环引用

    1. 循环应用的分类: 自循环引用; 相互循环引用; 多循环引用; 自循环引用: 一个对象中有一个成员变量A; 如...

  • iOS开发 循环引用的几种场景

    delegate 循环引用如果delegate使用strong修饰容易引起循环引用 block 循环引用block...

  • Day2

    1 单方向的引用不会产生循环引用。循环引用:闭包引用了self,self引用了闭包。Swift推荐使用解决循环引用...

  • 避免Block的循环引用

    避免Block的循环引用 什么是循环引用,什么时候发生循环引用 1 循环引用就是当self 拥有一个block的...

  • iOS基础 Block解决循环引用

    block 循环引用循环引用 A对象持有B,B又持有A,互相强引用 解决循环引用问题:ARC 和MRC ARC:...

  • 2019-03-07 对WKWebView中的循环引用的理解

    WKWebView的这个循环引用很像定时器的循环引用。定时器的循环引用是因为系统runloop循环 强引用了执行...

网友评论

    本文标题:循环引用

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