項(xiàng)目中碰到了這個(gè)問(wèn)題腋寨,很坑爹
觸發(fā)場(chǎng)景:
一個(gè)CollectionView有多個(gè)section劣针,每個(gè)section的數(shù)據(jù)源都通過(guò)單獨(dú)的網(wǎng)絡(luò)請(qǐng)求獲取,每次請(qǐng)求回來(lái)以后就刷新指定的section;
下拉刷新的時(shí)候,會(huì)同時(shí)并發(fā)這些section的網(wǎng)絡(luò)請(qǐng)求娘荡;
然后多刷幾次,就crash了驶沼,而且出現(xiàn)概率很高炮沐,crash的地方就是reloadSection,報(bào)的錯(cuò)就是[UICollectionView _endItemAnimationsWithInvalidationContext:tentativelyForReordering:]
經(jīng)測(cè)試回怜,如果直接用reloadData大年,是沒(méi)有問(wèn)題的,但是界面感覺(jué)會(huì)閃玉雾,效率也有點(diǎn)低翔试,理論上還是用reloadSection方法最好。
網(wǎng)上找了很多解決方案复旬,試過(guò)用performPatchUpdates垦缅,試過(guò)提前調(diào)用numbersOfItemInSection,都不管用
最后終于在stackOverFlow上發(fā)現(xiàn)了可能的原因:
再reloadSection的時(shí)候驹碍,其他section必須保證不變壁涎,否則就會(huì)出現(xiàn)上面的問(wèn)題柏蘑。
對(duì)比我現(xiàn)在的場(chǎng)景,感覺(jué)應(yīng)該就是這個(gè)原因了
因?yàn)槎鄠€(gè)section的網(wǎng)絡(luò)請(qǐng)求是并發(fā)的粹庞,每個(gè)請(qǐng)求回來(lái)都會(huì)reloadSection,那就可能會(huì)出現(xiàn)一個(gè)請(qǐng)求回來(lái)正在reloadSection的時(shí)候洽损,另一個(gè)網(wǎng)絡(luò)請(qǐng)求也完成了庞溜,剛好修改了數(shù)據(jù)源,
雖然都是在主線程碑定,但reloadSection方法應(yīng)該不是瞬間就完成的流码,如果在reloadSection執(zhí)行期間另外一個(gè)網(wǎng)絡(luò)請(qǐng)求修改了數(shù)據(jù)源,那就有問(wèn)題了延刘。
這個(gè)問(wèn)題怎么解決呢漫试?
1,每次都reloadData碘赖。 這個(gè)肯定是不能接受的驾荣,效果太差
2,讓服務(wù)器把這些網(wǎng)絡(luò)請(qǐng)求合并成一個(gè)普泡。 這個(gè)我倒是可以接受播掷,但服務(wù)器的同學(xué)肯定不能接受,而且改動(dòng)起來(lái)也太大
3撼班,現(xiàn)在采用的方案:客戶(hù)端把這些網(wǎng)絡(luò)請(qǐng)求合并成一個(gè)歧匈,然后統(tǒng)一reloadData。
其實(shí)也不是真正的合并請(qǐng)求砰嘁,只是用一個(gè)dispatchGroup件炉,將這些請(qǐng)求放到一個(gè)group中,等所有請(qǐng)求的結(jié)果都回來(lái)了再reloadData矮湘,看起來(lái)好像是合并了一樣斟冕。
具體實(shí)現(xiàn):
在下拉刷新時(shí)創(chuàng)建一個(gè)group,設(shè)置group的完成通知時(shí)間為reloadData板祝,然后 在每個(gè)section的網(wǎng)絡(luò)請(qǐng)求前宫静,調(diào)用group.enter(),在其網(wǎng)絡(luò)請(qǐng)求的完成回調(diào)里券时,調(diào)用group.leave()孤里。
注意:group.enter()和group.leave()必須成對(duì)出現(xiàn),且在同一個(gè)線程調(diào)用橘洞;網(wǎng)絡(luò)請(qǐng)求不管成功或者失敗捌袜,都需要調(diào)用group.leave(),不然group就永遠(yuǎn)完成不了了炸枣。
2017年11月29日更新:
創(chuàng)建的group在所有網(wǎng)絡(luò)請(qǐng)求的回調(diào)完成前都要保持對(duì)該group的引用虏等,否則如果當(dāng)回調(diào)時(shí)group已經(jīng)被釋放弄唧,那就會(huì)發(fā)生badAccess的crash!;羯馈候引!
發(fā)生這種情況的原因應(yīng)該是block對(duì)group的引用僅僅是弱引用,如果沒(méi)有其他強(qiáng)引用保證group不被釋放敦跌,group可能會(huì)在某些情況下會(huì)釋放澄干,導(dǎo)致回調(diào)時(shí)調(diào)用group.leave()時(shí)group已經(jīng)被釋放了,所以就crash了柠傍。