iOS開髮針對對Masonry下的FPS優化討論

来源:http://www.cnblogs.com/ludashi/archive/2017/11/16/7760471.html
-Advertisement-
Play Games

今天博客的內容就系統的討論一下Masonry對FSP的影響,以及如何更好的使用Masonry。如果你對iOS開發足夠熟悉的話,那麼對Masonry框架應該不陌生。簡單的說,Masonry的誕生讓AutoLayout的使用更為優雅,讓控制項的佈局更為方便。使用辯證的觀點來看一個事物的話,凡事都有兩面性, ...


今天博客的內容就系統的討論一下Masonry對FSP的影響,以及如何更好的使用Masonry。如果你對iOS開發足夠熟悉的話,那麼對Masonry框架應該不陌生。簡單的說,Masonry的誕生讓AutoLayout的使用更為優雅,讓控制項的佈局更為方便。使用辯證的觀點來看一個事物的話,凡事都有兩面性,Masonry的使用也不例外。Masonry框架的使用不當會直接影響當UI的FPS。今天我們就來討論一下在使用Masonry時的一些誤區,看一下那些影響性能的使用方式。本篇博客我們依然會依托於Demo來敘述的一些東西。

之前寫過一篇文章是專門來介紹Masonry框架的,並且對該框架的源碼進行了相關解析,詳細內容請移步於《iOS開發之Masonry框架源碼解析》。

 

一、Demo綜述

1.運行效果

先入為主,本篇博客的內容依然是依托於我們特意為本篇博客所打造的Demo的,首先我們先來看一下Demo運行起來是怎樣的效果,通過Demo我們可以看到那些問題,以及這些問題是如何被解決的。下方就是我們本篇博客所涉及Demo的運行效果。 

從下方的運行效果不難看出,我們是分了6種情況來觀察和判斷Masonry的各種使用方式對FPS的影響如何。上方通過六個SegmentControl可以去切換Cell的佈局方式。當然每種佈局方式所呈現出來的Cell是相同的。這樣也是做實驗時保持實驗項改變其他項保持一致的原則。我們可以通過右下方FPS指示器來直觀的感受一下FPS的變化趨勢。下方這個FPS顯示控制項是從我們之前的Demo中拿過來的。之前的Demo也是關於FPS優化的,只不過是關於Cell高度動態計算的FPS優化,詳情請移步於《iOS開發之多種Cell高度自適應實現方案的UI流暢度分析》。

下方Cell中所顯示的數據時隨機生成的,左邊的Image也是隨機取的。右邊的Title和Detail都是NSAttributedString並且下方的有些Detail有可能為空。如果某一條的Detail為空,那麼該條Detail下方的所有內容的佈局上移。稍後會詳細的介紹該Demo以及其中的技術點。

      

 

2、模擬網路請求

上面Cell中顯示的數據是通過模擬網路數據來獲取的,下方就是我們的模擬網路層的相關代碼。畢竟是Demo,並且Demo的重點不在網路層上,下方就簡單的寫了一下,代碼比較簡單。就是一個單例+一個模擬數據隨機生成的方法,然後把這個隨機生成的數據通過Block回調到網路層的使用者上。具體代碼如下所示:

    

 

3、上述Cell的基類XBaseTableViewCell

上面每種Segment中的Cell都是一種獨立的Cell類型,不過這些Cell有一個共同的父類。而這個父類就負責來處理這些Cell所共用的邏輯。下方的這個XBaseTableViewCell就是上述顯示的所有Cell的基類。其中聲明並初始化了Cell上的所有控制項。並且提供了相關的設置值的方法。

從下方的代碼中不難看出,有兩個方法是需要子類進行重寫的,一個是給控制項添加佈局的方法addLayoutSubviews, 另一個就是更新佈局的方法updateLayoutSubviews方法。每個子類中都會對這兩個方法進行重寫並給出不同的佈局方式。

  

 

4、Segment中切換Cell的代碼

下方是在相應的VC中的點擊SegmentControl的邏輯代碼, 點擊不同的Segment會選擇不同的Cell然後刷新TableView,代碼比較簡單就不做過多的贅述了。

  

 

 

二、對上述各種的佈局方式進行分析

接下來要做的事情就是分析一下每種佈局方式對FSP的影響,下方會對不同的佈局情況使用Instrument進行分析並看一下具體的數據。下方分別討論了只使用Masonry的Update操作、Remake操作、先Make後Update、Frame操作以及先Make後Frame操作。

1、update

首先我們來看一下update操作。也就是使用update直接給控制項賦值,這是比較偷懶的一種操作。因為在我們的Demo中在設置cell的值時會更新一些控制項的UI佈局,所有我們索性就直接使用Masonry的update,直接給控制項添加約束。在Masonry中的update操作有個特點,就是update一個約束會先在已添加的約束數組中找到該約束,然後更新該約束,如果找不到就install添加相應的約束。從這個update的功能來看其效率是比較低的。

我可以先看一下代碼實現,在子類XUpdateLayoutTableViewCell中,重寫了addLayoutSubviewsupdateLayoutSubviews兩個方法。在updateLayoutSubviews方法中,為所有的控制項使用update的方式添加約束。下方這樣寫會在每次設置值的時候都會調用下方的updateLayoutSubviews方法,這樣就會更新cell上的控制項的所有佈局,當然,不建議這樣去做,因為這樣會更新那些不需要更新的約束。之所以今天羅列出來,是因為在開發中下方的問題確實存在,也許是因為時間緊張,也許是因為其他原因導致的下方這種代碼實現。

  

 

我們先來使用Instruments跑一下上述的Demo,然後直觀的感受一下該Demo的Core Animation的直觀表現。下方就是我們將SegmentControl切換到Update時所對應的FPS數據。從下方的數據我們不難看出,直接用Update添加更新約束這種做法是比較影響FPS的。當然,Cell中還會使用到屬性字元串,這個我們稍後會討論一下的。

  

 

我們可以來跑一下Update狀態下的Time Profile。如下所示,從下方的結果中不難看出,在Cell更新數據時,有兩塊的操作比較耗時。一個是Masonry的update操作,另一個則是Label設置NSAttributedString的操作。因為我們使用的每個Label都會賦值一個屬性字元串,這個是比較耗時的操作。還有一個要明確一點的是,屬性字元串的創建和生成並不會占用多少時間,而屬性字元串的賦值和渲染所占用的時間是比較多的,這一點從下方的Time Profile中也是不難看出的。

  

 

2、remake

接下來我們在來看一下Remake操作,從下方的Core Animation的結果中不難看出,其所表現出來的效果還不如使用Update操作呢。下方的FPS比Update要低一些,這也與remake自身的操作有關係,remake從字面意思來看就是重新製作,如果之前已經添加過約束的話就先移除掉,然後再添加新的約束。

   

 

下方是Remake所對應的Time Profile,從結果中我們可以看出佈局更新占用了66.6%的耗時,而且33%的install耗時中uninstall占用了10%左右的開銷。在Masonry中remake效率是最低的。稍後我們會繼續進行討論。

  

 

3、make + update

討論完update和remake, 我們來討論一下使用Masonry的常規做法。就是使用make來初始化控制項的佈局,使用update來更新所需要更新的約束。因為代碼比較簡單,就不一一往上貼了,但是跑一下使用Instrument跑一下還是很有必要的。下方是make + update 的方式的Core Animation所跑出來的結果。但從下方的FSP結果來看,還是要比之前只使用update或者remake的效果要好一些的,不過下方的FPS還是不高,稍後我們會將下方的數據進行細化。

該部分的Time Profile就不跑了,因為設置值的時候我們依然採用的Update來更新的約束,只不過不是更新所有的約束,而是更新那些只需要更新的約束。因為更新的約束的量會少一些,所有FPS的表現效果會比之前更新所有的約束會更好一些。make + update的方式會是FPS稍微改善一些,但是從下方的圖中我們可以看出,改善的並不是特別好。

  

 

4、frame + frame

接下來,我們就不用Masonry來佈局了,我們直接使用Frame佈局。因為Autolayout最終仍然會轉換為Frame佈局的,很顯然Frame佈局在性能方面是優於Autolayout佈局的。接下來我們就來使用Frame佈局然後使用Frame更新。下方的FPS還算說得過去,不過還不是滿格,其大部分原因就是因為NSAttrubitedString的原因了。

   

 

我們可以看一下更新Frame的Time Profile,如下所示。從下方的截圖中,我們不難看出update frame的時間占比只占到了2.5%,之前更新約束能占到60%左右,可以看到使用Frame佈局的好處。從下方的分析結果中不難看出,現在影響FPS主要因素已經從更新佈局轉化到了AttributeString的設置。這也是上述FPS沒有滿格的原因。

  

 

6、make + frame

Masonry的誕生就是為了方便控制項佈局的,Frame佈局不夠靈活,適配起來比較繁瑣,所以才有了AutoLayout。不過雖然AutoLayout可以很方便的適配屏幕,可是其性能方面表現的不是特別好。那麼我們可不可以將兩者進行結合呢。也就是說使用make來初始化控制項的佈局,使用Frame來更新佈局。當然這一過程不是簡單的在設置值的時候更新一下Frame就可以的,因為在Cell設置值的時候去更新Frame是沒用的,因為更新完Frame後,在渲染顯示的時候,還是會按照AutoLayout的佈局來顯示的。我們需要做的是將Frame佈局放到Autolayout佈局之後,此處我們要做的就是將更新Frame的相關代碼放到下一個Runloop中來執行。更新Frame代碼如下:

  

 

在cell中是make初始化控制項佈局,使用Frame更新佈局,和Frame+Frame的方式差不多,只不過是使用Masonry佈局時,在首屏載入的時候不如Frame佈局,以後更新是一樣的。下方是使用Masonry+Frame的形式的Core Animation的結果。效果雖然比上一部分會稍微差一些,但是最終的效果還是滿Ok的。

  

 

 

 三、總結

本篇博客只討論Masonry的佈局方式對FPS的影響,至於上述的NSAttributeString的問題不做過多贅述了。如果根據業務需要,有許多富文本的展示影響了FPS的話,那麼可以採用其他的方式來進行優化,比如使用AsynDisplayKit所提供的相關Node進行顯示等等。在博客的結尾,還是有必要做一個總結的。

下方是我們在代碼中更為細化的數據,從數據中不難看出Remake的性能是最差的,所以我們在使用Masonry時儘量要少使用Remake。對控制項的更新只一味的選擇使用Update也不是一個好的選擇,如果要使用Masonry框架還要對控制項進行佈局更新的話,最好是把那些不變的約束和需要更新的約束分開。使用make來添加相關約束,使用update來修改需要更新的約束。當然使用Frame佈局的性能會好一些,不過佈局過程過於繁瑣不便於進行屏幕的適配。當然也可以使用Masonry進行佈局使用Frame進行佈局的更新,當然需要註意的是Frame佈局更新的時機,需在Autolayout載入的時機後進行。

下方是進行了統一的數據統計,當然是針對本篇博客所對應的Demo的。下方表格中統計了一次更新cell佈局所採用的不同方式的平均時間,從下方的數據中我們不難看粗Remake的更新佈局用時最多,消耗了12+ms, 而Update所有的約束用時也是不少,一次更新佈局使用了9+ms。而只更新需要更新的佈局用時7+ms, 稍微要比更新所有的佈局要好一些。當然直接修改Frame的用時最少,只用了0.06+ms的時間,從該數據可以直觀的感受到Frame佈局的效率性。

而右邊還給出了一個屬性字元串的創建和賦值的用時,其中我們可以看到,屬性字元串的創建耗時並不是太多,而比較耗時的是屬性字元串的賦值,每次賦值占用了0.7ms, 如果是10個的話,那麼賦值時間就是7ms, 如果屬性字元串的內容再複雜一些,那麼用時肯定會比這個高。當然我們可以使用第三方提供的一些控制項和方法將這部分時間給優化掉,這個可以放到以後再討論。

今天的博客就到這兒吧,目的是在使用Masonry時要合理的進行使用,有必要時,可以使用Frame進行佈局。

  

 

上述demo -github分享鏈接:https://github.com/lizelu/FPSProfileDemo

 


您的分享是我們最大的動力!

-Advertisement-
Play Games
更多相關文章
  • 綁定事件的處理方法任何元素都有事件屬性,而綁定事件就是將這個事件與一個函數相連接。 ①句柄事件dom.onXXX = function () {代碼塊} 以on開頭的事件屬於句柄事件相容性非常好,但是一個事件只能綁定一個處理函數。當綁定多個時後面的會覆蓋前面的。這種方法相當於在HTML的行間添加事件 ...
  • 下麵總結一下js中時間戳與日期格式的相互轉換: 1. 將時間戳轉換成日期格式: 註意:如果是Unix時間戳記得乘以1000。比如:PHP函數time()獲得的時間戳就要乘以1000。 2. 將日期格式轉換成時間戳: 以上三種獲取方式的區別: 第一、第二種:會精確到毫秒 第三種:只能精確到秒,毫秒用0 ...
  • 1、二級制操作優於Math 如: 2、慎用|| 大量運用if(x null){ x={} } 優於x=x||{} 3、switch 性能優於if...else if... ...
  • 這篇文章主要介紹了jQuery學習筆記之Ajax用法,結合實例形式較為詳細的分析總結了jQuery中ajax的相關使用技巧,包括ajax請求、載入、處理、傳遞等,需要的朋友可以參考下 本文實例講述了jQuery學習筆記之Ajax用法。分享給大家供大家參考,具體如下: 原文鏈接:https://yq. ...
  • 貪吃蛇的經典玩法有兩種: 第一種是筆者小時候在掌上游戲機最先體驗到的(不小心暴露了年齡),具體玩法是蛇吃完一定數量的食物後就通關,通關後速度會加快;第二種是諾基亞在1997年在其自家手機上安裝的游戲,它的玩法是吃到沒食物為止。筆者要實現的就是第二種玩法。 MVC設計模式 基於貪吃蛇的經典,筆者在實現 ...
  • 使用chrome瀏覽器選擇記住密碼的賬號,輸入框會自動加上黃色的背景,有些設計輸入框是透明背景的,需要去除掉這個黃色的背景; 方法1:陰影覆蓋 由於是設置顏色覆蓋,所以只對非透明的純色背景有效; 方法2:修改chrome瀏覽器渲染黃色背景的時間 完美解決 ...
  • activity生命周期知識點整理 Activity: 是一個應用組件,用戶可與其提供的屏幕進行交互。視窗通常會充滿屏幕,但也可以小於屏幕並浮動在其他視窗之上。 一個activity的什麼周期: 啟動運行狀態( onCreat() onStart() onResume() ) 暫停狀態( onPau ...
  • 1.發簡訊 頭文件 頭部代理 發送信息 代理方法實現 2.撥打電話 3.發送郵件 4.發送QQ消息 ...
一周排行
    -Advertisement-
    Play Games
  • 移動開發(一):使用.NET MAUI開發第一個安卓APP 對於工作多年的C#程式員來說,近來想嘗試開發一款安卓APP,考慮了很久最終選擇使用.NET MAUI這個微軟官方的框架來嘗試體驗開發安卓APP,畢竟是使用Visual Studio開發工具,使用起來也比較的順手,結合微軟官方的教程進行了安卓 ...
  • 前言 QuestPDF 是一個開源 .NET 庫,用於生成 PDF 文檔。使用了C# Fluent API方式可簡化開發、減少錯誤並提高工作效率。利用它可以輕鬆生成 PDF 報告、發票、導出文件等。 項目介紹 QuestPDF 是一個革命性的開源 .NET 庫,它徹底改變了我們生成 PDF 文檔的方 ...
  • 項目地址 項目後端地址: https://github.com/ZyPLJ/ZYTteeHole 項目前端頁面地址: ZyPLJ/TreeHoleVue (github.com) https://github.com/ZyPLJ/TreeHoleVue 目前項目測試訪問地址: http://tree ...
  • 話不多說,直接開乾 一.下載 1.官方鏈接下載: https://www.microsoft.com/zh-cn/sql-server/sql-server-downloads 2.在下載目錄中找到下麵這個小的安裝包 SQL2022-SSEI-Dev.exe,運行開始下載SQL server; 二. ...
  • 前言 隨著物聯網(IoT)技術的迅猛發展,MQTT(消息隊列遙測傳輸)協議憑藉其輕量級和高效性,已成為眾多物聯網應用的首選通信標準。 MQTTnet 作為一個高性能的 .NET 開源庫,為 .NET 平臺上的 MQTT 客戶端與伺服器開發提供了強大的支持。 本文將全面介紹 MQTTnet 的核心功能 ...
  • Serilog支持多種接收器用於日誌存儲,增強器用於添加屬性,LogContext管理動態屬性,支持多種輸出格式包括純文本、JSON及ExpressionTemplate。還提供了自定義格式化選項,適用於不同需求。 ...
  • 目錄簡介獲取 HTML 文檔解析 HTML 文檔測試參考文章 簡介 動態內容網站使用 JavaScript 腳本動態檢索和渲染數據,爬取信息時需要模擬瀏覽器行為,否則獲取到的源碼基本是空的。 本文使用的爬取步驟如下: 使用 Selenium 獲取渲染後的 HTML 文檔 使用 HtmlAgility ...
  • 1.前言 什麼是熱更新 游戲或者軟體更新時,無需重新下載客戶端進行安裝,而是在應用程式啟動的情況下,在內部進行資源或者代碼更新 Unity目前常用熱更新解決方案 HybridCLR,Xlua,ILRuntime等 Unity目前常用資源管理解決方案 AssetBundles,Addressable, ...
  • 本文章主要是在C# ASP.NET Core Web API框架實現向手機發送驗證碼簡訊功能。這裡我選擇是一個互億無線簡訊驗證碼平臺,其實像阿裡雲,騰訊雲上面也可以。 首先我們先去 互億無線 https://www.ihuyi.com/api/sms.html 去註冊一個賬號 註冊完成賬號後,它會送 ...
  • 通過以下方式可以高效,並保證數據同步的可靠性 1.API設計 使用RESTful設計,確保API端點明確,並使用適當的HTTP方法(如POST用於創建,PUT用於更新)。 設計清晰的請求和響應模型,以確保客戶端能夠理解預期格式。 2.數據驗證 在伺服器端進行嚴格的數據驗證,確保接收到的數據符合預期格 ...