iOS 中的timer --- NSRunLoopCommonModes和Timer .NSThread和Timer.GCD中的Timer

1. NSRunLoopCommonModes和Timer

  • 當(dāng)使用NSTimer的scheduledTimerWithTimeInterval方法時(shí)匕坯。事實(shí)上此時(shí)Timer會(huì)被加入到當(dāng)前線程的Run Loop中袭异,且模式是默認(rèn)的NSDefaultRunLoopMode掀亩。而如果當(dāng)前線程就是主線程菜谣,也就是UI線程時(shí)衰伯,某些UI事件砍的,比如UIScrollView的拖動(dòng)操作蹂喻,會(huì)將Run Loop切換成NSEventTrackingRunLoopMode模式筏餐,在這個(gè)過(guò)程中开泽,默認(rèn)的NSDefaultRunLoopMode模式中注冊(cè)的事件是不會(huì)被執(zhí)行的。也就是說(shuō)魁瞪,此時(shí)使用scheduledTimerWithTimeInterval添加到Run Loop中的Timer就不會(huì)執(zhí)行穆律。
  • 所以為了設(shè)置一個(gè)不被UI干擾的Timer,我們需要手動(dòng)創(chuàng)建一個(gè)Timer导俘,然后使用NSRunLoop的addTimer:forMode:方法來(lái)把Timer按照指定模式加入到Run Loop中峦耘。這里使用的模式是:NSRunLoopCommonModes,這個(gè)模式等效于NSDefaultRunLoopMode和NSEventTrackingRunLoopMode的結(jié)合旅薄。(參考Apple文檔

參考代碼:

- (void)viewDidLoad

{

    [super viewDidLoad];

    NSLog(@"主線程 %@", [NSThread currentThread]);

    //創(chuàng)建Timer

    NSTimer *timer = [NSTimer timerWithTimeInterval:2.0 target:self selector:@selector(timer_callback)userInfo:nil repeats:YES];

    //使用NSRunLoopCommonModes模式辅髓,把timer加入到當(dāng)前Run Loop中。

    [[NSRunLoop currentRunLoop] addTimer:timer forMode:NSRunLoopCommonModes];

}

//timer的回調(diào)方法

- (void)timer_callback

{

    NSLog(@"Timer %@", [NSThread currentThread]);

}

輸出:

主線程 <NSThread: 0x71501e0>{name = (null), num = 1}

Timer <NSThread: 0x71501e0>{name = (null), num = 1}

Timer <NSThread: 0x71501e0>{name = (null), num = 1}

Timer <NSThread: 0x71501e0>{name = (null), num = 1}

2. NSThread和Timer

上面講的NSRunLoopCommonModes和Timer中有一個(gè)問(wèn)題少梁,這個(gè)Timer本質(zhì)上是在當(dāng)前線程的Run Loop中循環(huán)執(zhí)行的洛口,因此Timer的回調(diào)方法不是在另一個(gè)線程的。那么怎樣在真正的多線程環(huán)境下運(yùn)行一個(gè)Timer呢凯沪?

可以先試試NSThread第焰。同上,我們還是會(huì)把Timer加到Run Loop中妨马,只不過(guò)這個(gè)是在另一個(gè)線程中挺举,因此我們需要手動(dòng)執(zhí)行Run Loop(通過(guò)NSRunLoop的run方法)而叼,同時(shí)注意在新的線程執(zhí)行中加入@autoreleasepool。

完整代碼如下:

- (void)viewDidLoad

{

    [super viewDidLoad];

    NSLog(@"主線程 %@", [NSThread currentThread]);

    //創(chuàng)建并執(zhí)行新的線程

    NSThread *thread = [[NSThread alloc] initWithTarget:self selector:@selector(newThread) object:nil];

    [thread start];

}

- (void)newThread

{

    @autoreleasepool

    {

        //在當(dāng)前Run Loop中添加timer豹悬,模式是默認(rèn)的NSDefaultRunLoopMode

        [NSTimer scheduledTimerWithTimeInterval:2.0 target:self selector:@selector(timer_callback)userInfo:nil repeats:YES];

        //開(kāi)始執(zhí)行新線程的Run Loop

        [[NSRunLoop currentRunLoop] run];

    }

}

//timer的回調(diào)方法

- (void)timer_callback

{

    NSLog(@"Timer %@", [NSThread currentThread]);

}

輸出:

主線程 <NSThread: 0x7118800>{name = (null), num = 1}

Timer <NSThread: 0x715c2e0>{name = (null), num = 3}

Timer <NSThread: 0x715c2e0>{name = (null), num = 3}

Timer <NSThread: 0x715c2e0>{name = (null), num = 3}

[返回目錄](méi)(http://www.cnblogs.com/mgen/p/3276722.html#_hContent)

3. GCD中的Timer

GCD中的Timer應(yīng)該是最靈活的葵陵,而且是多線程的。GCD中的Timer是靠Dispatch Source來(lái)實(shí)現(xiàn)的瞻佛。

因此先需要聲明一個(gè)dispatch_source_t本地變量:

@interface ViewController ()

{

    dispatch_source_t _timer;

}

接著通過(guò)dispatch_source_create函數(shù)來(lái)創(chuàng)建一個(gè)專(zhuān)門(mén)的Dispatch Source脱篙,接著通過(guò)dispatch_source_set_timer函數(shù)來(lái)設(shè)置Timer的參數(shù),注意這里的時(shí)間參數(shù)有些蛋疼伤柄。

開(kāi)始時(shí)間的類(lèi)型是dispatch_time_t绊困,最好用dispatch_time或者dispatch_walltime函數(shù)來(lái)創(chuàng)建dispatch_time_t對(duì)象。如果需要Timer立即執(zhí)行适刀,可以傳入dispatch_time(DISPATCH_TIME_NOW, 0)秤朗。

internal和leeway參數(shù)分別表示Timer的間隔時(shí)間和精度。類(lèi)型都是uint64_t笔喉。間隔時(shí)間的單位竟然是納秒取视。可以借助預(yù)定義的NSEC_PER_SEC宏常挚,比如如果間隔時(shí)間是兩秒的話作谭,那interval參數(shù)就是:2 * NSEC_PER_SEC。

leeway就是精度參數(shù)奄毡,代表系統(tǒng)可以延時(shí)的時(shí)間間隔折欠,最高精度當(dāng)然就傳0。

然后通過(guò)dispatch_source_set_event_handler函數(shù)來(lái)設(shè)置Dispatch Source的事件回調(diào)吼过,這里當(dāng)然是使用Block了锐秦。

最后所有dispatch_source_t創(chuàng)建后默認(rèn)都是暫停狀態(tài)的,所以必須通過(guò)dispatch_resume函數(shù)來(lái)開(kāi)始事件監(jiān)聽(tīng)盗忱。這里就代表著開(kāi)始Timer酱床。

完整代碼:

NSLog(@"主線程 %@", [NSThread currentThread]);

//間隔還是2秒

uint64_t interval = 2 * NSEC_PER_SEC;

//創(chuàng)建一個(gè)專(zhuān)門(mén)執(zhí)行timer回調(diào)的GCD隊(duì)列

dispatch_queue_t queue = dispatch_queue_create("my queue", 0);

//創(chuàng)建Timer

_timer = dispatch_source_create(DISPATCH_SOURCE_TYPE_TIMER, 0, 0, queue);

//使用dispatch_source_set_timer函數(shù)設(shè)置timer參數(shù)

dispatch_source_set_timer(_timer, dispatch_time(DISPATCH_TIME_NOW, 0), interval, 0);

//設(shè)置回調(diào)

dispatch_source_set_event_handler(_timer, ^()

{

    NSLog(@"Timer %@", [NSThread currentThread]);

});

//dispatch_source默認(rèn)是Suspended狀態(tài),通過(guò)dispatch_resume函數(shù)開(kāi)始它

dispatch_resume(_timer);

輸出:

主線程 <NSThread: 0x711fab0>{name = (null), num = 1}

Timer <NSThread: 0x713a380>{name = (null), num = 3}

Timer <NSThread: 0x713a380>{name = (null), num = 3}

Timer <NSThread: 0x713a380>{name = (null), num = 3

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末售淡,一起剝皮案震驚了整個(gè)濱河市斤葱,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌揖闸,老刑警劉巖,帶你破解...
    沈念sama閱讀 218,122評(píng)論 6 505
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件料身,死亡現(xiàn)場(chǎng)離奇詭異汤纸,居然都是意外死亡,警方通過(guò)查閱死者的電腦和手機(jī)芹血,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,070評(píng)論 3 395
  • 文/潘曉璐 我一進(jìn)店門(mén)贮泞,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái)楞慈,“玉大人,你說(shuō)我怎么就攤上這事啃擦∧依叮” “怎么了?”我有些...
    開(kāi)封第一講書(shū)人閱讀 164,491評(píng)論 0 354
  • 文/不壞的土叔 我叫張陵令蛉,是天一觀的道長(zhǎng)聚霜。 經(jīng)常有香客問(wèn)我,道長(zhǎng)珠叔,這世上最難降的妖魔是什么蝎宇? 我笑而不...
    開(kāi)封第一講書(shū)人閱讀 58,636評(píng)論 1 293
  • 正文 為了忘掉前任,我火速辦了婚禮祷安,結(jié)果婚禮上姥芥,老公的妹妹穿的比我還像新娘。我一直安慰自己汇鞭,他們只是感情好凉唐,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,676評(píng)論 6 392
  • 文/花漫 我一把揭開(kāi)白布。 她就那樣靜靜地躺著霍骄,像睡著了一般熊榛。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上腕巡,一...
    開(kāi)封第一講書(shū)人閱讀 51,541評(píng)論 1 305
  • 那天玄坦,我揣著相機(jī)與錄音,去河邊找鬼绘沉。 笑死煎楣,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的车伞。 我是一名探鬼主播择懂,決...
    沈念sama閱讀 40,292評(píng)論 3 418
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼另玖!你這毒婦竟也來(lái)了困曙?” 一聲冷哼從身側(cè)響起,我...
    開(kāi)封第一講書(shū)人閱讀 39,211評(píng)論 0 276
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤谦去,失蹤者是張志新(化名)和其女友劉穎慷丽,沒(méi)想到半個(gè)月后,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體鳄哭,經(jīng)...
    沈念sama閱讀 45,655評(píng)論 1 314
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡要糊,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,846評(píng)論 3 336
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了妆丘。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片锄俄。...
    茶點(diǎn)故事閱讀 39,965評(píng)論 1 348
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡局劲,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出奶赠,到底是詐尸還是另有隱情鱼填,我是刑警寧澤,帶...
    沈念sama閱讀 35,684評(píng)論 5 347
  • 正文 年R本政府宣布毅戈,位于F島的核電站苹丸,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏竹祷。R本人自食惡果不足惜谈跛,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,295評(píng)論 3 329
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望塑陵。 院中可真熱鬧感憾,春花似錦、人聲如沸令花。這莊子的主人今日做“春日...
    開(kāi)封第一講書(shū)人閱讀 31,894評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)兼都。三九已至嫂沉,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間扮碧,已是汗流浹背趟章。 一陣腳步聲響...
    開(kāi)封第一講書(shū)人閱讀 33,012評(píng)論 1 269
  • 我被黑心中介騙來(lái)泰國(guó)打工, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留慎王,地道東北人蚓土。 一個(gè)月前我還...
    沈念sama閱讀 48,126評(píng)論 3 370
  • 正文 我出身青樓,卻偏偏與公主長(zhǎng)得像赖淤,于是被迫代替她去往敵國(guó)和親蜀漆。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,914評(píng)論 2 355

推薦閱讀更多精彩內(nèi)容