一次iOS App優化(踩坑)之旅

分類:設計 時間:2016-10-18

未經深思熟慮的優化是bug之源,這句話做過深度優化的同學一定能明白其中的辛酸。今天和大家分享下博主一次優化CoreText的填坑經歷。記得那時候,iPhone 4s還算市面上的主流機型。

優化起因

當時正在做一款IM App,產品經理覺得每次第一次進入聊天界面的時候有點慢,而且進入之后的第一次滑動有點卡。正是由于 ,導致了后面一系列的優化。在開始介紹優化方案之前,先說下「首次體驗問題」。

首次體驗問題

首次體驗是個經典的場景,很多App都有類似的問題存在。它描述的是,App新進入一個場景,由于第一次必要的資源加載,邏輯運算等所帶來的延遲,而導致的用戶體驗延遲。

比如大家Kill進程后重新打開微信,如果快速滑動會話列表,能感覺到明顯的滑動動畫卡頓,而且這種卡頓只會經歷一次,再次往返滑動的時候又完全流暢了。大部分的耗時是因為頭像文件的磁盤io讀取,和圓角繪制。資源準備好加入cache后耗時就消失了,當然頭像可以異步到子線程中去繪制,但是會導致用戶能看到頭像“由默認頭像變為真實頭像”的過程,體驗稍差,顯然微信采取了同步繪制的機制。

當然這并不是個大問題,現在的硬件足夠快,功能場景也多,偶爾一秒以內的體驗延遲完全可以忍受。

回到剛才產品經理所說的慢和卡,其實也是經典的首次體驗問題。第一次進入聊天界面時有很多資源需要準備:

  1. 創建Controller及相關類
  2. 讀取消息列表
  3. 渲染消息

通過Instrument Profile過后,發現當時App有相當一部分時間花費在了CoreText的渲染上。當時App的文本消息是使用CoreText繪制的,而CoreText整個繪制流程當中有一步占比最重:文本消息的高度寬度計算及超鏈接檢測。

當時腦袋一拍,就有了方案,以空間換時間,把文字高寬度和超鏈接的信息都存入databae,這樣下次啟動的時候不用重新計算,所以就有了如下代碼:

BOOL needDetectLink_calculateSize = false;
if (textMsg.textWidth == 0) {
    needDetectLink_calculateSize = true;
}
    
if (needDetectLink_calculateSize) {
    textSize = [_Msg_Helper calcuteSizeOfAttributedMessageText:textMsg.attributedMsgString withFrame:textMsg.ctFrame lastLineWidth:amp;lastLineWidth];
    textMsg.isDirty = true;
}
else
{
    textSize = CGSizeMake(textMsg.textWidth, textMsg.textHeight);
}

計算完之后,再啟動一個后臺任務在子線程當中把計算好的信息(dirty message)存入database。優化好之后交給產品經理體驗,產品經理發現確實比之前快了不少,很滿意,皆大歡喜。

第一個坑:

原本優化任務開心結束了,直到一年多后測試同學突然拿著手機給我看了一條奇怪的消息:

最后一個字看起來被截掉了一小部分,一番調試之后,發現是之前緩存的文字寬度信息不對了,又花了幾個小時調查為何寬度會不對,代碼上看不出任何問題,而且有些文本消息展示沒有問題,只有特定的消息才會出現,直到不小心瞥見手機系統的語言是日語,猛的想到會不會是這兩種系統語言下中文字體不同,一調查果不其然。

先使用中文系統發送文本消息,再切換到日語系統就能大概率重現上述問題,雖然場景比較少,畢竟是個bug,還是修一修:

BOOL needDetectLink_calculateSize = false;
if (textMsg.textWidth == 0 || preSysLanguage != curSysLanguage) {
    needDetectLink_calculateSize = true;
}

心想還是挺簡單的,判斷下渲染時的系統語言就可以了。

第二個坑:

又過了一年多,iOS 9發布,測試同學又過來給我看了如下畫面:

我第一反應是不是換語言了,可是換語言的場景我處理過了,根據之前的思路很可能是換了字體,順著思路一想,哦,原來是iOS 9系統換了中文字體。所以按常理我應該把代碼改成這樣:

BOOL needDetectLink_calculateSize = false;
if (textMsg.textWidth == 0 || preSysLanguage != curSysLanguage || preiOSVersion != curiOSVersion) {
    needDetectLink_calculateSize = true;
}

這樣總可以了,或者更保險一點,我判斷前后兩次渲染所用的字體是否一致。可連續兩次的意外讓我對這段代碼產生了懷疑,最后撫摸著我手里絲滑順暢硬件指數爆表的iPhone 5s,我想到了一個更好的方案。

最終方案:

我把優化關閉了。

歡迎關注公眾號:


Tags: iOS 移動設計

文章來源:http://mrpeak.cn/blog/coretext-performance/


ads
ads

相關文章
ads

相關文章

ad