High Performance Auto Layout

前言


我們都希望自己的app能流暢運行不掉幀乖菱,這個topic介紹了

  • iOS12蘋果都做了哪些針對流暢度的優(yōu)化
  • 相關的底層運行機制
  • 怎樣高效地使用自動布局
  • autolayout相關

iOS12的優(yōu)化


首先静陈,蘋果在iOS12對autolayout做了性能優(yōu)化,以下是幾個參數(shù)對比螟碎,灰色是iOS11眉菱,藍色是iOS12。

Performance benchmark

橫軸是時間掉分,可以看到Moving Tree的提升非常大俭缓,相信大家對于滑動列表時的卡頓(hiccup)都深有感觸克伊,以前我針對列表滑動這塊也做了不少優(yōu)化,這次更新iOS12后發(fā)現(xiàn)以前一些沒有做優(yōu)化的頁面华坦,有輕微卡頓的都不卡了愿吹,不過在一些性能敏感頁還是有卡頓現(xiàn)象,還是需要自己去優(yōu)化的惜姐。

Render Loop的運行原理


The render loop is the process that runs potentially at 120 times every second that make sure that all the content is ready to go for each frame.
———— by Ken Ferry

render loop是一個可以最多每秒運行120次的過程犁跪,用來保證每幀刷新前需要渲染的內(nèi)容都已經(jīng)準備好。

這個過程有三個階段歹袁,
先Update Constraints坷衍,再Layout,最后Display条舔。

Render Loop Workflow

Update Constraints從葉節(jié)點view開始執(zhí)行枫耳,直到window;
layoutSubviews則是反過來逞刷,從window開始嘉涌,傳遞到最終的葉節(jié)點view;
最后是drawRect繪制夸浅,也是從window開始仑最;

蘋果在設計上為了減少布局的重復調(diào)用,分了這3個階段帆喇,并提供了平行的類似功能的方法警医,比如updateConstraints和layoutSubviews,setNeedsUpdateConstraints和setNeedsLayout等

Render Loop Methods

看到這里我感覺有必要重溫一下這些布局方法坯钦,這里就簡單回顧一下Update Constraints的3個方法

updateConstraints()

一般來說要改變某個約束预皇,我們可以在某個action或方法中改變約束就可以了,但我們也可以重寫某個view的updateConstraints婉刀,在重寫的updateConstraints里集中改變一批約束吟温。
updateConstraints通常是布局有變化時,系統(tǒng)給我們調(diào)用的突颊,也可以由setNeedsUpdateConstraints觸發(fā)鲁豪,由于調(diào)用在render loop的第一階段,他有兩個適用場景

  1. 當我們有許多約束要產(chǎn)生變化律秃,比如橫豎屏切換時爬橡,我們可以在traitCollectionDidChange里調(diào)用setNeedsUpdateConstraints,updateConstraints里集中處理需要變化的約束
  2. 當我們希望盡早產(chǎn)生這些變化

要注意的問題

  1. 這個方法有可能每秒調(diào)用120次棒动,所以要避免churning constraints糙申,也就是不要deactivate所有約束,再重新activate他們船惨;只改變需要改變的約束柜裸,對于不變的約束只添加一次
  2. 方法內(nèi)不要調(diào)setNeedsUpdateConstraints缕陕,會產(chǎn)生feedback loop,雖然不是死循環(huán)但也會降低性能
  3. 在最后一行調(diào)用[super updateConstraints]疙挺,保證向父view傳遞
setNeedsUpdateConstraints()

這個方法用來標記當layout即將發(fā)生時榄檬,讓系統(tǒng)調(diào)用updateConstraints。
通常我們用它來優(yōu)化批量的約束變化衔统,這樣可以避免重復計算。調(diào)用后并不會馬上調(diào)updateConstraints海雪,而是在下一次render loop的layout即將發(fā)生時锦爵,調(diào)用updateConstraints

updateConstraintsIfNeeded()

當有l(wèi)ayout變化時,系統(tǒng)會調(diào)用這個方法奥裸,更新當前view和他的subviews的所有約束险掀,也可以由我們主動調(diào)用,來獲得最新的布局湾宙,和layoutIfNeeded類似樟氢。
禁止重寫這個方法。調(diào)用后也不會觸發(fā)updateConstraints侠鳄。

另外還提到了如果使用interface builder布局埠啃,能避免踩到一些降低性能的坑,但我覺得最好還是用純代碼更靈活些伟恶。

以下是會降低性能的坑:

deactivate all再activate導致性能很差
上面的做法和這種類似盼铁,顯然性能很差

好了灌灾,我們可以了解一下當激活約束時,到底發(fā)生了什么?

激活約束時的workflow

Update Phase
view通常是在一個window里缘揪,當update Constraint phase開始時, window會實例化一個布局引擎(layout engine)号杠,當給view添加約束時称簿,會將約束對應的等式(equation)

firstItem.firstAttribute {=,<=,>=} secondItem.secondAttribute * multiplier + constant

交給布局引擎,布局引擎通過代數(shù)運算解出view布局需要知道的相應變量的值即寒,如minX橡淆、minY、width蒿叠、height明垢。
其實就是最簡單的代數(shù)里的解方程。市咽。痊银。如下

把text1的變量代入,解出text2的變量施绎,以此類推

解完后會通知view溯革,有value改變了贞绳,
view接著調(diào)用 [superView setNeedsLayout],讓自己進入layout phase致稀;

準備進入Layout Phase

Layout Phase
view會將engine里計算好的variable值 copy到自己的frame冈闭,subview再調(diào)用setBounds,setCenter抖单,完成布局萎攒;

Layout

所以每一次在updateConstraints方法里deactivate constraints,再reactivate都會重復 實例化布局引擎-解方程-銷毀的過程矛绘,有可能每秒執(zhí)行多次耍休,從而導致性能問題;

正確的做法應該是這樣

保證只執(zhí)行一次

如何高效地使用自動布局


don't pay for what you don't use
為了性能考慮货矮,不是同一個父view下的view是不應該相互產(chǎn)生約束關系的(雖然可以這么做)羊精,因為會顯著增加布局引擎的計算復雜度(類似于多個光源在多個物體上產(chǎn)生陰影),而目前iOS12里計算復雜度隨view增加是線性增長的囚玫;
所以也不要寫重復約束和沒有用的約束喧锦;

don't wedge two layouts into one set of constraints
在一個視圖里別搞兩套布局關系,如下圖

看著腦殼疼

總結(jié):我們使用傳統(tǒng)的frame布局就是一個布局抓督、繪制燃少、渲染的過程,使用自動布局其實就多了一個布局引擎運算本昏。視頻里特別提到用約束來布局并不會比用frame布局消耗太多的性能供汛,因為engine的計算優(yōu)化了,過程很高效涌穆,所以不要避免使用autolayout怔昨,你可以頻繁地使用它,但不要添加多余或重復的約束宿稀。

和autolayout有關的東西


Inequality(也就是>=和<=)會消耗更多性能嗎趁舀,和等號相比非常小,只是多了一個變量而已祝沸;
setConstant 做了最大程度的優(yōu)化矮烹,鼓勵使用;
priority 只是告訴引擎一個minimize error罩锐,對性能影響不大奉狈;

Instrument增加了新的分析layout性能的工具(一片掌聲)
然而目前beta 版里沒有...

前瞻,可以看到layout占用的CPU涩惑、發(fā)生churning的view數(shù)量等
關于churning

關于intrinsicContentsize

intrinsicContentsize給UIView添加約束

假如你寫死寬高仁期,不需要intrinsicContentsize,可以告訴引擎不用計算這個view的intrinsicContentSize,優(yōu)化性能跛蛋。
當然也可以返回一個指定的size熬的,都需要重寫,做法如下

swift版
OC版

關于systemLayoutSizeFittingSize
和intrinsicContentsize相反赊级,他是從布局引擎獲取size
每次調(diào)用該方法都要創(chuàng)建和銷毀一個布局引擎押框,所以比較耗性能,不應該頻繁調(diào)用理逊。

systemLayoutSizeFittingSize workflow

關于約束沖突(Unsatisfiable Constraints)
會降低性能橡伞,也可能掩蓋其他的布局問題,所以一定要解決晋被!

視頻地址:
https://developer.apple.com/videos/play/wwdc2018/220/

最后編輯于
?著作權歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末骑歹,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子墨微,更是在濱河造成了極大的恐慌,老刑警劉巖扁掸,帶你破解...
    沈念sama閱讀 218,682評論 6 507
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件翘县,死亡現(xiàn)場離奇詭異,居然都是意外死亡谴分,警方通過查閱死者的電腦和手機锈麸,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,277評論 3 395
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來牺蹄,“玉大人忘伞,你說我怎么就攤上這事∩忱迹” “怎么了氓奈?”我有些...
    開封第一講書人閱讀 165,083評論 0 355
  • 文/不壞的土叔 我叫張陵,是天一觀的道長鼎天。 經(jīng)常有香客問我舀奶,道長,這世上最難降的妖魔是什么斋射? 我笑而不...
    開封第一講書人閱讀 58,763評論 1 295
  • 正文 為了忘掉前任育勺,我火速辦了婚禮,結(jié)果婚禮上罗岖,老公的妹妹穿的比我還像新娘涧至。我一直安慰自己,他們只是感情好桑包,可當我...
    茶點故事閱讀 67,785評論 6 392
  • 文/花漫 我一把揭開白布南蓬。 她就那樣靜靜地躺著,像睡著了一般。 火紅的嫁衣襯著肌膚如雪蓖康。 梳的紋絲不亂的頭發(fā)上铐炫,一...
    開封第一講書人閱讀 51,624評論 1 305
  • 那天,我揣著相機與錄音蒜焊,去河邊找鬼倒信。 笑死,一個胖子當著我的面吹牛泳梆,可吹牛的內(nèi)容都是我干的鳖悠。 我是一名探鬼主播,決...
    沈念sama閱讀 40,358評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼优妙,長吁一口氣:“原來是場噩夢啊……” “哼乘综!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起套硼,我...
    開封第一講書人閱讀 39,261評論 0 276
  • 序言:老撾萬榮一對情侶失蹤卡辰,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后邪意,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體九妈,經(jīng)...
    沈念sama閱讀 45,722評論 1 315
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 37,900評論 3 336
  • 正文 我和宋清朗相戀三年雾鬼,在試婚紗的時候發(fā)現(xiàn)自己被綠了萌朱。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 40,030評論 1 350
  • 序言:一個原本活蹦亂跳的男人離奇死亡策菜,死狀恐怖晶疼,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情又憨,我是刑警寧澤翠霍,帶...
    沈念sama閱讀 35,737評論 5 346
  • 正文 年R本政府宣布,位于F島的核電站蠢莺,受9級特大地震影響壶运,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜浪秘,卻給世界環(huán)境...
    茶點故事閱讀 41,360評論 3 330
  • 文/蒙蒙 一蒋情、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧耸携,春花似錦棵癣、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,941評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至,卻和暖如春河劝,著一層夾襖步出監(jiān)牢的瞬間壁榕,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 33,057評論 1 270
  • 我被黑心中介騙來泰國打工赎瞎, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留牌里,地道東北人。 一個月前我還...
    沈念sama閱讀 48,237評論 3 371
  • 正文 我出身青樓务甥,卻偏偏與公主長得像牡辽,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子敞临,可洞房花燭夜當晚...
    茶點故事閱讀 44,976評論 2 355

推薦閱讀更多精彩內(nèi)容