What's New in UICollectionView in iOS 10?
在iOS 10中,UIKit的兩個(gè)容器控件得到新的特性萌丈,apple在會(huì)上強(qiáng)調(diào)了這些新特性所帶來(lái)的性能提升雷则,現(xiàn)總結(jié)如下:
1.cell生命周期的變化
只有UICollectionView支持這項(xiàng)更新,且貌似開(kāi)啟prefetchingEnabled才行月劈,具體表現(xiàn)為,與當(dāng)前區(qū)域較為臨近的離屏cell將不會(huì)立即進(jìn)入reuse隊(duì)列,而是仍然駐留在那個(gè)位置湿右,等待用戶(hù)往上滑動(dòng)去再現(xiàn)它罚勾,這樣一來(lái),cellForItemAtIndexPath將不會(huì)被反復(fù)調(diào)用——這些沒(méi)有被立即recovery的cell們?cè)僦匾?jiàn)天日之后只會(huì)往delegate發(fā)送willDisplayCell進(jìn)行一下通知而已尖殃。那么聯(lián)系到大多數(shù)情況我們都在cellForItemAtIndexPath函數(shù)內(nèi)部做model的填充,那么當(dāng)用戶(hù)的確在某個(gè)cell區(qū)間之內(nèi)反復(fù)滑動(dòng)缔俄,可以明顯緩解由于反復(fù)的圖片加載、文字繪制等操作帶來(lái)的瞬時(shí)cpu壓力俐载。但是對(duì)于某些情況下,例如cell每次被顯示出來(lái)都可能處于不一樣的狀態(tài)挖炬,那么就需要將這些狀態(tài)改變移步到willDisplayCell了状婶。
對(duì)于iOS 10之前的UIKit,其實(shí)我們也可以定制一種機(jī)制來(lái)避免草姻,當(dāng)被reuse的cell被重新使用并且它上面的內(nèi)容與當(dāng)前需要填充的內(nèi)容一致走敌,被重新填充一遍的浪費(fèi)。(比如self.model == model)
2.prefetchDataSource
這個(gè)新的協(xié)議屬性是UICollectionView和UITableView都支持的掉丽。這個(gè)協(xié)議其實(shí)是用來(lái)通知我們,當(dāng)前滑動(dòng)到某個(gè)區(qū)域后僧须,根據(jù)這次滑動(dòng)的方向接下去可能還會(huì)滑向哪些indexPaths项炼。好讓我們做一些數(shù)據(jù)上的預(yù)備或者銷(xiāo)毀。
分為2個(gè)函數(shù):
required: prefetchRowsAtIndexPaths
這個(gè)協(xié)議方法提供一個(gè)數(shù)組暂论,這個(gè)數(shù)組提示了按著本次滑動(dòng)方向拌禾,再接下去要碰到哪些indexPaths了。
以UITableView為例闻蛀,回調(diào)過(guò)來(lái)的這個(gè)數(shù)組為當(dāng)前屏幕邊緣的indexPath的接下去(上或者下)第10個(gè)開(kāi)始算的indexPath您市,假設(shè)我當(dāng)前向下滑動(dòng),底部的section:0 row:15變成了section:0 row:16茵休,此時(shí)協(xié)議回傳section:0 row:26(之前已經(jīng)將17-25傳給我們了)給我們手蝎,此時(shí)如果我們改變了方向往上滑動(dòng)盗尸,那么協(xié)議會(huì)一口氣返回10個(gè)indexPath給我們,而這10個(gè)是最頂部顯示indexPath前面的10個(gè)鞍时。
optional: cancelPrefetchingForRowsAtIndexPaths
這個(gè)協(xié)議返回的數(shù)組用于在扣蜻,當(dāng)我們快速滑動(dòng)到某個(gè)區(qū)域后又立刻按著反方向滑動(dòng),那么原本被預(yù)估要出現(xiàn)的幾個(gè)indexPath會(huì)被取消掉這樣锐极,這個(gè)數(shù)組就是存儲(chǔ)被取消預(yù)估的indexPath芳肌,經(jīng)過(guò)測(cè)試,假設(shè)此時(shí)最頂部是section:0 row:10亿笤,并且方向?yàn)樯系墓浪鉯ndexPaths有10個(gè)了(row : 0-10),那么當(dāng)我們往下滑動(dòng)到頂部為section:0 row:16的時(shí)候汪榔,這個(gè)協(xié)議會(huì)回調(diào)一個(gè)section:0 row:0給我們肃拜,也就是差了15個(gè)這樣的個(gè)數(shù)之后就會(huì)調(diào)用該協(xié)議來(lái)告訴我們?cè)撊∠ヮA(yù)估算的indexPath了。
目前從UITableView看來(lái)士聪,這個(gè)功能用處不大猛蔽,他只是提供一個(gè)參考值給我們。通過(guò)用戶(hù)的手勢(shì)和拉動(dòng)的屏幕距離來(lái)估算給我們一段可能出現(xiàn)的區(qū)間枢舶,這個(gè)區(qū)間又是根據(jù)apple自己定的規(guī)則(即上面提到的替久,提前10個(gè)、返回10個(gè)后众、差15個(gè)開(kāi)始取消),實(shí)際上用戶(hù)的操作行為難以被估算教藻,很可能這些預(yù)讀取的索引只有10%的命中率:假設(shè)用戶(hù)是突然改變滑動(dòng)方向右锨,此時(shí)咱們已經(jīng)接受過(guò)上下方向共20個(gè)的預(yù)讀索引了,然后用戶(hù)只在當(dāng)前區(qū)間進(jìn)行小幅度的上下滑動(dòng)绍移,那么預(yù)讀操作只會(huì)命中邊緣的1-2個(gè)蹂窖。
3.prefetchingEnabled
仍然是UICollectionView獨(dú)占,提供了cell的預(yù)讀取功能瞬测。具體表現(xiàn)在,當(dāng)我們滑動(dòng)至某個(gè)區(qū)域的時(shí)候灯蝴,例如section:1? item:5到section:1 item:10這個(gè)區(qū)間狮斗,那么UICollectionView就會(huì)去讀取cellForItemAtIndexPath來(lái)預(yù)先加載大概section:1 item:3到section:1 item:12這樣的區(qū)間,這個(gè)預(yù)讀操作apple是說(shuō)為異步的碳褒,但是本著UIView必須在主線程下操作的規(guī)矩沙峻,應(yīng)該指的是 當(dāng)前的滾動(dòng)結(jié)束之后layoutSubviews被調(diào)用完了在下一次runloop中去訪問(wèn)cellForItemAtIndexPath 這樣,利用用戶(hù)屏幕靜止的時(shí)間去讀取摔寨。
預(yù)讀取了cell并存儲(chǔ)在reuse隊(duì)列中之后,當(dāng)這些cell真的需要被顯示了删顶,那么就可以willDisplayCell通知一下直接刷出來(lái)淑廊,這樣一來(lái),用戶(hù)感覺(jué)不到諸如圖片的下載這樣的讀取過(guò)程季惩。
當(dāng)開(kāi)啟這個(gè)功能時(shí),prefetchDataSource會(huì)受到影響啥繁,預(yù)估算indexPath的策略會(huì)和關(guān)閉這個(gè)功能的時(shí)候不一樣。也就是關(guān)閉的時(shí)候prefetchDataSource同UITableView一樣的機(jī)制酬核。
同樣由于某些需求宪睹,這個(gè)功能可以隨時(shí)被關(guān)閉。