iOS的一些滑動(dòng)優(yōu)化

優(yōu)化過(guò)程

1.排除干擾項(xiàng)

排除以下可能影響加載速度的干擾項(xiàng):

1)去除加載/緩存/繪制圖片過(guò)程鸭津;

2)所有scrollView相關(guān)的delegate代碼去除践惑;

3)跟滑動(dòng)有關(guān)的KVO良漱,主要是contensize相關(guān)去除墅茉;

4)檢查是否hook了類里的一些方法(如果有隊(duì)友這么做了凡蜻,拿著刀找他去就行了)辣之;

去除以上干擾的狀態(tài)觅玻,我稱之為“白板狀態(tài)”想际,先優(yōu)化好此狀態(tài)的幀率,再加回這些進(jìn)行進(jìn)一步優(yōu)化串塑,不幸的是沼琉,白板狀態(tài)下,F(xiàn)PS并沒有顯著提升桩匪。

2.優(yōu)化開始

使用instrument的Time Profiler調(diào)試

1)collectionView的willDisplayCell方法耗時(shí)較多打瘪,檢查代碼發(fā)現(xiàn)是同事為了嘗試解決首次進(jìn)入時(shí)cell寬高會(huì)執(zhí)行從0到其實(shí)際寬度動(dòng)畫的bug,調(diào)用了layoutIfNeeded,去除后并未復(fù)現(xiàn)該bug闺骚。此時(shí)彩扔,7P表現(xiàn)良好FPS達(dá)到了55+,6P仍然處于20+僻爽,此時(shí)思路應(yīng)該是由于大量調(diào)用CPU虫碉,故6P的FPS仍然表現(xiàn)不佳;

2)經(jīng)檢查胸梆,瀑布流滑動(dòng)時(shí)敦捧,CollectionViewLayout的prepareLayout調(diào)用了過(guò)多次數(shù)(而prepareLayout意味著重新計(jì)算布局,圖片量越大碰镜,計(jì)算越耗時(shí)(我們的瀑布流使用了循環(huán)嵌套循環(huán))兢卵。根據(jù)collectionView的生命周期,當(dāng)contentSize變化的時(shí)候才會(huì)調(diào)用prepareLayout绪颖,或者在Layout里重寫了方法:

1

-?(BOOL)shouldInvalidateLayoutForBoundsChange:(CGRect)newBounds;

經(jīng)檢查發(fā)現(xiàn)隨著滑動(dòng)秽荤,newBounds的y一直變化,導(dǎo)致持續(xù)重新布局柠横。之所以重寫shouldInvalidateLayoutForBoundsChange方法窃款,是因?yàn)槲覀兪褂玫腄ZNEmptyDataSet在有contentOffset的情況下,刪除collectionView所有數(shù)據(jù)源之后的布局出現(xiàn)問(wèn)題牍氛。因此我們要針對(duì)shouldInvalidate方法的調(diào)用進(jìn)行優(yōu)化晨继,添加magic number,判斷僅當(dāng)size變化時(shí)糜俗,再重新繪制瀑布流:

@property?(assign,?nonatomic)?CGSize?newBoundsSize;

-?(BOOL)shouldInvalidateLayoutForBoundsChange:(CGRect)newBounds?{

if(CGSizeEqualToSize(self.newBoundsSize,?newBounds.size))?{

returnNO;

}

self.newBoundsSize?=?newBounds.size;

returnYES;

}

此時(shí)白板狀態(tài)7P的FPS已達(dá)60踱稍。6p正常滑動(dòng)已經(jīng)50+悠抹,快速滑動(dòng)時(shí)仍會(huì)降至20-30珠月;

3)下一步的優(yōu)化思路就是處理快速滑動(dòng),參照VVeboTableViewDemo中的方法進(jìn)行優(yōu)化楔敌。

需要注意和這個(gè)demo不同的是:

(1)collectionView無(wú)法通過(guò)CGRect取到即將顯示的所有indexPath啤挎;

(2)collectionView通過(guò)point取indexPath的時(shí)候point不能是右下角邊緣值,不然會(huì)返回item為0的indexPath卵凑;

(3)因?yàn)閐emo里是寫了個(gè)tableView的子類庆聘,而我直接在controller里處理了,所以hitTest 這里我取了一個(gè)折中的處理,但是效果并不是100%完美勺卢,在decelerating的過(guò)程中用手指停住伙判,手指只要不松開就不會(huì)加載當(dāng)前的cell;

(4)targetContentOffset:(inout CGPoint *)targetContentOffset 最好不要直接賦值黑忱,inout參數(shù)在別處改動(dòng)了會(huì)很麻煩宴抚。

下面貼上代碼來(lái)說(shuō)明這四點(diǎn):

@property?(nonatomic,?strong)?NSMutableArray?*needLoadArr;

//為了處理(3)中的hitTest

@property?(nonatomic,?assign)?CGPoint?targetOffset;

-?(void)scrollViewWillEndDragging:(UIScrollView?*)scrollView?withVelocity:(CGPoint)velocity?targetContentOffset:(inout?CGPoint?*)targetContentOffset?{

//conference?:https://github.com/johnil/VVeboTableViewDemo/blob/master/VVeboTableViewDemo/VVeboTableView.m

//FPS?optimition?part?3-1?:?loadCell?if?needed

NSIndexPath?*indexPath?=?[self.collectionView?indexPathForItemAtPoint:*targetContentOffset];

NSIndexPath?*firstVisibleIndexPath?=?[[self.collectionView?indexPathsForVisibleItems]?firstObject];

//判斷快速滑動(dòng)超過(guò)20個(gè)item后不加載中間的cell

NSInteger?skipCount?=?20;

if(labs(firstVisibleIndexPath.item?-?indexPath.item)?>?skipCount)?{

//處理(1)中無(wú)法跟tableView一樣根據(jù)CGRect取到indexPath

NSIndexPath?*firstIndexPath?=?[self.collectionView?indexPathForItemAtPoint:CGPointMake(0,?targetContentOffset->y)];

NSIndexPath?*lastIndexPath?=?[self.collectionView?indexPathForItemAtPoint:CGPointMake(self.collectionView.frame.size.width?-?10.f,

targetContentOffset->y?+?self.collectionView.frame.size.height?-?10.f)];

//?-?10.f?是為了處理(2)中的point準(zhǔn)確性

NSMutableArray?*arr?=?[NSMutableArraynew];

for(NSUInteger?i?=?firstIndexPath.item;?i?<=?lastIndexPath.item;?i++)?{

[arr?addObject:[NSIndexPath?indexPathForItem:i?inSection:0]];

}

NSUInteger?loadSum?=?6;

if(velocity.y?<?0)?{

//scroll?up

if((lastIndexPath.item?+?loadSum)?<?self.viewModel.numberOfItems)?{

for(NSUInteger?i?=?1;?i??loadSum)?{

for(NSUInteger?i?=?1;?i?x,?targetContentOffset->y);

}

}

-?(void)scrollViewDidEndDecelerating:(UIScrollView?*)scrollView

{

//FPS?optimition?part?3-2?:?loadCell?if?needed?(when?you?touch?and?end?decelerating)

//if?use?collectionView?as?subView?override?-?(UIView?*)hitTest:(CGPoint)point?withEvent:(UIEvent?*)event?instead

if(!CGPointEqualToPoint(self.targetOffset,?CGPointZero)?&&

fabs(self.targetOffset.y?-?scrollView.contentOffset.y)?>?10.f?&&

scrollView.contentOffset.y?>?scrollView.frame.size.height?&&

scrollView.contentOffset.y?<?(scrollView.contentSize.height?-?scrollView.frame.size.height))?{

[self.needLoadArr?removeAllObjects];

self.targetOffset?=?CGPointZero;

[self.collectionView?reloadData];

}else{

[self.needLoadArr?removeAllObjects];

}

}

最后在cell繪制的時(shí)候判斷勒魔,比VVebo多的是還判斷了一步是否在當(dāng)前緩存中。為了讓瀑布流滑動(dòng)體驗(yàn)更好菇曲,在進(jìn)入瀑布流的頁(yè)面冠绢,我將緩存上限提高到70M,按我們一張圖片在200k-900k的大小來(lái)看常潮,可以滿足大部分情況下的需求弟胀。

//FPS?optimition?part?3-3?:?loadCell?if?needed

if(self.needLoadArr.count?>?0?&&

[self.needLoadArr?indexOfObject:indexPath]?==?NSNotFound?&&

//判斷是否在緩存中

![rawPhoto?imageExistInMemoryWithType:type])?{

[cell.imageView?loadingState];

cell.imageView.image?=?nil;

returncell;

}

此時(shí)6p幀率升至55+;

4)這里我也嘗試將collectionView的滑動(dòng)速率降至0.5喊式,以減少cell加載次數(shù)孵户,但效果并不理想;

5)沉浸式體驗(yàn)下垃帅, tabbar的多次出現(xiàn)隱藏對(duì)FPS并無(wú)顯著影響延届;

6)對(duì)scrollView 的contentSize 的 KVO,設(shè)置了底部圖片frame贸诚,對(duì)FPS影響不大,仍然優(yōu)化為到頂部/底部 才改變frame厕吉;

7)scollView的didScroll代理調(diào)用了NSDateFormatter酱固,調(diào)用次數(shù)密集, 根據(jù)以往經(jīng)驗(yàn)头朱,NSDateFormatter在autorelease下往往不能及時(shí)釋放运悲,故加如autoreleasepool 以保證及時(shí)釋放;

進(jìn)入速度優(yōu)化

進(jìn)入瀑布流之時(shí)项钮,所有的cell都會(huì)加載一遍班眯,導(dǎo)致卡頓。起初我以為是collectionViewLayout的某個(gè)方法調(diào)用錯(cuò)了烁巫。后來(lái)經(jīng)過(guò)debug發(fā)現(xiàn)署隘,collectionView的數(shù)據(jù)源傳入的是mutableArr的count,數(shù)據(jù)在變化亚隙,只要deepCopy出來(lái)一份磁餐,就解決了這個(gè)問(wèn)題。

總結(jié)

多人協(xié)作開發(fā)時(shí)阿弃,往往就會(huì)因?yàn)楦鞣N原因?qū)е律厦娴膯?wèn)題出現(xiàn)诊霹,若深入理解相關(guān)知識(shí)的生命周期和一些基礎(chǔ)知識(shí),可以減少上面至少一半的問(wèn)題渣淳。

另外優(yōu)化也是個(gè)持續(xù)的過(guò)程脾还,平時(shí)測(cè)試也很少可以發(fā)現(xiàn),當(dāng)積累到一定量級(jí)之后才會(huì)顯現(xiàn)入愧,也許下次某位同事修復(fù)某個(gè)bug鄙漏,又會(huì)帶出性能問(wèn)題嗤谚,整個(gè)優(yōu)化過(guò)程,其實(shí)是十分有趣的泥张,而且優(yōu)化成功后呵恢,成就感十足,讓我們痛并快樂著吧媚创。


原文來(lái)自cocoachina:http://www.cocoachina.com/ios/20170317/18911.html

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末渗钉,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子钞钙,更是在濱河造成了極大的恐慌鳄橘,老刑警劉巖,帶你破解...
    沈念sama閱讀 212,542評(píng)論 6 493
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件芒炼,死亡現(xiàn)場(chǎng)離奇詭異瘫怜,居然都是意外死亡,警方通過(guò)查閱死者的電腦和手機(jī)本刽,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 90,596評(píng)論 3 385
  • 文/潘曉璐 我一進(jìn)店門鲸湃,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái),“玉大人子寓,你說(shuō)我怎么就攤上這事暗挑。” “怎么了斜友?”我有些...
    開封第一講書人閱讀 158,021評(píng)論 0 348
  • 文/不壞的土叔 我叫張陵炸裆,是天一觀的道長(zhǎng)掏呼。 經(jīng)常有香客問(wèn)我唇牧,道長(zhǎng),這世上最難降的妖魔是什么疹尾? 我笑而不...
    開封第一講書人閱讀 56,682評(píng)論 1 284
  • 正文 為了忘掉前任洛史,我火速辦了婚禮惯殊,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘虹菲。我一直安慰自己靠胜,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 65,792評(píng)論 6 386
  • 文/花漫 我一把揭開白布毕源。 她就那樣靜靜地躺著浪漠,像睡著了一般。 火紅的嫁衣襯著肌膚如雪霎褐。 梳的紋絲不亂的頭發(fā)上址愿,一...
    開封第一講書人閱讀 49,985評(píng)論 1 291
  • 那天,我揣著相機(jī)與錄音冻璃,去河邊找鬼响谓。 笑死损合,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的娘纷。 我是一名探鬼主播嫁审,決...
    沈念sama閱讀 39,107評(píng)論 3 410
  • 文/蒼蘭香墨 我猛地睜開眼,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼赖晶!你這毒婦竟也來(lái)了律适?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 37,845評(píng)論 0 268
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤遏插,失蹤者是張志新(化名)和其女友劉穎捂贿,沒想到半個(gè)月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體胳嘲,經(jīng)...
    沈念sama閱讀 44,299評(píng)論 1 303
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡厂僧,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 36,612評(píng)論 2 327
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了了牛。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片颜屠。...
    茶點(diǎn)故事閱讀 38,747評(píng)論 1 341
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖鹰祸,靈堂內(nèi)的尸體忽然破棺而出汽纤,到底是詐尸還是另有隱情,我是刑警寧澤福荸,帶...
    沈念sama閱讀 34,441評(píng)論 4 333
  • 正文 年R本政府宣布,位于F島的核電站肴掷,受9級(jí)特大地震影響敬锐,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜呆瞻,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 40,072評(píng)論 3 317
  • 文/蒙蒙 一台夺、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧痴脾,春花似錦颤介、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,828評(píng)論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)。三九已至前域,卻和暖如春辕近,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背匿垄。 一陣腳步聲響...
    開封第一講書人閱讀 32,069評(píng)論 1 267
  • 我被黑心中介騙來(lái)泰國(guó)打工移宅, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留归粉,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 46,545評(píng)論 2 362
  • 正文 我出身青樓漏峰,卻偏偏與公主長(zhǎng)得像糠悼,于是被迫代替她去往敵國(guó)和親。 傳聞我的和親對(duì)象是個(gè)殘疾皇子浅乔,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 43,658評(píng)論 2 350

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