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)橄嗤δ芴峁┙涌谏肀ぃ獸oundation框架提供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ā)
參考