最近在開發(fā)中計(jì)劃實(shí)現(xiàn)一個(gè)滾動(dòng)新聞(TableView的其中cell中實(shí)現(xiàn)),于是我定義了一個(gè)NSTimer定時(shí)器開實(shí)現(xiàn)一直滾動(dòng),但是當(dāng)我發(fā)現(xiàn)了當(dāng)我拖懂TableView時(shí)候,滾動(dòng)新聞就停止了.
于是我首先想到的是用GCD創(chuàng)建一個(gè)異步線程,將定時(shí)器放到這里,為了讓定時(shí)器更準(zhǔn)確,我在定時(shí)器后面添加了[[NSRunLoop currentRunLoop] run];(因?yàn)槎〞r(shí)器在子線程中默認(rèn)是不啟動(dòng)的) 之后確實(shí)實(shí)現(xiàn)了拖動(dòng)tableView的時(shí)候,滾動(dòng)新聞也滾動(dòng),但是dang當(dāng)進(jìn)入別的頁(yè)面在返回當(dāng)前頁(yè)面的時(shí)候,有時(shí)會(huì)發(fā)生內(nèi)存錯(cuò)誤
-[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:] |
我才發(fā)現(xiàn)是之前nstimer定時(shí)器的問題
經(jīng)過查閱資料和別人幫助終于找到了解決方案
直接在主線程設(shè)置NSTimer
self.timer = [NSTimer scheduledTimerWithTimeInterval:0.2 target:self selector:@selector(timerChanged:) userInfo:nil repeats:YES];
[[NSRunLoop currentRunLoop] addTimer:_timer forMode:NSRunLoopCommonModes];
//:NSRunLoopCommonModes,這個(gè)模式等效于NSDefaultRunLoopMode和NSEventTrackingRunLoopMode的結(jié)合。
結(jié)論
當(dāng)系統(tǒng)啟動(dòng)時(shí)會(huì)默認(rèn)創(chuàng)建一個(gè)runloop模式是NSDefaultRunLoopMode,當(dāng)使用NSTimer的scheduledTimerWithTimeInterval方法時(shí)。事實(shí)上此時(shí)Timer會(huì)被加入到當(dāng)前線程的RunLoop中,且模式是默認(rèn)的NSDefaultRunLoopMode。而如果當(dāng)前線程就是主線程,也就是UI線程時(shí),某些UI事件,比如UIScrollView的拖動(dòng)操作,會(huì)將Run Loop切換成NSEventTrackingRunLoopMode模式,在這個(gè)過程中,默認(rèn)的NSDefaultRunLoopMode模式中注冊(cè)的事件是不會(huì)被執(zhí)行的。也就是說,此時(shí)使用scheduledTimerWithTimeInterval添加到Run Loop中的Timer就不會(huì)執(zhí)行。
所以為了設(shè)置一個(gè)不被UI干擾的Timer,我們需要手動(dòng)創(chuàng)建一個(gè)Timer,然后使用NSRunLoop的addTimer:forMode:方法來把Timer按照指定模式加入到Run Loop中。這里使用的模式是:NSRunLoopCommonModes,這個(gè)模式等效于NSDefaultRunLoopMode和NSEventTrackingRunLoopMode的結(jié)合。
這個(gè)問題開啟了我對(duì)runloop的學(xué)習(xí)的興趣