定时器启示录

早些时候看过一些分析定时器内存方面的文章,但在遇到这个bug前我是不屑的。不就是定时器强引用ViewController,而ViewController再用strong属性去引用定时器,必然会导致循环引用么。解决办法也很简单,只需使用weak属性去引用定时器即可。然而这一次的经历却证明我还是图样,我单知道使用weak属性不会导致循环引用,我没注意到此时的定时器在无形中延长了ViewController的生命周期。这就为这个bug埋下了隐患。

记录一下bug的解决总是有必要的。

下午的一次自测中,偶尔发现观众端听不到主播端的声音。我先是诧异,接着是很不安,因为墨菲定律告诉我们:如果你担心某种情况发生,那么它就更有可能发生。最开始以为是主播端的问题,便仔细检查了主播端的代码,又加入了另一台手机设置为观众,作为对照。运行之后发现对照组是好的,但刚才那台手机的问题仍然偶现。这就说明主播端的推流是没问题的。接下来的工作便是在问题手机上尽可能找到复现的操作,以便根据操作路径定位大致原因。在某次频繁进入离开直播房间时,APP直接卡死了,再无任何交互的响应。问题开始变得严重,时间也一分一秒的流逝在这一次次的调试中,一晃下班时间快到了,周围开始变的嘈杂,安卓兄弟开始催我下班还说要带我上王者但我是不信的。我整理了下东西,但又不想在节前留下些许问题,便又坐了回去。等到周围开始安静时,夕阳已经西下。我努力回想之前的操作,发现只在直播预约状态下,问题才会重现。于是在页面的dealloc函数中打好断点,点击返回,果然函数没有被调用。这说明页面依然被某个对象持有而没有释放。在检查了所有Block回调都使用的是weakSelf后,最后只剩下定时器了。

问题的根源算是找到了。原来在直播预约状态下会启动一个定时器,但在点击返回时忘记invalid定时器了。这让定时器延长了ViewController的生命周期。加上invalid后,问题搞定,收工。回家的路上碰巧遇到了K君,便给K君讲述了这个问题,K君听后哈哈大笑说:加上invalid只能解决这一次的bug,却不能避免下一次又忘记,而且根据页面dealloc函数里逻辑的不同,bug的外在表现形式也必然不同,到时候又得花费不少的时间找bug啊。闻道于朝,不禁感叹K君的身经百战。

回到家后,打开谷歌又搜到了早些时候看过的那些文章,感慨颇多。系统的NSTimer简单却又不那么简单:

  1. 不注意使用的话有内存泄漏的隐患
  2. 需要在合适的地方invalid定时器,否则定时器会一直强引用target从而延长target的生命周期。
  3. 使用时必须保证有一个活跃的runloop,并且需要指定mode
  4. 精度可能不够
  5. 创建和撤销必须在同一个线程上,在多线程环境下使用不便
  6. 不支持block,造成使用上的不便。(iOS10开始,已经支持block了)

为了从根本上避免上述问题,一个弱引用target的、能够在自身销毁时自动invalid的定时器想必是极好的,但又该如何实现呢?好在互联网在经过这么多年的发展,第三方开源库从未像现在这般丰富,唾手可得。不多时,便在GitHub上找到了MSWeakTimer

MSWeakTimer提供了和系统NSTimer一致的接口,好的代码就该这样美美与共,和而不同:

@property (nonatomic, strong) MSWeakTimer *weakTimer;

self.weakTimer = [MSWeakTimer scheduledTimerWithTimeInterval:3 target:self selector:@selector(doSome) userInfo:nil repeats:YES dispatchQueue:dispatch_get_main_queue()];
//立即触发回调方法
[self.weakTimer fire];

- (void)doSome {
    NSLog(@"++++++%@", self);
}

至于MSWeakTimer的实现原理自然是和NSTimer不同的:通过封装GCD定时器实现NSTimer的功能,但内部却是弱引用target,不仅如此MSWeakTimer还支持在其他线程中执行回调函数。

@interface MSWeakTimer ()
{
    struct
    {
        uint32_t timerIsInvalidated;
    } _timerFlags;
}

@property (nonatomic, assign) NSTimeInterval timeInterval;
@property (nonatomic, weak) id target; //弱引用target
@property (nonatomic, assign) SEL selector;
@property (nonatomic, strong) id userInfo;
@property (nonatomic, assign) BOOL repeats;

@property (nonatomic, ms_gcd_property_qualifier) dispatch_queue_t privateSerialQueue;

@property (nonatomic, ms_gcd_property_qualifier) dispatch_source_t timer;

@end
  
...

//自身销毁时invalidate掉定时器
- (void)dealloc
{
  [self invalidate];

  ms_release_gcd_object(_privateSerialQueue);
}

当我们使用MSWeakTimer时,就可以避免因忘记invalid定时器,导致ViewController生命周期被延长不能及时销毁而产生的bug。从这之后,我便不再遇到和NSTimer相关的bug了。

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 159,015评论 4 362
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 67,262评论 1 292
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 108,727评论 0 243
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 43,986评论 0 205
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 52,363评论 3 287
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 40,610评论 1 219
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 31,871评论 2 312
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 30,582评论 0 198
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 34,297评论 1 242
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 30,551评论 2 246
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 32,053评论 1 260
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 28,385评论 2 253
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 33,035评论 3 236
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 26,079评论 0 8
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 26,841评论 0 195
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 35,648评论 2 274
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 35,550评论 2 270