自欺欺人的使用 NSTimer 销毁
自欺欺人的使用 NSTimer 銷毀
Demo地址
1.NSTimer是要加到runloop中才會起作用。
常見的創(chuàng)建timer方式
// 第一種方式 @property (nonatomic , strong) NSTimer *timer;// 默認加入當前runloop的NSDefaultRunLoopMode self.timer = [NSTimer scheduledTimerWithTimeInterval:1.0 target:self selector:@selector(timerAction:) userInfo:nil repeats:NO]; // 第二種方式 self.timer = [NSTimer timerWithTimeInterval:1.0 target:self selector:@selector(timerAction:) userInfo:nil repeats:YES];第一種缺陷如果當前線程就是主線程,也就是UI線程時,某些UI事件,比如UIScrollView的拖動操作,會將Run Loop切換成NSEventTrackingRunLoopMode模式,在這個過程中,默認的NSDefaultRunLoopMode模式中注冊的事件是不會被執(zhí)行的。也就是說,此時使用scheduledTimerWithTimeInterval添加到Run Loop中的Timer就不會執(zhí)行
第二種方式需要使用NSRunLoop的addTimer:forMode:方法來把Timer按照指定模式加入到Run Loop中。這里使用的模式是:NSRunLoopCommonModes,這個模式等效于NSDefaultRunLoopMode和NSEventTrackingRunLoopMode的結合
- 以上兩種方式都是在主線程上創(chuàng)建的,如果在子線程創(chuàng)建的timer,加入到runloop則需要手動開啟runloop[[NSRunLoop currentRunLoop] run];,同時也必須在子線程銷毀。
2.NSTimer會強引用它的target對象。
- [self.timer invalidate]是唯一的方法將定時器從循環(huán)池中移除
- 當我們在控制器中創(chuàng)建timer且tager設為self時。
- 會發(fā)生 timer 添加到 Runloop 的時候,且會被 Runloop 強引用,
- Note in particular that run loops maintain strong references to their timers, so you don’t have to maintain your own strong reference to a timer after you have added it to a run loop.
- 然后 Timer 又會有一個對 Target 的強引用(也就是 self )
- Target is the object to which to send the message specified by aSelector when the timer fires. The timer maintains a strong reference to target until it (the timer) is invalidated.
也就是說 NSTimer 強引用了 self ,self的全局變量 NSTimer 又使 self 強引用了 NSTimer,導致 self 一直不能被釋放掉,所以也就走不到 self 的 dealloc 里。
此時我們就會想把 Target 設置為 weakSelf ,運行后也不起作用. 是由于我們的 self 和 weakSelf 都是指針指向控制器,控制器的dealloc需要timer的銷毀才調用。同樣造成相互強引用。
__weak typeof(self) weakSelf = self; self.timer = [NSTimer scheduledTimerWithTimeInterval:1.0 target:weakSelf selector:@selector(timerAction:) userInfo:nil repeats:NO];此時我們又想到下面那種把timer設為weak,此時是直接運行造成壞內(nèi)存訪問,因為timer創(chuàng)建就銷毀
- 另一種當我們在創(chuàng)建完timer后 置為nil,NSTimer還會不會起作用,答案是會起作用。因為Runloop對NSTimer 有了強引用,指向NSTimer那塊內(nèi)存。
3.解決runloop循環(huán)引用
- iOS 10.0 以后增加兩個創(chuàng)建方法
自定義分類創(chuàng)建NSTimer,適用于iOS 10以前
- 原理等同于以上方法,把 target 轉換為 NSTimer 自身然后把控制器的定時器方法在block方法中保存執(zhí)行。
4.使用 GCD 定時器
// GCD 定時器 - (void)timerNine {__weak typeof(self) weakSelf = self;dispatch_queue_t queue = dispatch_queue_create("SYLingGCDTimer", DISPATCH_QUEUE_CONCURRENT);dispatch_source_t timer = dispatch_source_create(DISPATCH_SOURCE_TYPE_TIMER, 0, 0, queue);// leewayInSeconds 精準度dispatch_source_set_timer(timer, DISPATCH_TIME_NOW, 1.0 * NSEC_PER_SEC, 0 * NSEC_PER_SEC);dispatch_source_set_event_handler(timer, ^{// code to be executed when timer firestimer;[weakSelf timerAction];});dispatch_resume(timer); }Demo地址
我的博客即將搬運同步至騰訊云+社區(qū),邀請大家一同入駐:https://cloud.tencent.com/developer/support-plan?invite_code=1ritpp1xqps9u
轉載于:https://www.cnblogs.com/ShaoYinling/p/8859056.html
總結
以上是生活随笔為你收集整理的自欺欺人的使用 NSTimer 销毁的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 面向对象精要-理解对象
- 下一篇: 爬虫学习day1