在 iOS開發(fā)過(guò)程中也祠,我一直知道更新UI需要在主線程中,但也沒怎么細(xì)想為什么要在主線程中,或者說(shuō)為什么不能在子線程中更新UI近速。今天抽空自己在網(wǎng)上查查資料 诈嘿,了解一下這個(gè)問題堪旧。
????? 像UIKit這樣大的框架上確保線程安全是一個(gè)重大的任務(wù),會(huì)帶來(lái)巨大的成本奖亚。UIKit不是線程安全的淳梦,假如在兩個(gè)線程中設(shè)置了同一張背景圖片,很有可能就會(huì)由于背景圖片被釋放兩次昔字,使得程序崩潰爆袍。或者某一個(gè)線程中遍歷找尋某個(gè)subView作郭,然而在另一個(gè)線程中刪除了該subView陨囊,那么就會(huì)造成錯(cuò)亂。apple有對(duì)大部分的繪圖方法和諸如UIColor等類改寫成線程安全可用夹攒,可還是建議將UI操作保證在主線程中蜘醋。
事實(shí)上在子線程中如果要對(duì)其他UI 進(jìn)行更新,必須等到該子線程運(yùn)行結(jié)束咏尝,而對(duì)響應(yīng)用戶點(diǎn)擊的Button的UI更新則是及時(shí)的压语,不管他是在主線程還是在子線程中做的更新,意義都不大了编检,因?yàn)樽泳€程中對(duì)所有其他ui更新都要等到該子線程生命周期結(jié)束才進(jìn)行胎食。
????? 在子線程中是不能進(jìn)行UI 更新的,我們看到的UI更新其實(shí)是子線程代碼執(zhí)行完畢了允懂,又自動(dòng)進(jìn)入到了主線程厕怜,執(zhí)行了子線程中的UI更新的函數(shù)棧,這中間的時(shí)間非常的短累驮,就讓大家誤以為分線程可以更新UI酣倾。如果子線程一直在運(yùn)行,則子線程中的UI更新的函數(shù)棧 主線程無(wú)法獲知谤专,即無(wú)法更新躁锡。只有極少數(shù)的UI能直接進(jìn)行UI更新,因?yàn)殚_辟線程時(shí)會(huì)獲取當(dāng)前環(huán)境置侍,如點(diǎn)擊某個(gè)按鈕映之,這個(gè)按鈕響應(yīng)的方法是開辟一個(gè)子線程,在子線程中對(duì)該按鈕進(jìn)行UI 更新是能及時(shí)的蜡坊,如上面的換背景圖杠输,但這沒有任何意義。
原因一:安全+效率
因?yàn)閁IKit框架不是線程安全的秕衙,當(dāng)多個(gè)線程同時(shí)操作UI的時(shí)候蠢甲,搶奪資源,導(dǎo)致崩潰据忘,UI異常等問題鹦牛。假如在兩個(gè)線程中設(shè)置了同一張背景圖片搞糕,很有可能就會(huì)由于背景圖片被釋放兩次,使得程序崩潰曼追∏涎觯或者某一個(gè)線程中遍歷找尋某個(gè)subView,然而在另一個(gè)線程中刪除了該subView礼殊,那么就會(huì)造成錯(cuò)亂驹吮。apple有對(duì)大部分的繪圖方法和諸如UIColor等類改寫成線程安全可用,可還是建議將UI操作保證在主線程中晶伦。例如說(shuō)碟狞,我們需要在子線程中讀取一個(gè)image對(duì)象,使用接口 [UIImage imageNamed:] 坝辫,但 imageNamed: 實(shí)際上在 iOS9 以后才是線程安全的篷就, iOS9 之前都需要在主線程獲取。所以近忙,我們需要從子線程切換到主線程獲取image,然后再切回子線程拿到這個(gè)image智润,這里我們必須使用sync及舍。
原因二:用戶體驗(yàn)
iOS中只有主線程才能立即刷新UI。在子線程中是不能夠更新UI窟绷,我們看到的子線程能夠更新UI的原因是锯玛,等到子線程執(zhí)行完畢,自動(dòng)進(jìn)入了主線程去執(zhí)行子線程中更新UI的代碼兼蜈。由于子線程執(zhí)行時(shí)間非常短暫攘残,讓我們誤以為子線程可以更新UI。如果子線程一直在運(yùn)行为狸,則無(wú)法更新UI歼郭,因?yàn)闆]有辦法進(jìn)入主線程。
在子線程刷新UI辐棒,一旦出錯(cuò)病曾,會(huì)造成我們無(wú)法解決的困難!