今天面试问道了循环引用,所以就看了看,原来只是知道使用了Block容易造成循环引用。今天就来简单的介绍一些循环引用。

先来简单介绍一下什么是循环引用?

循环引用可以简单的理解成:A对象引用了B对象,B对象又引用了A对象。两者相互保持对方的一个引用。导致任何时候计数都不为0,最终两者都无法释放。

产生循环引用的方式:

1、NSTimer

比如说我在一个类中声明了一个NSTimer计时器类。而在NSTimer 的方法

+ (NSTimer *)scheduledTimerWithTimeInterval:(NSTimeInterval)seconds
target:(id)target
selector:(SEL)aSelector
userInfo:(id)userInfo
repeats:(BOOL)repeats

当我们在aSelector中调用了自己的属性或者方法时(比如调用了自己的self.class),那么当我们实例化这个类之后然后我们让他延迟几秒释放,那么我们会发现time中的aSelector会一直执行。现在就来简单的分析一下吧:

timer没有调用invalidate方法是不会因为类的释放而停止的。而对于类实例来说:它认为timer没有执行完毕,所以没有机会进入dealloc。循环引用,相互等待。所以我们可以在类实例释放之前手动调用一下NSTimer的invalidate方法。还有就是下面的代码:

__weak ClassA *weakSelf = self;
timer = [NSTimer scheduledTimerWithTimeInterval:1.0f target:weakSelf selector:@selector(startTimer) userInfo:nil repeats:YES];

所以我们在使用NSTimer时一定要注意NSTimer的invalidate时机。

在下面更新中,对NSTimer进行了重新说明。NSTimer是会造成循环引用,但是只要我们在合适的地方将其停止并释放就没问题。但是你有的时候并不能保证其一定会释放,比如我点击了倒计时,但是我没有等倒计时结束就返回,如果是ViewController,你可以在视图将要消失的时候调用停止和释放方法。但是如果不是在ViewController中就不确定了。所以在gitHub上的demo上有个ZGWeakTimerTarget,可以巧妙地解决循环引用问题。更多请参见这里.

2、Block

例如我们定义了一个block块,然后作为了一个类的属性变量,那么当我们在这个块中调用自己的属性或者方法的时候就会产生循环引用。

解决循环引用方法:通过__weak声明一个self的新变量来代替原来的self。这样在块中可以通过这个弱引用self来防止block中对self进行strong引用。

3、delegate

一般情况下我们声明delegate时使用assign赋值,因为赋值属性不会增加计数。

如果一个UITableViewController 对象a通过retain获取了UITableView对象b的所有权,这个UITableView对象b的delegate又是a, 如果这个delegate是retain方式的,那基本上就没有机会释放这两个对象了。

---------------------------------------------------------------------------------------------------------

2016年6月7日更新:

引用循环定义:
所谓的“引用循环”是指双向的强引用,所以那些“单项的强引用”(block强引用self)是没有问题的。 
 
2017年6月19日更新:
近期分享的PPT和DEMO。详见这里

iOS循环引用问题的更多相关文章

  1. iOS循环引用

    iOS循环引用 当前类的闭包/Block属性,用到了当前类,就会造成循环引用 此闭包/Block应该是当前类的属性,我们经常对Block进行copy,copy到堆中,以便后用. 单方向引用是不会产生循 ...

  2. iOS 循环引用解决方案

    一.BLOCK 循环引用 一般表现为,某个类将block作为自己的属性变量,然后该类在block的方法体里面又使用了该类本身.构成循环引用. // 定义 block 的时候,会对外部变量做一次 cop ...

  3. iOS 循环引用

    1.循环引用一般是指:A持有B,B同时持有A,从而导致死循环无法释放对象. 2.一般循环引用出现在block和delegate中,而一般解决方法就是将self变成weakSelf(强引用变成弱引用), ...

  4. iOS 循环引用讲解(中)

    谈到循环引用,可能是delegate为啥非得用weak修饰,可能是block为啥要被特殊对待,你也可能仅仅想到了一个weakSelf,因为它能解决99%的关于循环引用的事情.下面我以个人的理解谈谈循环 ...

  5. iOS循环引用常见场景和解决办法

    好多场景会导致循环引用,例如使用Block.线程.委托.通知.观察者都可能会导致循环引用. 1.委托 遵守一个规则,委托方持有代理方的强引用,代理方持有委托方的弱引用. 实际场景中,委托方会是一个控制 ...

  6. iOS 循环引用 委托 (实例说明)

    如何避免循环引用造成的内存泄漏呢: 以delegate模式为例(viewcontroller和view之间就是代理模式,viewcontroller有view的使用权,viewcontroller同时 ...

  7. iOS之weak和strong、懒加载及循环引用

    一.weak和strong 1.理解 刚开始学UI的时候,对于weak和strong的描述看得最多的就是“由ARC引入,weak相当于OC中的assign,但是weak用于修饰对象,但是他们都不会造成 ...

  8. 【转】iOS学习之容易造成循环引用的三种场景

    ARC已经出来很久了,自动释放内存的确很方便,但是并非绝对安全绝对不会产生内存泄露.导致iOS对象无法按预期释放的一个无形杀手是——循环引用.循环引用可以简单理解为A引用了B,而B又引用了A,双方都同 ...

  9. 【原】iOS容易造成循环引用的三种场景,就在你我身边!

    ARC已经出来很久了,自动释放内存的确很方便,但是并非绝对安全绝对不会产生内存泄露.导致iOS对象无法按预期释放的一个无形杀手是——循环引用.循环引用可以简单理解为A引用了B,而B又引用了A,双方都同 ...

随机推荐

  1. MVC3.0学习笔记之元模型元数据ModelMetaData以及模型元数据提供系统

    模型元数据ModelMetaData是MVC中很重要的概念,它包括但不仅限于 模型的类型,模型包含了哪些属性,属性都是什么类型的,属性上都有什么特性. ASP.NET MVC3.0 提供了默认的模型元 ...

  2. Android 2.1 和 Android 4.4 工程目录超详细对比及详解

    在搭建Android开发环境及简单地建立一个HelloWorld项目后,本篇将通过HelloWorld项目来介绍Android项目的目录结构.本文的主要主题如下: 1.1.HelloWorld项目的目 ...

  3. MongoDB 安装记录

    之前使用一直没记录,防再次掉坑,记录下 echo 开始 D: cd D:\Program Files\MongoDB\Server\3.2\bin mongod --install --service ...

  4. position 属性和 z-index 属性对页面节点层级影响的例子

    转:http://www.neoease.com/tutorials/z-index/ 不设 z-index 属性 单层节点 双层节点 多层节点

  5. 配置visual studio code进行asp.net core rc2的开发

    1.安装.net core sdk https://github.com/dotnet/cli#installers-and-binaries,根据你的系统选择下载. 2.下载vscode的C#扩展插 ...

  6. Action接收页面传来的参数方法

    接收页面传来的参数方法 1.第一种:在action中设置相应的变量 在相应的action中设置与将要传进来的参数名相同的变量 eg: 页面传给后台两个参数 name=chance & age ...

  7. HT全矢量化的图形组件设计

    HT一直被客户称道的就是其全矢量化的设计特色,矢量相比传统图片好处太多了: 矢量可无级缩放,界面不失真不模糊 描述矢量的文本内容远比图片小得多 目前各种window.devicePixelRatio不 ...

  8. IOS开发UI基础之UIScrollView

    什么是UIScrollView ● 移动设备的屏幕⼤大⼩小是极其有限的,因此直接展⽰示在⽤用户眼前的内容也相当有限 ● 当展⽰示的内容较多,超出⼀一个屏幕时,⽤用户可通过滚动⼿手势来查看屏幕以外的内容 ...

  9. C#函数式程序设计之用闭包封装数据

    如果一个程序设计语言能够用高阶函数解决问题,则意味着数据作用域问题已十分突出.当函数可以当成参数和返回值在函数之间进行传递时,编译器利用闭包扩展变量的作用域,以保证随时能得到所需要的数据. C#函数式 ...

  10. struts2基础——自定义拦截器

    一.自定义拦截器 默认的拦截器能实现的功能是有限的,Struts2 支持自定义拦截器. 二.拦截器类 1.实现 Interceptor 接口 2.继承 AbstractInterceptor 抽象类, ...