国产探花免费观看_亚洲丰满少妇自慰呻吟_97日韩有码在线_资源在线日韩欧美_一区二区精品毛片,辰东完美世界有声小说,欢乐颂第一季,yy玄幻小说排行榜完本

首頁 > 學院 > 開發(fā)設計 > 正文

RunLoop 總結(jié):RunLoop的應用場景(二)

2019-11-09 14:51:15
字體:
供稿:網(wǎng)友

好的書籍都是值得反復看的,那好的文章,好的資料也值得我們反復看。我們在不同的階段來相同的文章或資料或書籍都能有不同的收獲,那它就是好文章,好書籍,好資料。關于iOS 中的RunLoop資料非常的少,以下資料都是非常好的。

CF框架源碼(這是一份很重要的源碼,可以看到CF框架的每一次迭代,我們可以下載最新的版本來分析,或與以下文章對比學習。目前最新的是CF-1153.18.tar.gz)

RunLoop官方文檔(學習iOS的任何技術,官方文檔都是入門或深入的極好手冊;我們也可以在Xcode--->Help--->Docementation and API Reference --->搜索RunLoop---> Guides(59)--->《Threading PRogramming Guide:Run Loops》這篇即是)

深入理解RunLoop(不要看到右邊滾動條很長,其實文章占篇幅2/5左右,下面有很多的評論,可見這篇文章的火熱)

RunLoop個人小結(jié) (這是一篇總結(jié)的很通俗容易理解的文章)

sunnyxx線下分享RunLoop(這是一份關于線下分享與討論RunLoop的視頻,備用地址:https://pan.baidu.com/s/1pLm4Vf9)

iphonedevwiki中的CFRunLoop(commonModes中其實包含了三種Mode,我們通常知道兩種,還有一種是啥,你知道么?)

維基百科中的Event loop(可以看看這篇文章了解一下事件循環(huán))

使用場景

1.我們經(jīng)常會在應用中看到tableView 的header 上是一個橫向ScrollView,一般我們使用NSTimer,每隔幾秒切換一張圖片。可是當我們滑動tableView的時候,頂部的scollView并不會切換圖片,這可怎么辦呢?2.界面上除了有tableView,還有顯示倒計時的Label,當我們在滑動tableView時,倒計時就停止了,這又該怎么辦呢?

場景中的代碼實現(xiàn)

我們的定時器Timer是怎么寫的呢?一般的做法是,在主線程(可能是某控制器的viewDidLoad方法)中,創(chuàng)建Timer。可能會有兩種寫法,但是都有上面的問題,下面先看下Timer的兩種寫法:

12345// 第一種寫法NSTimer *timer = [NSTimer timerWithTimeInterval:1.0 target:self selector:@selector(timerUpdate) userInfo:nil repeats:YES];[[NSRunLoop currentRunLoop] addTimer:timer forMode:NSDefaultRunLoopMode];[timer fire];// 第二種寫法NSTimer *timer = [NSTimer scheduledTimerWithTimeInterval:1.0 target:self selector:@selector(timerUpdate) userInfo:nil repeats:YES];[timer fire];

上面的兩種寫法其實是等價的。第二種寫法,默認也是將timer添加到NSDefaultRunLoopMode下的。要驗證這一結(jié)論,我們只需要在timerUpdate方法中,將當前runLoop的currentMode打印出來即可。

1234567891011121314- (void)timerUpdate{    NSLog(@"當前線程:%@",[NSThread currentThread]);    NSLog(@"啟動RunLoop后--%@",[NSRunLoop currentRunLoop].currentMode);//    NSLog(@"currentRunLoop:%@",[NSRunLoop currentRunLoop]);    dispatch_async(dispatch_get_main_queue(), ^{        self.count ++;        NSString *timerText = [NSString stringWithFormat:@"計時器:%ld",self.count];        self.timerLabel.text = timerText;    });}// 控制臺輸出結(jié)果:2016-12-02 15:33:57.829 RunLoopDemo02[6698:541533] 當前線程:<nsthread: 0x600000065500>{number = 1, name = main}2016-12-02 15:33:57.829 RunLoopDemo02[6698:541533] 啟動RunLoop后--kCFRunLoopDefaultMode</nsthread: 0x600000065500>

然后,我們在滑動tableView的時候timerUpdate方法,并不會調(diào)用。原因是啥呢?原因是當我們滑動scrollView時,主線程的RunLoop 會切換到UITrackingRunLoopMode這個Mode,執(zhí)行的也是UITrackingRunLoopMode下的任務(Mode中的item),而timer 是添加在NSDefaultRunLoopMode下的,所以timer任務并不會執(zhí)行,只有當UITrackingRunLoopMode的任務執(zhí)行完畢,runloop切換到NSDefaultRunLoopMode后,才會繼續(xù)執(zhí)行timer。

要如何解決這一問題呢?解決方法很簡單,我們只需要在添加timer 時,將mode 設置為NSRunLoopCommonModes即可。

12345678- (void)timerTest{    // 第一種寫法    NSTimer *timer = [NSTimer timerWithTimeInterval:1.0 target:self selector:@selector(timerUpdate) userInfo:nil repeats:YES];    [[NSRunLoop currentRunLoop] addTimer:timer forMode:NSRunLoopCommonModes];    [timer fire];    // 第二種寫法,因為是固定添加到defaultMode中,就不要用了}

從RunLoop官方文檔和 iPhonedevwiki中的CFRunLoop可以看出,NSRunLoopCommonModes并不是一種Mode,而是一種特殊的標記,包含三種mode(kCFRunLoopDefaultMode、NSTaskDeathCheckMode、UITrackingRunLoopMode),添加到NSRunLoopCommonModes中的還沒有執(zhí)行的任務,會在mode切換時,再次添加到當前的mode中,這樣就能保證不管當前runloop切換到哪一個mode,任務都能正常執(zhí)行。并且被添加到NSRunLoopCommonModes中的任務會存儲在runloop 的commonModeItems中。

其他一些關于timer的坑

我們在子線程中使用timer,也可以解決上面的問題,但是需要注意的是把timer加入到當前runloop后,必須讓runloop 運行起來,否則timer僅執(zhí)行一次。

示例代碼:

123456789101112131415161718192021222324252627282930313233343536//首先是創(chuàng)建一個子線程- (void)createThread{    NSThread *subThread = [[NSThread alloc] initWithTarget:self selector:@selector(timerTest) object:nil];    [subThread start];    self.subThread = subThread;} // 創(chuàng)建timer,并添加到runloop的mode中- (void)timerTest{    NSRunLoop *runLoop = [NSRunLoop currentRunLoop];    NSLog(@"啟動RunLoop前--%@",runLoop.currentMode);    NSLog(@"currentRunLoop:%@",[NSRunLoop currentRunLoop]);        // 第一種寫法,改正前//    NSTimer *timer = [NSTimer timerWithTimeInterval:1.0 target:self selector:@selector(timerUpdate) userInfo:nil repeats:YES];//    [[NSRunLoop currentRunLoop] addTimer:timer forMode:NSDefaultRunLoopMode];//    [timer fire];    // 第二種寫法    NSTimer *timer = [NSTimer scheduledTimerWithTimeInterval:1.0 target:self selector:@selector(timerUpdate) userInfo:nil repeats:YES];    [timer fire];    [[NSRunLoop currentRunLoop] run];} //更新label- (void)timerUpdate{    NSLog(@"當前線程:%@",[NSThread currentThread]);    NSLog(@"啟動RunLoop后--%@",[NSRunLoop currentRunLoop].currentMode);    NSLog(@"currentRunLoop:%@",[NSRunLoop currentRunLoop]);    dispatch_async(dispatch_get_main_queue(), ^{        self.count ++;        NSString *timerText = [NSString stringWithFormat:@"計時器:%ld",self.count];        self.timerLabel.text = timerText;    });}

添加timer 前的控制臺輸出:

001.png

添加timer前的runloop

添加timer后的控制臺輸出:

002.jpg

添加timer后的runloop

從控制臺輸出可以看出,timer確實被添加到NSDefaultRunLoopMode中了。可是添加到子線程中的NSDefaultRunLoopMode里,無論如何滾動,timer都能夠很正常的運轉(zhuǎn)。這又是為啥呢?

這就是多線程與runloop的關系了,每一個線程都有一個與之關聯(lián)的RunLoop,而每一個RunLoop可能會有多個Mode。CPU會在多個線程間切換來執(zhí)行任務,呈現(xiàn)出多個線程同時執(zhí)行的效果。執(zhí)行的任務其實就是RunLoop去各個Mode里執(zhí)行各個item。因為RunLoop是獨立的兩個,相互不會影響,所以在子線程添加timer,滑動視圖時,timer能正常運行。

總結(jié)

1、如果是在主線程中運行timer,想要timer在某界面有視圖滾動時,依然能正常運轉(zhuǎn),那么將timer添加到RunLoop中時,就需要設置mode 為NSRunLoopCommonModes。2、如果是在子線程中運行timer,那么將timer添加到RunLoop中后,Mode設置為NSDefaultRunLoopMode或NSRunLoopCommonModes均可,但是需要保證RunLoop在運行,且其中有任務。


發(fā)表評論 共有條評論
用戶名: 密碼:
驗證碼: 匿名發(fā)表
主站蜘蛛池模板: 曲阳县| 光泽县| 丽江市| 丘北县| 施秉县| 通州区| 九台市| 泉州市| 吉木萨尔县| 新邵县| 天水市| 乐亭县| 子洲县| 遂昌县| 凤山县| 巨鹿县| 明溪县| 绵竹市| 定襄县| 长汀县| 平武县| 宁城县| 夏津县| 南康市| 二连浩特市| 扎囊县| 会理县| 十堰市| 寻乌县| 通渭县| 兴宁市| 连云港市| 东辽县| 略阳县| 嘉荫县| 湄潭县| 喜德县| 南漳县| 铜鼓县| 五原县| 犍为县|