今年的Session 202 - What's New in Cocoa Touch是這樣的邏輯:
- UIKit舊有功能的效能優化
- 滾動新增資料預獲取功能
- 降低圖片渲染不必要的記憶體開銷
- 優化Auto Layout計算的時間複雜度
- UIKit舊有功能的API調整
- 框架中舊的全域性變數、常量以及函式被巢狀進物件,使得它們看上去更Swift
- 淘汰舊版本的編解碼API,新增更安全的編解碼API
- UIKit的新功能
- Notification的互動、分組、設定
- Messages的動態貼紙、iPhone X下Home Bar的互動響應
- 密碼的自動生成和填充
- Siri Shortcut
UIKit的效能提升
- UIKit通過“資料預載入”和“CPU算力調整”來做了滾動優化,這兩項優化對於UITableView和UICollectionView甚至你自己定製的UIScrollView都有效。
- UIKit針對圖片渲染相關API的優化了記憶體開銷
- UIKit優化了Auto Layout運算的開銷
“資料預載入”的背後是一個這樣的故事:
我們舉UITabelView為例子,一次完整的Cell載入過程是這樣的:
- 在UITableView的DataSource的
- tableView:cellForRowAt:
方法中,工程師將Cell例項從快取佇列中取出,或直接初始化一個新cell - 工程師將資料取出,然後賦值給Cell例項
- UIKit會呼叫layoutSubviews給cell的子view作佈局
- UIKit將cell繪製出來並展示
只有一幀之內做完這4件事情,UITableView滾動的時候才不會卡。
在以上4步中,第2步開銷大小是取決於不同場合不同業務邏輯的。因為有的時候你用於展示這個Cell的資料可能已經預先整理過,直接拿來就可用,不會有什麼大的開銷。但有的時候你用於展示這個Cell的資料是來自於資料庫、或者本地檔案、或者其它地方的,那麼就會多一個從其他地方取資料整理資料的過程,那麼就會增加一筆額外開銷,這一筆開銷就很有可能導致掉幀卡頓。
如上圖所示,在之前UIKit的實現中,預先取資料這個行為本身也是有的,而且也是非同步的。但由於取資料的時機是跟載入Cell的時機是同時開始的,所以CPU又要預先取資料,也要載入、渲染Cell。這就導致了CPU在一幀的時間內同時做兩件事,就有可能導致掉幀。
而這次的優化,就是把預先取資料的行為放在了Cell渲染完成之後。這樣就可以在一幀剛開始的時候,將CPU從資料預載入的事務中解放出來,全力去做Cell相關的事情,這樣就能夠儘早將Cell渲染完交差。然後CPU再進行資料非同步預載入的事情。
在這一輪優化中,UIKit針對資料預載入提供了新的Protocol。拿UITableView來說,就提供了UITableViewDataSourcePrefetching
,這個Protocol中包含兩個方法:
func tableView(_ tableView: UITableView, prefetchRowsAt indexPaths: [IndexPath])
func tableView(_ tableView: UITableView,
cancelPrefetchingForRowsAt: indexPaths [IndexPath])
複製程式碼
- (void)tableView:prefetchRowsAt:
- (void)tableview:cancelPrefetchingForRowsAt:
複製程式碼
實現這個protocol時,只有prefetchRowsAt
這個方法是必須的。cancelPrefetchingForRowsAt
這個會由系統呼叫,比如當你cell的資料是需要下載才能得到的,那麼結合斷點續傳功能和這個protocol,你就能很優雅地處理cell資料載入的事情。
“算力調整”的背後是這樣的故事:
蘋果工程師在不斷地做效能檢測的時候,又發現了一個這樣的情況:如果使用者之前在看一些載入開銷比較小的Cell,然後使用者突然滾動到載入開銷比較大的Cell時,UIKit依舊會出現掉幀的卡頓現象。而且此時系統本身也沒什麼負載,也沒有什麼開銷大的後臺任務在執行,因此就排除了CPU負載過大導致卡頓這一可能。
那為什麼CPU沒什麼負載,卻依舊出現了卡頓呢?他們研究了一輪,發現原來這是因為CPU效能排程邏輯導致的,這段過程是這樣:
- 當使用者之前一直在看載入開銷小的Cell的時候,其本身需要的CPU效能並不高,那麼此時CPU效能排程管理器就更加傾向於保持低效能執行,這樣能夠省電。
- 當使用者突然劃到一個載入開銷大的Cell的時候,CPU效能排程管理器也並不知道你這時候要載入一個開銷那麼大的Cell,於是它就還是在低效能的狀態下去載入這個開銷比較大的Cell。
- 當CPU效能排程器反應過來這個Cell原來需要那麼大的開銷的時候,它就會切到高效能去消化這個負載。不過往往這時候再提高CPU效能就已經晚了,就有很大機率會導致卡頓。
這個過程往往會發生在Feed流類似的應用中。比如你之前一直在看的Cell都是文字內容的,開銷極小。突然你劃到視訊Cell了,這個cell開銷很大,CPU效能排程管理器在Cell載入到一半了才去提高效能等級,那就很容易出現卡頓的情況了。
找到原因之後,優化的事情就好做了。現在蘋果工程師打通了整個流程,使得UIKit的資訊能夠傳遞到CPU效能排程管理器。當UIKit在載入下一個Cell的時候,如果發現這是一個載入開銷比較大的Cell,UIKit就會去通知CPU效能排程器,告訴排程器趕緊提高效能。這樣一來,因為CPU效能已經提前提上來了,那麼系統就能最大可能避免掉幀卡頓的情況發生。
也就是說,之前CPU的排程情況是這樣:
優化之後,CPU的排程就變成了這樣:
因為UIKit預測到了下一個Cell開銷比較大,所以提前跟CPU效能排程器打了招呼,於是CPU的效能就立刻提上來了。相比之前CPU效能慢慢往上提的情況,就更不容易出現卡頓。
圖片渲染相關API的記憶體優化
演講者先說了一遍記憶體是如何影響UI效能的,這一段其實可以說得很簡單:當系統剩餘記憶體不多,而此時你的應用又需要很大的一片記憶體時,系統就要通過回收記憶體或強行關閉後臺App的方式來為你的應用騰出記憶體來。系統為你騰記憶體這一操作的開銷導致了你的App此時需要更長時間的等待,進而影響了你App的UI效能。
為了緩解這個問題,iOS 12引入了Automatic Backing Store
這項技術。這項技術主要是針對畫圖類的App起作用,對於其他的場合無效。本質上的實現就是通過在保證色彩不失真的基礎上,使用更少的資料量,去表達一個畫素的顏色。
如下圖所示,在64位色的情況下,左右兩張圖片的資料量是一樣的,都是2.2M左右。雖然右邊只有黑白兩色,但是依舊使用了64位去儲存每個畫素的顏色色值。
所以呢,蘋果就想了個辦法,說既然右邊這張圖片只有黑白兩色,那我幹嘛還要用64位去表達一個顏色呢?8位就足夠了啊。於是,右邊這個圖每畫素的顏色用8位來表達之後,就變成只有275K了,於是記憶體就省了:
那為什麼不直接用1位呢?反正也就黑白兩色。對不起,因為色表標準最小就是8位的,如果你用了1位色,螢幕是不支援這套標準的。Automatic Backing Store
對左邊這幅圖無效,因為它不是圖片壓縮演算法,它只是在你用畫筆畫完圖片並且渲染的時候,把原來需要64位去儲存的單個畫素的色值,改成用8位去儲存而已,這個過程是有可能產生一定的色彩失真的。所以Automatic Backing Store
只適合畫圖類應用,在以下3個場景中,它是預設開啟的:
- UIView.draw()
- UIGraphicsImageRenderer
- UIGraphicsImageRenderer.Range
有關Automatic Backing Store
的內容,還可以看Session 219 - Image and Graphics Best Practices
Auto Layout計算的優化
iOS 12中,Auto Layout做了非常大的優化。
當一個View包含了N個佈局上互相獨立的子View時,Auto Layout的計算耗時是隨著子view數量的增加而線性增加的。因為蘋果工程師們的努力,iOS 12的計算耗時比iOS 11少了一些,如下圖:
當一個View包含了N個子View,且這N個子View的佈局存在依賴的情況時。iOS 11下Auto Layout的計算耗時是隨著子View的數量增加而指數性增長的。在iOS 12優化之後,計算耗時呈線性增長,這可以說是一個比較大的優化了。(但我一直是認為其實這本身就應該是一個線性時間內可以完成的任務,iOS 11的時候工程師怎麼把它實現成指數性增長的了?這個工程師該殺),如下圖:
當N個View相互巢狀時,iOS 11下Auto Layout的計算耗時是隨著子View的數量增加而指數性增長的。在iOS 12優化之後,計算耗時呈線性增長。我還是覺得這本身也是一個線性時間內可以完成的任務,當初在iOS 11把它實現成指數性增長任務的工程師該殺。如下圖:
更多的內容可以看Session 220 - High Performance Auto Layout
UIKit舊有API的修改
- 更Swift的UIKit
- 更安全的編解碼
更Swift的UIKit
在Swift 4.2中,有些全域性的Type被挪進了物件中,包括但不限於:
還有些全域性常量也被挪進了有關物件中,包括但不限於:
還有些全域性函式也被挪近了有關物件中,包括但不限於:
這麼一來,UIKit看起來確實更Swift了,只是升級4.2的時候,又要面對一堆編譯錯誤了。
更安全的編解碼
演講者只是在這裡提了一句,iOS 12提供了更安全的編解碼API,舊的API將會被淘汰。具體是什麼情況要去看Session 222 - Data You Can Trust
UIKit 新功能
- Notification
- Messages
- Automatic Passwords and Security Code AutoFill
- Siri Shortcuts
Notification API修改
-
Interaction
- iOS 12加強了針對Notification的互動,大部分介面開發者可以自由定製了。
-
Grouping
- iOS 12會將眾多Notification分組並展示,並且提供了API讓開發者在一定程度上決定如何進行分組。
-
Settings
- iOS 12向開發者提供了介面,使得開發者能夠讓使用者直接開啟或關閉通知。
以上三點演講者只是一帶而過,更多內容請看:
Session 710 - What's New in User Notifications
Session 711 - Using Grouped Notifications
Messages
iOS 12中,你可以將Message的人臉識別貼紙帶入camera中。如果你需要針對這些做更多的定製的話,你需要在Info.Plist中新增以下內容,MSMessagesAppPresentationContextMedia
其實就是指的camera:
<key>MSSupportedPresentationContexts</key>
<array>
<string>MSMessagesAppPresentationContextMessages</string>
<string>MSMessagesAppPresentationContextMedia</string>
</array>
複製程式碼
而且你也可以根據以下API檢視一條Message是不是動態的:
var presentationContext: MSMessagesAppPresentationContext
enum MSMessagesAppPresentationContext : UInt {
case messages
case media
}
複製程式碼
iOS 12也給Message新增了新的互動操作:之前在底部bar處水平滑動,系統會自動切換App。現在你的Message App可以接收這個事件,可以選擇覆蓋系統切換App的行為,或者執行你自己的行為。
Automatic Passwords and Security Code AutoFill
之前的iOS版本中,已經實現了自動輸入密碼的功能:
在iOS 12中,工程師可以在修改密碼的地方也彈出提示,告知使用者是否需要將密碼儲存在iCloud Keychain:
iOS 12還能夠幫你自動生成密碼,在註冊流程和修改密碼流程都能用,只要開發者給Password的輸入框打上tag告知這是一個密碼輸入框就好了:
在輸入手機號,傳送驗證碼,輸入驗證碼流程中,iOS 12在鍵盤上提供了讀取驗證碼的功能,這樣能夠使得使用者不必切來切去:
以上這些內容演講者也都只是稍微提了一下,具體內容可以看這裡:Session 204 - Automatic Strong Passwords and Security Code AutoFill
Safe Area
演講者把之前就已經有的SafeArea Insets
講了一遍,沒有提到任何新內容。只是說希望大家能夠儘早使用Safe Area Insets
去做不同裝置的UI適配。
最後給到了一個Session:Session 235 - UIKit: Apps for Every Size and Shape,根據演講者的說法來看,這個Session裡面可能有新內容,大家若是有興趣的話可以看一看。
Siri Shortcuts
Siri Shortcurs能夠使得你的App響應Siri的排程。具體的做法是響應來自各個App的Intents。當然,你也可以給自己的App設定Intents。每一個Intents都有不同的型別:
Siri會根據Intent找到對應的App,然後再解析使用者給出的指令,來決定本次操作是哪種型別,進而開發者給到對應的響應操作。
具體的情況還是要看以下這些Session:
Session 211 - Introduction to Siri Shortcuts
Session 214 - Building for Voice with Siri Shortcuts
Session 217 - Siri Shortcuts on the Siri Watch Face
以上就是WWDC 2018 - Session 202 - What's New in Cocoa Touch的解說