使用Dispatch_source 创建的timer遇到的问题

一、立即释放

timer必须设置为自己的成员变量或者属性,不然会立即释放。

二、循环引用

1
2
3
dispatch_source_set_event_handler(_refreshTimer, ^{
self.
});

handler里面使用了self的话,会引起循环引用,导致类不能正确释放。

三、清空timer导致crash

最近在iOS11的项目里遇到一个crash:EXC_BREAKPOINT
最终确定问题是由这个timer引起的。
触发条件是:在一个vc中创建了一个timer,我连hanlder都没加,也没有使用dispatch_resume开启,然后点击左上角返回,这时便crash了。
于是,我加了如下代码:

1
2
3
- (void)dealloc {
dispatch_source_cancel(_timer);
}

还是crash。无奈google了一下,发现两篇文章:

  1. https://forums.developer.apple.com/thread/81445
  2. https://forums.developer.apple.com/message/91884#91884
  3. https://forums.developer.apple.com/message/46175#46175
    找到了解决办法:
    1
    2
    3
    4
    5
    - (void)dealloc {
    dispatch_source_cancel(_timer);
    dispatch_resume(_timer);
    _timer = nil;
    }

这样就不会crash了。类也能正确释放了。
项目:代码下载

四、-cleanUpResource方法

一个类到底是否有一个cleanUpResource方法,在类释放之前调用来清空资源?答案是根据情况。

  1. 单例类需要
  2. 拥有CADisplayLink成员变量以及NSTimer成员变量的类需要。这两个类的成员变量需要手动调用invalidate方法,不然拥有该成员变量的类永远不会被释放,因为循环引用。注意:用Dispatch_source_create创建的timer不需要在cleanUpResource方法中提前释放。因为这个timer并不会引用self,所以不会造成循环引用。
  3. 普通类不需要。包括viewController、view。

五、dealloc方法

假设一个vc,拥有view1和view2,那么在vc释放时,dealloc的调用顺序是vc、view1、view2。

注意:vc在调用dealloc时,view1和view2并没有释放。
假设view1和view2因为自身的原因无法释放,则不会影响到vc的dealloc方法的调用。

六、苹果开发者论坛

地址:https://forums.developer.apple.com/welcome

在这里可以向苹果工程师提问,也可以搜索问题。类似于stack overflow。很方便。