日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

自欺欺人的使用 NSTimer 销毁

發布時間:2025/3/20 编程问答 32 豆豆
生活随笔 收集整理的這篇文章主要介紹了 自欺欺人的使用 NSTimer 销毁 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

自欺欺人的使用 NSTimer 銷毀

Demo地址

1.NSTimer是要加到runloop中才會起作用。

常見的創建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模式中注冊的事件是不會被執行的。也就是說,此時使用scheduledTimerWithTimeInterval添加到Run Loop中的Timer就不會執行

  • 第二種方式需要使用NSRunLoop的addTimer:forMode:方法來把Timer按照指定模式加入到Run Loop中。這里使用的模式是:NSRunLoopCommonModes,這個模式等效于NSDefaultRunLoopMode和NSEventTrackingRunLoopMode的結合

[[NSRunLoop mainRunLoop] addTimer:self.timer forMode:NSRunLoopCommonModes];
  • 以上兩種方式都是在主線程上創建的,如果在子線程創建的timer,加入到runloop則需要手動開啟runloop[[NSRunLoop currentRunLoop] run];,同時也必須在子線程銷毀。

2.NSTimer會強引用它的target對象。

  • [self.timer invalidate]是唯一的方法將定時器從循環池中移除
- (void)dealloc {// 自欺欺人的寫法,永遠都不會執行到,除非你在外部手動invalidate這個timer[self.timer invalidate]; }
  • 當我們在控制器中創建timer且tager設為self時。
  • 會發生 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,此時是直接運行造成壞內存訪問,因為timer創建就銷毀

@property (nonatomic , strong) NSTimer *timer; self.timer = [NSTimer timerWithTimeInterval:1.0 target:self selector:@selector(timerAction:) userInfo:nil repeats:YES]; [[NSRunLoop currentRunLoop] addTimer:self.timer forMode:NSRunLoopCommonModes];
  • 另一種當我們在創建完timer后 置為nil,NSTimer還會不會起作用,答案是會起作用。因為Runloop對NSTimer 有了強引用,指向NSTimer那塊內存。
self.timer = [NSTimer scheduledTimerWithTimeInterval:1.0 target:self selector:@selector(timerAction) userInfo:nil repeats:YES]; self.timer = nil;

3.解決runloop循環引用

  • iOS 10.0 以后增加兩個創建方法
+ (NSTimer *)timerWithTimeInterval:(NSTimeInterval)interval repeats:(BOOL)repeats block:(void (^)(NSTimer *timer))block API_AVAILABLE(macosx(10.12), ios(10.0), watchos(3.0), tvos(10.0));+ (NSTimer *)scheduledTimerWithTimeInterval:(NSTimeInterval)interval repeats:(BOOL)repeats block:(void (^)(NSTimer *timer))block API_AVAILABLE(macosx(10.12), ios(10.0), watchos(3.0), tvos(10.0));
自定義分類創建NSTimer,適用于iOS 10以前
  • 原理等同于以上方法,把 target 轉換為 NSTimer 自身然后把控制器的定時器方法在block方法中保存執行。
+ (instancetype)syl_timerWithTimeInterval:(NSTimeInterval)time repeats:(BOOL)repeats block:(void (^)(NSTimer *timer))block {// 此時的 target 為 NSTimerreturn [NSTimer timerWithTimeInterval:time target:self selector:@selector(timeAction:) userInfo:block repeats:repeats]; }+ (void)timeAction:(NSTimer *)timer {void (^block)(NSTimer *) = [timer userInfo];!block?:block(timer); }

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地址

我的博客即將搬運同步至騰訊云+社區,邀請大家一同入駐:https://cloud.tencent.com/developer/support-plan?invite_code=1ritpp1xqps9u

轉載于:https://www.cnblogs.com/ShaoYinling/p/8859056.html

總結

以上是生活随笔為你收集整理的自欺欺人的使用 NSTimer 销毁的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。