<ruby id="bdb3f"></ruby>

    <p id="bdb3f"><cite id="bdb3f"></cite></p>

      <p id="bdb3f"><cite id="bdb3f"><th id="bdb3f"></th></cite></p><p id="bdb3f"></p>
        <p id="bdb3f"><cite id="bdb3f"></cite></p>

          <pre id="bdb3f"></pre>
          <pre id="bdb3f"><del id="bdb3f"><thead id="bdb3f"></thead></del></pre>

          <ruby id="bdb3f"><mark id="bdb3f"></mark></ruby><ruby id="bdb3f"></ruby>
          <pre id="bdb3f"><pre id="bdb3f"><mark id="bdb3f"></mark></pre></pre><output id="bdb3f"></output><p id="bdb3f"></p><p id="bdb3f"></p>

          <pre id="bdb3f"><del id="bdb3f"><progress id="bdb3f"></progress></del></pre>

                <ruby id="bdb3f"></ruby>

                企業??AI智能體構建引擎,智能編排和調試,一鍵部署,支持知識庫和私有化部署方案 廣告
                ## **微博 Demo 性能優化技巧** 我為了演示 YYKit 的功能,實現了微博和 Twitter 的 Demo,并為它們做了不少性能優化,下面就是優化時用到的一些技巧。 [TOC=3,3] ### **預排版** 當獲取到 API JSON 數據后,我會把每條 Cell 需要的數據都在后臺線程計算并封裝為一個布局對象 CellLayout。CellLayout 包含所有文本的 CoreText 排版結果、Cell 內部每個控件的高度、Cell 的整體高度。每個 CellLayout 的內存占用并不多,所以當生成后,可以全部緩存到內存,以供稍后使用。這樣,TableView 在請求各個高度函數時,不會消耗任何多余計算量;當把 CellLayout 設置到 Cell 內部時,Cell 內部也不用再計算布局了。 對于通常的 TableView 來說,提前在后臺計算好布局結果是非常重要的一個性能優化點。為了達到最高性能,你可能需要犧牲一些開發速度,不要用 Autolayout 等技術,少用 UILabel 等文本控件。但如果你對性能的要求并不那么高,可以嘗試用 TableView 的預估高度的功能,并把每個 Cell 高度緩存下來。這里有個來自百度知道團隊的開源項目可以很方便的幫你實現這一點:[FDTemplateLayoutCell](https://github.com/forkingdog/UITableView-FDTemplateLayoutCell/)。 ### **預渲染** 微博的頭像在某次改版中換成了圓形,所以我也跟進了一下。當頭像下載下來后,我會在后臺線程將頭像預先渲染為圓形并單獨保存到一個 ImageCache 中去。 對于 TableView 來說,Cell 內容的離屏渲染會帶來較大的 GPU 消耗。在 Twitter Demo 中,我為了圖省事兒用到了不少 layer 的圓角屬性,你可以在低性能的設備(比如 iPad 3)上快速滑動一下這個列表,能感受到雖然列表并沒有較大的卡頓,但是整體的平均幀數降了下來。用 Instument 查看時能夠看到 GPU 已經滿負荷運轉,而 CPU 卻比較清閑。為了避免離屏渲染,你應當盡量避免使用 layer 的 border、corner、shadow、mask 等技術,而盡量在后臺線程預先繪制好對應內容。 ### **異步繪制** 我只在顯示文本的控件上用到了異步繪制的功能,但效果很不錯。我參考 ASDK 的原理,實現了一個簡單的異步繪制控件。這塊代碼我單獨提取出來,放到了這里:[YYAsyncLayer](https://github.com/ibireme/YYAsyncLayer)。YYAsyncLayer 是 CALayer 的子類,當它需要顯示內容(比如調用了 [layer setNeedDisplay])時,它會向 delegate,也就是 UIView 請求一個異步繪制的任務。在異步繪制時,Layer 會傳遞一個?BOOL(^isCancelled)()這樣的 block,繪制代碼可以隨時調用該 block 判斷繪制任務是否已經被取消。 當 TableView 快速滑動時,會有大量異步繪制任務提交到后臺線程去執行。但是有時滑動速度過快時,繪制任務還沒有完成就可能已經被取消了。如果這時仍然繼續繪制,就會造成大量的 CPU 資源浪費,甚至阻塞線程并造成后續的繪制任務遲遲無法完成。我的做法是盡量快速、提前判斷當前繪制任務是否已經被取消;在繪制每一行文本前,我都會調用 isCancelled() 來進行判斷,保證被取消的任務能及時退出,不至于影響后續操作。 目前有些第三方微博客戶端(比如 VVebo、墨客等),使用了一種方式來避免高速滑動時 Cell 的繪制過程,相關實現見這個項目:[VVeboTableViewDemo](https://github.com/johnil/VVeboTableViewDemo)。它的原理是,當滑動時,松開手指后,立刻計算出滑動停止時 Cell 的位置,并預先繪制那個位置附近的幾個 Cell,而忽略當前滑動中的 Cell。這個方法比較有技巧性,并且對于滑動性能來說提升也很大,唯一的缺點就是快速滑動中會出現大量空白內容。如果你不想實現比較麻煩的異步繪制但又想保證滑動的流暢性,這個技巧是個不錯的選擇。 ### **全局并發控制** 當我用 concurrent queue 來執行大量繪制任務時,偶爾會遇到這種問題: ![](https://box.kancloud.cn/2015-11-19_564d5004ac339.png)? ![](https://box.kancloud.cn/2015-11-19_564d5004da1af.png) 大量的任務提交到后臺隊列時,某些任務會因為某些原因(此處是 CGFont 鎖)被鎖住導致線程休眠,或者被阻塞,concurrent queue 隨后會創建新的線程來執行其他任務。當這種情況變多時,或者 App 中使用了大量 concurrent queue 來執行較多任務時,App 在同一時刻就會存在幾十個線程同時運行、創建、銷毀。CPU 是用時間片輪轉來實現線程并發的,盡管 concurrent queue 能控制線程的優先級,但當大量線程同時創建運行銷毀時,這些操作仍然會擠占掉主線程的 CPU 資源。ASDK 有個 Feed 列表的 Demo:[SocialAppLayout](https://github.com/facebook/AsyncDisplayKit/tree/master/examples/SocialAppLayout),當列表內 Cell 過多,并且非常快速的滑動時,界面仍然會出現少量卡頓,我謹慎的猜測可能與這個問題有關。 使用 concurrent queue 時不可避免會遇到這種問題,但使用 serial queue 又不能充分利用多核 CPU 的資源。我寫了一個簡單的工具?[YYDispatchQueuePool](https://github.com/ibireme/YYDispatchQueuePool),為不同優先級創建和 CPU 數量相同的 serial queue,每次從 pool 中獲取 queue 時,會輪詢返回其中一個 queue。我把 App 內所有異步操作,包括圖像解碼、對象釋放、異步繪制等,都按優先級不同放入了全局的 serial queue 中執行,這樣盡量避免了過多線程導致的性能問題。 ### **更高效的異步圖片加載** SDWebImage 在這個 Demo 里仍然會產生少量性能問題,并且有些地方不能滿足我的需求,所以我自己實現了一個性能更高的圖片加載庫。在顯示簡單的單張圖片時,利用 UIView.layer.contents 就足夠了,沒必要使用 UIImageView 帶來額外的資源消耗,為此我在 CALayer 上添加了 setImageWithURL 等方法。除此之外,我還把圖片解碼等操作通過 YYDispatchQueuePool 進行管理,控制了 App 總線程數量。 ### **其他可以改進的地方** 上面這些優化做完后,微博 Demo 已經非常流暢了,但在我的設想中,仍然有一些進一步優化的技巧,但限于時間和精力我并沒有實現,下面簡單列一下: 列表中有不少視覺元素并不需要觸摸事件,這些元素可以用 ASDK 的圖層合成技術預先繪制為一張圖。 再進一步減少每個 Cell 內圖層的數量,用 CALayer 替換掉 UIView。 目前每個 Cell 的類型都是相同的,但顯示的內容卻各部一樣,比如有的 Cell 有圖片,有的 Cell 里是卡片。把 Cell 按類型劃分,進一步減少 Cell 內不必要的視圖對象和操作,應該能有一些效果。 把需要放到主線程執行的任務劃分為足夠小的塊,并通過 Runloop 來進行調度,在每個 Loop 里判斷下一次 VSync 的時間,并在下次 VSync 到來前,把當前未執行完的任務延遲到下一個機會去。這個只是我的一個設想,并不一定能實現或起作用。
                  <ruby id="bdb3f"></ruby>

                  <p id="bdb3f"><cite id="bdb3f"></cite></p>

                    <p id="bdb3f"><cite id="bdb3f"><th id="bdb3f"></th></cite></p><p id="bdb3f"></p>
                      <p id="bdb3f"><cite id="bdb3f"></cite></p>

                        <pre id="bdb3f"></pre>
                        <pre id="bdb3f"><del id="bdb3f"><thead id="bdb3f"></thead></del></pre>

                        <ruby id="bdb3f"><mark id="bdb3f"></mark></ruby><ruby id="bdb3f"></ruby>
                        <pre id="bdb3f"><pre id="bdb3f"><mark id="bdb3f"></mark></pre></pre><output id="bdb3f"></output><p id="bdb3f"></p><p id="bdb3f"></p>

                        <pre id="bdb3f"><del id="bdb3f"><progress id="bdb3f"></progress></del></pre>

                              <ruby id="bdb3f"></ruby>

                              哎呀哎呀视频在线观看