iOS性能優化-異步繪制


參考地址:https://blog.ibireme.com/2015/11/12/smooth_user_interfaces_for_ios/

很久以前就看過這篇文章,但是也只是看過就過了,沒有去整理思路,最近有時間把一些點整理一下.

通讀下來可以總結一下對性能優化,在這里也就是提高界面流暢度的宗旨只有一句話唯而已:把能異步執行的都盡量異步執行.

在我這篇里主要記錄一下文本的異步繪制,先上兩個視頻,異步處理前后的差異,我直接把YYFPSLabel拿過來用了,檢測FPS的變化情況:

 

 可以看到,在滑動很快的時候,FPS最低已經達到了20幾.

 

 

 經過異步繪制處理之后,可以看到無論如何滑動,FPS一直保持在60.

這是我寫的一個小demo:https://github.com/alan12138/Interview-question/tree/master/3/AsyncLabel,也就是上面運行案例的代碼.

前后對比的效果就是將cell中的label使用UILabel和使用自定義label之后的效果.

 首先,其實這種優化是對流暢度非常敏感的界面來說的,一般場景很少需要做這樣的優化,並且,只有在文字非常多且復雜,滑動非常快的時候才能明顯的感覺到差別.

如果項目中某個地方需要優化,而你也想嘗試一下使用YYAsyncLayer,並且對文字的處理比較簡單,可以將demo中的ATLabel拿來參考,當然直接使用YYLabel是最好的選擇,ATLabel只是用來演示YYAsyncLayer的使用,並且非常簡陋.

 不談YYLabel內部各種復雜的處理,他是直接繼承自UIView,自己造了個Label控件出來,但是從異步繪制的角度來說,其原理就是,將本來UILabel所做的繪制文字的工作拿過來自己做,並放在子線程異步執行.

 

下面簡單分析一下YYAsyncLayer的內部原理:

其中涉及到了四個類:

 

 

YYAsyncLayer

YYTransaction

YYSentinel

YYDispatchQueuePool

 

先從YYTransaction開始說起,每一個YYTransaction對象相當於一個異步繪制任務.

ATLabel中在以下需要調用重繪的方法中都提交了contentsNeedUpdated任務,

 

 

 查看commit方法可以看到,他使用了一個Set來存儲這些任務.並且在其中調用了一個方法:YYTransactionSetup

 

 看一下YYTransactionSetup方法:

 

 

 可以看到這個方法中的代碼只會執行一次,也就是在第一次commit 的時候執行一次,之后便不會再執行了.方法內部初始化了一個Set對象,用來收集繪制任務,並做了runloop監聽,在runloop等待和退出之前,也就是空閑的時候,調用回調方法.

 

 

 而在這個回調方法中,便是執行所有收集到的繪制任務.

綜上所述,在label需要重繪的時候,作者將繪制任務收集起來,並在runloop空閑的時候一起執行.

接下來看一下作者是如何執行這些任務的:

可以看到每個繪制任務都是調用display方法,而display中執行的_displayAsync方法便是對異步繪制的處理,也就是說每個繪制任務最終都會調用到這個方法.

 

 _displayAsync方法:

 

在ATLabel中可以看到

 

 

 作者重寫了layerClass方法,並返回了YYAsyncLayer.class,也就是將當前label的layer替換為了YYAsyncLayer.然后便可以通過實現YYAsyncLayer的代理方法newAsyncDisplayTask.將ATLabel我們自己對文字繪制的實現異步執行.

 上面圈出來的便是對代理中我們task.display代碼實現的調用.,可以看到是在異步代碼塊中.

回到YYAsyncLayer的 _displayAsync方法,可以看到最后回到主線程將繪制內容賦值,便完成了整個流程.

 

 

 

最后,還有作者一些細節性的處理我沒有寫下來,有興趣可以自己研究一下,比如計數器的使用,hash的處理,隊列數量的控制,cancel()的處理,還有一些繪制相關的工作,作者短短的幾百行代碼凝聚了很多智慧.

 其他:

貝塞爾曲線異步繪制圓角:https://github.com/alan12138/Interview-question/tree/master/3/AsyncImage 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM