你了解RunLoop線程敝缈福活嗎?已封裝好,2句代碼直接使用

如果你沒有了解RunLoop的一些基礎(chǔ),建議你看看這2篇博客,對線程贝缙耄活本質(zhì)理解有很大幫助

中高級iOS必備知識點之 RunLoop(一)

源碼解讀RunLoop,理解以后面試必加分

(溫馨提示:這里是一步一步探究,步驟過程比較多,如嫌棄啰嗦,可直接拿后面封裝的代碼直,2句即可完美使用.)

我們面試中經(jīng)常遇到很多面試官,問我們關(guān)于RunLoop的知識點,可能我們大多數(shù)人了解RunLoop,但在項目中,我們真正用到RunLoop還是比較少的,RunLoop其實應(yīng)用場景還是比較多,比如我們的定時器、線程背常活渺鹦、性能優(yōu)化、監(jiān)控應(yīng)用卡頓.這個博客主要介紹的是'線程庇己活'

現(xiàn)在的網(wǎng)絡(luò)請求基本都是用的AFNetworking這個框架,相信大家對它很了解,而它里面就是用RunLoop來控制子線程的生命周期.它會讓子線程一直存在內(nèi)存中不釋放,這種好處就是對于我們經(jīng)常去子線程做事情的話,我們就不必一直去創(chuàng)建-銷毀-創(chuàng)建-銷毀,這樣能很大的提高性能,好處也是多多.

接下來我們來看看怎么能做到控制一個線程的生命周期(也就是線程币缡活),想讓它活多久就多久,想讓它什么時候銷毀就什么時候銷毀.

還是老樣子,由簡單到復(fù)雜,我們創(chuàng)建一個線程,這個用NSThread為例子(也可以用PThread,Operation,GCD都可以)

為了能看到線程是什么時候銷毀的,我們可以定一個MyThread,繼承NSThread,

@interface?MyThread : NSThread

并在.m文件,主要監(jiān)測線程啥時候銷毀.

-(void)dealloc{

? ? NSLog(@"%s",__func__);

}

這樣我們就能很清楚的看到MyThread啥時候銷毀:

很清楚,上面的代碼執(zhí)行完NSThread就掛了.所以我們在開發(fā)中如果有需要經(jīng)常在子線程干事情,是不是就是希望這個線程能一直不銷毀,這樣就避免了一直創(chuàng)建-銷毀-創(chuàng)建-銷毀.

那我們怎么處理?直接在子線程加一個runloop,因為我們知道在獲取runloop的時候,就會創(chuàng)建runloop

還是沒能成功,如果你有細(xì)看我之前的2篇博客,你會注意到有一點:

如果Mode里面沒有任何Source0/Source1/Timer/Observer,RunLoop會立馬退出

所以我們只要在runloop里面加上任何一個就能保證線程不退出,那我們立刻試試:

? 因為是子線程,我們只用NSDefaultRunLoopMode就行了,不用考慮另一個模式

我們再想想,run方法只是達(dá)到了線程苯汗活的功能,真正要執(zhí)行的應(yīng)該還是在這個線程上去執(zhí)行另外的操作.所以我完整的寫一個線程保活的例子,如下:

上面就是一個簡單的線程保活的例子,其實這個是存在一些弊端的,那我們繼續(xù)探究一下.

'線程闭诳В活'存在的問題再探究

為了代碼簡潔易懂,我換一個block創(chuàng)建,跟上面的效果是一模一樣,便于理解,我先是創(chuàng)建2個控制器的跳轉(zhuǎn),因為我想看看,控制器銷毀的時候,線程會不會也跟著銷毀.請看下面的代碼:

看控制臺很明顯,此時并沒有達(dá)到我們想要的結(jié)果,雖然線程確實一直存在,能一直幫我做事情(控制臺可以一直輸出test),但是我們發(fā)現(xiàn)控制器銷毀了,而控制器上的線程卻沒有跟著銷毀!我們看不到控制臺有輸出.那是怎么回事呢?難道出現(xiàn)循環(huán)引用?很明顯不是!

難道是self.Mythread沒有清空?你把self.MyThread = nil;寫在VC的dealloc里面,你會發(fā)現(xiàn),線程依然不會銷毀!

原因是線程一直沒有執(zhí)行完,它一直卡在[[NSRunLoop currentRunLoop] run]這段代碼,所以NSLog(@"---- end ----")也一直沒有執(zhí)行,線程都沒有結(jié)束,所以它不會銷毀.所以如果你想要一個全局的線程,任何頁面都可以調(diào)用,永遠(yuǎn)不用銷毀的話,那這個線程就能達(dá)到這個效果.現(xiàn)在我們想要的效果肯定是在當(dāng)前頁面存在,這個VC銷毀的時候,線程也會銷毀,我們想控制這個線程的生命周期,想讓它銷毀它就銷毀.那我們繼續(xù)看看怎么處理.

我們知道線程執(zhí)行結(jié)束,線程就會銷毀,只要執(zhí)行NSLog(@"---- end ----"),就能讓線程銷毀,所以我們明顯的思路就是在VC的dealloc里面停止self.MyThread線程的RunLoop.請看下面的代碼.

線程依舊沒有銷毀.

有可能有的人會認(rèn)為,這很有可能是執(zhí)行dealloc說明VC快銷毀了,你在快銷毀的VC中執(zhí)行stop方法,是不是來不及呢?那這樣,我用按鈕執(zhí)行stop事件.請看下圖

此時發(fā)現(xiàn),線程依舊沒有銷毀(log中沒有輸出線程的dealloc).

[[NSRunLoop currentRunLoop] run]無限循環(huán);

其實是這個[[NSRunLoop currentRunLoop] run];這個原因?qū)е碌?我們先看官方的解釋,對于這個方法.

看這個上面紅色的翻譯大致意思是:這個方法是無限循環(huán)的執(zhí)行runMode:beforeDate,它是很有效的處理一個無限循環(huán)的.大概類似

white(1)

{runMode:beforeDate}

所以我們大概知道,這個方法是無限循環(huán)也就是關(guān)不了,可以理解為死循環(huán).而我們執(zhí)行的CFRunLoopStop(CFRunLoopGetCurrent()),其實只是停止它無限循環(huán)中的一次runMode:beforeDate,因為它會不斷創(chuàng)建,所以無法全部停止,所以我們很自然想到用runMode:beforeDate這個方法來嘗試解決.

看控制臺的輸出,我們確實是完成了想用它就用它,不用它就讓它銷毀的操作,也完成了控制器銷毀時候,線程也會銷毀.(Stop是一個BOOL值,[NSDate distantFuture]是一個很大的值.)

但是上面的還是不夠完美,我們看看同樣的代碼,假如我們其他操作會不會出現(xiàn)什么問題,比如我們很可能不會點擊停止,直接點返回,此時我們也想銷毀線程,所以我們想著在VC的dealloc里面調(diào)用stop方法試試,請看下面:

看上面的操作,此時應(yīng)該控制器銷毀,而線程依舊還是沒有銷毀

為什么點擊調(diào)用stop就可以使線程銷毀,而在dealloc里面調(diào)用stop就不能使線程銷毀?

我們當(dāng)前這個寫法先看一個注意點:waitUntilDone這個傳值如果傳NO有時候可能導(dǎo)致崩潰,原因如下:

有可能出現(xiàn)的情況

所以上面的參數(shù)我改成YES.

而線程不銷毀的原因是這樣:

再執(zhí)行到這邊的時候,while()里面的條件還是一直是YES,導(dǎo)致還是會一直重復(fù)執(zhí)行里面代碼,所以runloop還是會一直運行.所以我們把條件改一下即可:?while(!weakSelf.Stop&& weakSelf) 把條件改成這個即可(如果這里用__strong處理可能產(chǎn)生循環(huán)引用).

看運行結(jié)果,這種操作完美解決!

我們再驗證一下之前點擊停止的那種模式有沒有影響!你會發(fā)現(xiàn)又崩了!如下:

原因很簡單:點擊停止已經(jīng)調(diào)用了stop,RunLoop已經(jīng)結(jié)束了,它已經(jīng)不能做事情了,只是沒有銷毀.你返回的時候dealloc又調(diào)用了stop,又讓它去工作,肯定會出問題的.所以我們只要加一個判斷即可:

這下真的完美解決了,如論怎么操作,線程和控制器都會銷毀!我們看一下成果:

結(jié)果完美展示

這里我們發(fā)現(xiàn)很多步驟才出來結(jié)果,而且是感覺還有點麻煩,那我們直接封裝即可:

線程的封裝:

封裝用起來就非常容易了.先看執(zhí)行調(diào)用代碼,再看封裝

封裝以后就剩這3句,初始化,調(diào)用做事,停止,代碼很少,很好用,請看效果:

完美解決了這個問題.請看下面封裝代碼:(就是把我們之前寫的,封裝起來了):

到這里,我們基本把要說的都說了,該封裝的已經(jīng)封裝了,有需要可以直接拿去調(diào)用!

因為理論上控制器銷毀了,線程也會跟著銷毀,所以控制的dealloc里面應(yīng)該是不用調(diào)用stop,按照這個思路我們直接在GDThread的dealloc里面調(diào)用stop方法即可,那封裝的線程將變得更簡單,只有2步操作即可.,初始化,調(diào)用做事!

2句代碼完成保活!

拓展--C語言的封裝

有上面的封裝其實已經(jīng)可以,用C語言的封裝作為了解一下:

只要換了紅色圈圈的內(nèi)容即可,其他的都和原來一樣,這里也是可以直接使用.

接下來我會繼續(xù)努力編寫其他博客,您的支持就是我最大的動力!

如果覺得我寫得對您有所幫助继找,請點贊關(guān)注我耕捞,我會持續(xù)更新??

感謝支持??????!

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市蓬推,隨后出現(xiàn)的幾起案子板乙,更是在濱河造成了極大的恐慌,老刑警劉巖,帶你破解...
    沈念sama閱讀 207,113評論 6 481
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件募逞,死亡現(xiàn)場離奇詭異蛋铆,居然都是意外死亡,警方通過查閱死者的電腦和手機放接,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,644評論 2 381
  • 文/潘曉璐 我一進(jìn)店門刺啦,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人纠脾,你說我怎么就攤上這事玛瘸。” “怎么了苟蹈?”我有些...
    開封第一講書人閱讀 153,340評論 0 344
  • 文/不壞的土叔 我叫張陵糊渊,是天一觀的道長。 經(jīng)常有香客問我慧脱,道長渺绒,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 55,449評論 1 279
  • 正文 為了忘掉前任菱鸥,我火速辦了婚禮宗兼,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘氮采。我一直安慰自己殷绍,他們只是感情好,可當(dāng)我...
    茶點故事閱讀 64,445評論 5 374
  • 文/花漫 我一把揭開白布鹊漠。 她就那樣靜靜地躺著主到,像睡著了一般。 火紅的嫁衣襯著肌膚如雪躯概。 梳的紋絲不亂的頭發(fā)上镰烧,一...
    開封第一講書人閱讀 49,166評論 1 284
  • 那天,我揣著相機與錄音楞陷,去河邊找鬼怔鳖。 笑死,一個胖子當(dāng)著我的面吹牛固蛾,可吹牛的內(nèi)容都是我干的结执。 我是一名探鬼主播,決...
    沈念sama閱讀 38,442評論 3 401
  • 文/蒼蘭香墨 我猛地睜開眼艾凯,長吁一口氣:“原來是場噩夢啊……” “哼献幔!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起趾诗,我...
    開封第一講書人閱讀 37,105評論 0 261
  • 序言:老撾萬榮一對情侶失蹤蜡感,失蹤者是張志新(化名)和其女友劉穎蹬蚁,沒想到半個月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體郑兴,經(jīng)...
    沈念sama閱讀 43,601評論 1 300
  • 正文 獨居荒郊野嶺守林人離奇死亡犀斋,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 36,066評論 2 325
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了情连。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片叽粹。...
    茶點故事閱讀 38,161評論 1 334
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖却舀,靈堂內(nèi)的尸體忽然破棺而出虫几,到底是詐尸還是另有隱情,我是刑警寧澤挽拔,帶...
    沈念sama閱讀 33,792評論 4 323
  • 正文 年R本政府宣布辆脸,位于F島的核電站,受9級特大地震影響螃诅,放射性物質(zhì)發(fā)生泄漏啡氢。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點故事閱讀 39,351評論 3 307
  • 文/蒙蒙 一州刽、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧浪箭,春花似錦穗椅、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,352評論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至宣鄙,卻和暖如春袍镀,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背冻晤。 一陣腳步聲響...
    開封第一講書人閱讀 31,584評論 1 261
  • 我被黑心中介騙來泰國打工苇羡, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人鼻弧。 一個月前我還...
    沈念sama閱讀 45,618評論 2 355
  • 正文 我出身青樓设江,卻偏偏與公主長得像,于是被迫代替她去往敵國和親攘轩。 傳聞我的和親對象是個殘疾皇子叉存,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 42,916評論 2 344

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