拖動scrollView時定時器活動停止的解決方案

weixin_34365417發表於2016-10-18

最近在開發中計劃實現一個滾動新聞(TableView的其中cell中實現),於是我定義了一個NSTimer定時器開實現一直滾動,但是當我發現了當我拖懂TableView時候,滾動新聞就停止了.
於是我首先想到的是用GCD建立一個非同步執行緒,將定時器放到這裡,為了讓定時器更準確,我在定時器後面新增了[[NSRunLoop currentRunLoop] run];(因為定時器在子執行緒中預設是不啟動的) 之後確實實現了拖動tableView的時候,滾動新聞也滾動,但是dang當進入別的頁面在返回當前頁面的時候,有時會發生記憶體錯誤

-[UIViewAnimationState class]: message sent to deallocated instance 0x7fc9ec351490

在終端定位找到

rollNewCell timer] | -[NSRunLoop(NSRunLoop) run] | -[NSRunLoop(NSRunLoop) runMode:beforeDate:] | CFRunLoopRunSpecific | __CFRunLoopRun | __CFRunLoopDoTimer | __CFRUNLOOP_IS_CALLING_OUT_TO_A_TIMER_CALLBACK_FUNCTION__ | __NSFireTimer | -[SQ_ScrollNewCell timerChanged:] |

我才發現是之前nstimer定時器的問題

經過查閱資料和別人幫助終於找到了解決方案

直接在主執行緒設定NSTimer

  self.timer = [NSTimer scheduledTimerWithTimeInterval:0.2 target:self selector:@selector(timerChanged:) userInfo:nil repeats:YES];
     [[NSRunLoop currentRunLoop] addTimer:_timer forMode:NSRunLoopCommonModes];
//:NSRunLoopCommonModes,這個模式等效於NSDefaultRunLoopMode和NSEventTrackingRunLoopMode的結合。
  • 結論

  • 當系統啟動時會預設建立一個runloop模式是NSDefaultRunLoopMode,當使用NSTimer的scheduledTimerWithTimeInterval方法時。事實上此時Timer會被加入到當前執行緒的RunLoop中,且模式是預設的NSDefaultRunLoopMode。而如果當前執行緒就是主執行緒,也就是UI執行緒時,某些UI事件,比如UIScrollView的拖動操作,會將Run Loop切換成NSEventTrackingRunLoopMode模式,在這個過程中,預設的NSDefaultRunLoopMode模式中註冊的事件是不會被執行的。也就是說,此時使用scheduledTimerWithTimeInterval新增到Run Loop中的Timer就不會執行。

  • 所以為了設定一個不被UI干擾的Timer,我們需要手動建立一個Timer,然後使用NSRunLoop的addTimer:forMode:方法來把Timer按照指定模式加入到Run Loop中。這裡使用的模式是:NSRunLoopCommonModes,這個模式等效於NSDefaultRunLoopMode和NSEventTrackingRunLoopMode的結合。

  • 這個問題開啟了我對runloop的學習的興趣

相關文章