初探Runloop

1.runloop是什么?

runloop 是一個(gè)運(yùn)行循環(huán)(死循環(huán));

return UIApplicationMain(argc, argv, nil, NSStringFromClass([AppDelegate class])); 該句代碼默認(rèn)會(huì)開啟一個(gè)主線程

例證:


2.runloop有什么用? ? ?

? ? (1)保證線程不退出


? ? ? ?我們知道線程結(jié)束的條件是,線程中未有未執(zhí)行的任務(wù)

? ? ? ?所以為了保證主線程運(yùn)轉(zhuǎn),執(zhí)行 return UIApplicationMain(argc, argv, nil, ? ? ?NSStringFromClass([AppDelegate class])); 該句代碼創(chuàng)建了一個(gè)runloop

? ? ? 注意:(1)主線程:是指app啟動(dòng)時(shí)第一個(gè)創(chuàng)建的線程,在該線程中才能執(zhí)行UI有關(guān)操作,除此之外其實(shí)和其它子線程沒有區(qū)分,(這也是為什么UI作為屬性時(shí),使用的是nonatomic)

? ?(2)負(fù)責(zé)監(jiān)聽事件:觸摸事件、時(shí)鐘事件、網(wǎng)絡(luò)事件:


? ? ? ? 案例 ? 當(dāng)滑動(dòng)其他頁面時(shí),頂部輪播圖不會(huì)輪播

3.runloop和多線程

? (1) 線程默認(rèn)是不開啟runloop的,線程不被cpu收回的前提是線程中有未執(zhí)行完的任務(wù)


該線程開啟后,不會(huì)執(zhí)行eat方法 因?yàn)?/p>

(1)。線程已經(jīng)死掉了(oc對(duì)象保留,但線程已經(jīng)死掉了,因?yàn)槲从形赐瓿傻娜蝿?wù)(runloop沒有開啟))


正確的方法是:







4.runloop 性能優(yōu)化(加載大圖時(shí),渲染圖片像素較高)

問題:當(dāng)用tableview顯示高清圖片時(shí),如果一屏的高清圖片過多,導(dǎo)致在一個(gè)runloop中渲染圖片的時(shí)間過多,進(jìn)而不能及時(shí)響應(yīng)用戶的滑動(dòng)操作(在某個(gè)項(xiàng)目 *覓 中就出行過這種情況)導(dǎo)致滑動(dòng)時(shí)顯示出卡頓

注意:渲染圖片屬于runloop要做的事,滑動(dòng)tableview也屬于runloop要處理的事情,在一次性循環(huán)中,runloop既要渲染大量的高清圖片又要響應(yīng)拖拽事件,因此就會(huì)顯得滑動(dòng)卡頓

解決思路:讓每個(gè)runloop中只渲染一張圖片,這樣就不會(huì)導(dǎo)致渲染很多圖片后,才響應(yīng)用戶的滑動(dòng)動(dòng)作

步驟

1.添加觀察runloop各個(gè)狀態(tài)的觀察者


2.把添加圖片的代碼加到一個(gè)數(shù)組中


3.添加一個(gè)間隔0.001秒的定時(shí)器,保證線程每個(gè)0.001秒就被喚醒 然后執(zhí)行渲染圖片的任務(wù),因?yàn)闀r(shí)間間隔非常短,因此加載圖片非常快


4.定時(shí)器進(jìn)入休眠前執(zhí)行渲染某一張圖片的任務(wù)


注意點(diǎn):

(1)觀察runloop 要用到? CoreFoundation 框架中的 CFRunloop。 注意啦:CF是由C語言實(shí)現(xiàn)的,而不是Objective-C,所以如果用到了CF,就需要手動(dòng)管理內(nèi)存,ARC是無能為力的;

CF中遇到create、new、copy 要記得手動(dòng)釋放內(nèi)存

例如:



(2)C語言中只能用函數(shù)指針來完成回調(diào),OC中當(dāng)然有很多方式:通知、block、代理、kvo


(3)橋接

先來說說「Core Foundation」(以下簡(jiǎn)稱CF)的歷史吧。當(dāng)年喬布斯被自己創(chuàng)辦的公司驅(qū)逐后,成立了「NeXT Computer」,其實(shí)做的還是老本行:賣電腦,但依舊不景氣。好在NeXTSTEP系統(tǒng)表現(xiàn)還不錯(cuò),虧損不至于太嚴(yán)重。正好此時(shí)蘋果的市場(chǎng)份額大跌,急需一個(gè)新的操作系統(tǒng),結(jié)果大家都知道了,喬布斯借此收購(gòu),重新回到了蘋果。

這里就牽扯到了一個(gè)問題,如何讓舊有的系統(tǒng)(Mac OS 9)和NeXTSTEP合成為一個(gè)新系統(tǒng)?這就需要一個(gè)更為底層的核心庫(kù)可以供Mac Toolbox和OPENSTEP雙方調(diào)用。CF就這么誕生了。

CF是由C語言實(shí)現(xiàn)的,而不是Objective-C,所以如果用到了CF,就需要手動(dòng)管理內(nèi)存,ARC是無能為力的。當(dāng)然因?yàn)镃F和Foundation之間的友好關(guān)系,它們之間的管理權(quán)也是可以移交的,這個(gè)后面再說。

Core Foundation框架(CoreFoundation.framework) 是一組C語言接口,它們?yōu)閕OS應(yīng)用程序提供基本數(shù)據(jù)管理和服務(wù)功能。下面列舉該框架支持進(jìn)行管理的數(shù)據(jù)以及可提供的服務(wù):

群體數(shù)據(jù)類型 (數(shù)組、集合等)

程序包

字符串管理

日期和時(shí)間管理

原始數(shù)據(jù)塊管理

偏好管理

URL及數(shù)據(jù)流操作

線程和RunLoop

端口和soket通訊

Core Foundation框架和Foundation框架緊密相關(guān),它們?yōu)橄嗤δ芴峁┙涌?,但Foundation框架提供Objective-C接口。如果您將Foundation對(duì)象和Core Foundation類型摻雜使用,則可利用兩個(gè)框架之間的 “toll-free bridging”。所謂的Toll-free bridging是說您可以在某個(gè)框架的方法或函數(shù)同時(shí)使用Core Foundatio和Foundation 框架中的某些類型。很多數(shù)據(jù)類型支持這一特性,其中包括群體和字符串?dāng)?shù)據(jù)類型。每個(gè)框架的類和類型描述都會(huì)對(duì)某個(gè)對(duì)象是否為 toll-free bridged,應(yīng)和什么對(duì)象橋接進(jìn)行說明。


CoreFoundation 是C語言構(gòu)成 而Foundation 是用OC把CoreFoundation進(jìn)行包裝了一遍

CoreFoundation 和 Foundation 之間相互轉(zhuǎn)換就用到了橋接

橋接分為三種模式

第一種橋接方式? __bridge transfers a pointer between Objective-C and Core Foundation with no transfer of ownership.(這種方式只是傳遞了指針,而沒有傳遞對(duì)象的所有權(quán),也就是如果str銷毀了,strC也不能用了)

CFStringRef strC = nil;

{

NSString *str = [NSString stringWithFormat:@"123"];

strC = (__bridge CFStringRef)(str);

}

NSLog(@"%@ ",strC);

第二種橋接方式? __bridge_retained or CFBridgingRetain casts an Objective-C pointer to a Core Foundation pointer and also transfers ownership to you.You are responsible for calling CFRelease or a related function to relinquish ownership of the object.(這種方式只是用于OC對(duì)象轉(zhuǎn)換為CF類型,它會(huì)將對(duì)象的所有權(quán)轉(zhuǎn)移給strC,也就是說,即便str釋放了,strC也可以使用

注意 在ARC條件下,如果使用__bridge_retained橋接,那么strC必須手動(dòng)釋放,因?yàn)闃蚪拥臅r(shí)候已經(jīng)將對(duì)象的所有轉(zhuǎn)移給了strC,而C語言的東西是不歸ARC管理的


NSString *str = [NSString stringWithFormat:@"123"];

CFStringRef strC = (__bridge_retained CFStringRef)str;

//CFStringRef StrC = CFBridgingRetain(str); 這一句和上面一句的效果一樣

NSLog(@"%@ %@",str,strC);

CFRelease(strC);


第三種橋接方式? __bridge_transfer or CFBridgingRelease moves a non-Objective-C pointer to Objective-C and also transfers ownership to ARC.ARC is responsible for relinquishing ownership of the object.這種方式只是用于CF對(duì)象轉(zhuǎn)換為OC類型,它會(huì)將對(duì)象的所有權(quán)轉(zhuǎn)移給str,也就是說,即便strC釋放了,str也可以使用

//注意 在ARC條件下,如果使用__bridge_transfer橋接,那么strC不用手動(dòng)釋放,因?yàn)開_bridge_transfer會(huì)自動(dòng)釋放strC的

CFStringRef strC = CFStringCreateWithCString(nil, "456", kCFStringEncodingASCII);

NSString *str = (__bridge_transfer NSString*) (strC);

NSString *str = CFBridgingRelease(strC); //這一句和上面一句的效果一樣

NSLog(@"%@ %@",str,strC);

CFRelease(strC);

總結(jié)

runloop和線程之間的關(guān)系

* 每個(gè)線程有且僅有一個(gè)對(duì)應(yīng)的runloop,子線程的runloop默認(rèn)是沒有開啟的,但是主線程的runloop默認(rèn)是開啟的

*runloop是懶加載,獲得runloop等于開啟runloop 例如: ?[NSRunLoop currentRunLoop]

*runloop有5中mode(模式),但是主要的是兩種模式:NSDefaultRunLoopMode(默認(rèn)模式)和UITrackingUIRunLoopMode(界面追蹤模式,也就是頁面滑到時(shí)主線程會(huì)切換到UITrancking模式),要注意

**runloop啟動(dòng)時(shí),只能有一種模式,要切換到另外一種模式,runloop要先退出再開啟。

**每種模式都有source、定時(shí)器、observe三種觸發(fā)模式,并且不同模式下,三種觸發(fā)是相互隔離的,也就是說,比如定時(shí)器1加到NSDefault這種模式下了,那么當(dāng)runloop啟動(dòng)時(shí)運(yùn)行在UITrancking模式下事,就不會(huì)接收到定時(shí)器1的觸發(fā)了

例如:NStimer定時(shí)滑動(dòng)的問題,如果NStimer只加入到NSDefault模式下,那么當(dāng)頁面滑動(dòng)時(shí),主線程的runloop從default模式退出,開啟UITrancking模式,但是NStimer并沒有添加到UITrancking模式下,所以在滑動(dòng)頁面時(shí),就收不到滑動(dòng)的觸發(fā)

參考

Core Foundation 框架 詳解

蘋果官方文檔Toll-Free Bridged Types

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

友情鏈接更多精彩內(nèi)容