高性能AutoLayout High Performance Auto Layout

01.iOS 12 的改善

UICollectionView性能對比,item自動適配大小,iOS 11看上去有掉幀卡頓的現象,iOS 12表現完美,沒有掉幀。

高性能AutoLayout High Performance Auto Layout

下面是iOS 11和iOS 12的性能對比,灰色條是iOS 11的耗時,藍色條是iOS 12的耗時。在iOS 12上會很大程度改善你的應用程序。

高性能AutoLayout High Performance Auto Layout

02.實現和感觀

render loop

render loop 是一個每秒鐘跑120次的一個進程,是為了確保所有的內容都能為每一個frame做好準備。lender loop 一共包括三個步驟來更新約束,佈局和渲染。

首先,每一個需要接收到更新約束的view會從子view向上傳遞,直到window

然後,每一個接收到的view開始layoutsubviews,和更新約束是從相反的方向開始,layout從window開始到每一個子view進行layout。

最後,每一個需要渲染的view,和layout相同,從父view向子view開始渲染。

高性能AutoLayout High Performance Auto Layout

render loop目的是為了避免重複的工作。

舉一個例子:一個UILable 需要一個約束來描述它的大小,但是有很多屬性會影響他的大小,設置它的font,text size等等都會受到影響。當一個屬性改變的時候,可能text其他屬性也會被重新賦值,很有可能調用一堆屬性的setter方法,這樣效率會很低。

只需要調用updateConstraints 並指定好要更新的屬性,render loop會幫助你計算好它的frame並完成渲染,從而避免多次設置的重複工作。

高性能AutoLayout High Performance Auto Layout

在設置約束的一些不好的寫法,每次開始的時候調用deactivate,設置結束之後調用activate。相當於layoutsubviews,每次調用layoutsubviews你銷燬你subviews,重新創建在重新添加。這樣性能不會很好。

高性能AutoLayout High Performance Auto Layout

每次都是移除並重新添加,相當於這樣的代碼

高性能AutoLayout High Performance Auto Layout

官方建議寫法為,約束只需要添加一次,每次調用super.updateConstraints完成約束的更新。

高性能AutoLayout High Performance Auto Layout

render loop有很強的特定性,它的好處可以避免一些重複性的工作。但是它也很危險,因為它調用的頻率會很高,是非常敏感的一段代碼。

蘋果建議使用interface builder進行佈局。

高性能AutoLayout High Performance Auto Layout

激活一個約束

在設置約束的時候發生了什麼事情呢?從下面的圖中可以看到整體的一個結構。

有一個view 在window上,window上面有個叫做engine的內部對象,engine是autolayout計算的核心,當添加一個約束的時候,會創建一個Equation對象,然後會把equation對象添加到engine上,equation依據variables對象。

高性能AutoLayout High Performance Auto Layout

variables相當於每一個約束的值,比如說一個UIlabel有四個約束minX minY width height那麼minX minY width height 就是variables。

高性能AutoLayout High Performance Auto Layout

個圖為例,這裡只關注水平方向的佈局,首先要創建equation,然後每一個equation會添加給engine。

高性能AutoLayout High Performance Auto Layout

engine會去計算這些variables,engine會把每一個view的variables用數學公式計算出一個定量。

高性能AutoLayout High Performance Auto Layout

計算出定量之後,engine會發送通知,通知view調用他父view的setNeedsLayout()方法,就會完成render loop的第一步更新約束,然後繼續render loop的 layout更新,最後view會直接拷貝engine計算好的定量進行賦值渲染。

高性能AutoLayout High Performance Auto Layout

engine是一個layout的緩存,和依賴的追蹤器。非常有方向性的,它知道哪些約束會影響哪些view,當你改變一些約束時,它能夠準確的更新。

不需要的約束不要加

你也可以穿過層級,為兩個沒有相同父view的view設置約束,但是這樣性能會很差。

大多數情況下,view的約束應該加在他的父view或者兄弟view上。

高性能AutoLayout High Performance Auto Layout

最小限度的錯誤

當view向engine獲取約束的值的時候,engine會確保錯誤率最小

高性能AutoLayout High Performance Auto Layout

03.構建高性能layout

創建一個layout

構建一個社交軟件的cell,通過autolayout進行佈局。

高性能AutoLayout High Performance Auto Layout

查找代碼中的問題

下面是beta版的一個調試工具,最上面第一項表示你CPU的使用情況,峰值的地方可能需要關注一下你的layout是否有性能問題,下面一行追蹤你的約束,高的地方說明是有問題的。

第二項是你對約束添加、刪除、修改等操作的記錄。

第三項是當前控件的大小。

高性能AutoLayout High Performance Auto Layout

點擊約束峰值的地方可以看詳情。

創建高性能的佈局

通過instrument調試工具,可以看出一些佈局上的耗時問題。一下是需要注意的幾點:

1.避免刪除所有的約束的情況

2.對於靜態約束,只需要添加一次

3.只改變需要改變的約束

4.儘量用hide() 方法隱藏view,而不是remove然後在add

有些控件比較特殊,比如 UIImageView,它的大小是根據他的image計算確定他的content size。UILabel是根據他的text確定的。這些都會返回它們的固有尺寸,UIView 會直接通過他們的固有尺寸來當做約束條件。

重寫 intrinsicContentSize

text的計算是成本很高的,所以UIlabel的size通過text去控制計算開銷成本會很高。這個時候我們可以 通過重寫 UILabel 的 intrinsicContentSize 來直接控制它的固有尺寸。如果已知一個UILabel的展示size,直接重寫其屬性,其他情況使用UIView.noIntrinsicMetric。

高性能AutoLayout High Performance Auto Layout

參考:WWDC2018《High Performance Auto Layout》


分享到:


相關文章: