NSTimer注意点及循环引用

NSTimer

  1. 作用:文档又讲:在固定的时间间隔被触发,给指定目标发送消息。
  2. NSTimer使用必须注意点?
    1. 要想timer能够运行起来,必须将timer实例 添加到 指定线程的Runloop下某个model下. 上面一句话蕴含几点:
      1.1. 必须存在线程
      1.2. 指定线程的Runloop必须启动
      1.3. 必须将timer添加到Runloop的某个model下(即:timer作为Model的item)
    1. Runloop 与 timer 关系? 文档中是这样写的:

Once scheduled on a run loop, the timer fires at the specified interval until it is invalidated. A nonrepeating timer invalidates itself immediately after it fires. However, for a repeating timer, you must invalidate the timer object yourself by calling its invalidate method. Calling this method requests the removal of the timer from the current run loop; as a result, you should always call the invalidate method from the same thread on which the timer was installed. Invalidating the timer immediately disables it so that it no longer affects the run loop. The run loop then removes the timer (and the strong reference it had to the timer), either just before the invalidate method returns or at some later point. Once invalidated, timer objects cannot be reused.
上面文档提出几个注意点:

  1. timer必须运行在runloop中,不重复的timer,触发后系统立即使其自身无效. 重复的timer,必须调用invalidate方法才能使timer无效,且调用invalidate方法后会请求从runloop删除timer.
  2. 使用timer与废弃timer必须在同一个线程中.
  3. Runloop会在invalidate方法返回之前或之后的某个时间点移除timer(即:移除runloop对timer的强引用)
  4. 一旦失效,就不能重用计时器对象。
    1. 根据2中文档所知,runloop会对timer有强引用.
    1. timer会对目标对象target进行强引用
  • 5.invalidate方法作用? 文档说明:

Stops the timer from ever firing again and requests its removal from its run loop.
//即:停止timer再次被触发,且请求从runloop中移除

NSTimer如何解决循环引用?

  1. 首选讲NSTimer使用时产生循环引用的原因?
    // 实线:强引用,虚线:弱引用


    屏幕快照 2019-09-17 下午6.10.05.png
  • 可以看出无论self对timer是强/弱引用,timer始终强持有self实例.当self强引用timer时,self与timer相互引用,肯定造成循环.当self弱引用timer时,timer一旦被触发,则timer一定被添加到runloop中,这时runloop强持有timer,timer强持有self,若self是NSObject,UIView,UIViewController的实例,就要求runloop退出(model的item为空)或被释放(线程被销毁),但runloop对应线程是主线程时,就造成self无法被释放.
  1. 解决方案?
  • 直接方法:
    2.1.1. 使用iOS10之后新出的block回调方式.
    2.1.2.拦截pop方法,废弃timer.不同开发人有不同的方案.我这里是通过自定义navigation,重写pop方法,下沉给nav.toViewController, self实现相应方法,调用timer的invalidate
    2.1.3. 在viewDidDisappear里 调用timer的invalidate.(self is UIViewController)
  • 类方法方案:(强力推荐,因为无需外部调用timer的invalidate,避免遗忘)

就是通过将timer的target设置为一个类对象.虽然相互持有关系没有被打破,可是因为类对象(class object)无需回收,所以不用担心。

  • 消息转发方案:

就是通过将timer的target设置为一个NSProxy的实例,自定义继承NSProxy类,实现消息转发方法. 就是说:timer调用target(proxy实例)的selector,利用消息转发原理,回调self的selector

  • RunTime方案:

就是随意创建一个object作为timer的selector,给object添加实例方法,添加的实例方法就是timer触发的消息方法.

  • Block方案:

即给NSTimer添加分类,添加类方法获取timer实例,将timer的target设置为NSTimer类对象(简介利用了类方法方案),打破timer对self的强持有关系.

具体实现代码https://github.com/zhbgitHub/NSTimerUse
代码中注释有应该的注意点及timer占用资源的释放说明.

  • 使用GCD定时器取代NSTimer(较简单直接贴代码)
@interface xxx ()
@property (nonatomic, strong) dispatch_source_t timer;
@end

- (void)startTimer
{
   dispatch_queue_t globalQueue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
    self.timer = dispatch_source_create(DISPATCH_SOURCE_TYPE_TIMER, 0, 0, globalQueue);
    dispatch_source_set_timer(_timer, dispatch_time(DISPATCH_TIME_NOW, 0), 2.0*NSEC_PER_SEC, 0);
    dispatch_source_set_event_handler(_timer, ^{
        dispatch_async(dispatch_get_main_queue(), ^{
            NSLog(@"执行了");
        });
    });
    //开启计时器
    dispatch_resume(_timer);
}

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

推荐阅读更多精彩内容