iOS循环引用问题
今天面试问道了循环引用,所以就看了看,原来只是知道使用了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日更新:
最新文章
- 组合模式/composite模式/对象结构型模式
- 《Entity Framework 6 Recipes》中文翻译系列 (35) ------ 第六章 继承与建模高级应用之TPH继承映射中使用复合条件
- $scope.$watch()——监听数据变化
- js 判断所选时间(或者当前时间)是否在某一时间段用于不同时间段显示不同的客服qq
- Learning in Two-Player Matrix Games
- Oracle日期函数和循环总结
- ping时不知道ping那个Ip的解决办法
- 超强1000 JQuery插件
- GitHub Top 100 简介
- avalonjs 1.3.7发布
- 直接用postman测试api ,服务器端没提供跨域也可以访问。
- spring基础系列--JavaConfig配置
- HTML5对音视频的处理
- iPad Pro 10.5+Apple Pencil之专注文献阅读与笔记效率的App综述
- Unity中的屏幕坐标:ComputeScreenPos/VPOS/WPOS
- vue-02-安装-指令
- 机器学习 第四篇:OLS回归分析
- MySQL 高可用性—keepalived+mysql双主(有详细步骤和全部配置项解释)
- jetty 代码启动
- HDU 6071 Lazy Running (同余最短路 dij)