今天產品經理告訴我:誒,那個誰,這個界面很卡誒!!!你看看什麼狀況。。。因而我掏出了Instrument裏的Core Animation看看FPS,發現滑動的時候FPS特別低Orz!html
首先,查閱資料看下爲何會產生卡頓的緣由。 ios
全部的 Bitmap,包括圖片、文本、柵格化的內容,最終都要由內存提交到顯存,綁定爲 GPU Texture。不管是提交到顯存的過程,仍是 GPU 調整和渲染 Texture 的過程,都要消耗很多 GPU 資源。當在較短期顯示大量圖片時(好比 TableView 存在很是多的圖片而且快速滑動時),CPU 佔用率很低,GPU 佔用很是高,界面仍然會掉幀。避免這種狀況的方法只能是儘可能減小在短期內大量圖片的顯示,儘量將多張圖片合成爲一張進行顯示。 另外當圖片過大,超過 GPU 的最大紋理尺寸時,圖片須要先由 CPU 進行預處理,這對 CPU 和 GPU 都會帶來額外的資源消耗。算法
當多個視圖(或者說 CALayer)重疊在一塊兒顯示時,GPU 會首先把他們混合到一塊兒。若是視圖結構過於複雜,混合的過程也會消耗不少 GPU 資源。爲了減輕這種狀況的 GPU 消耗,應用應當儘可能減小視圖數量和層次,而且減小沒必要要的透明視圖。佈局
離屏渲染是指圖層在被顯示以前是在當前屏幕緩衝區之外開闢的一個緩衝區進行渲染操做。 離屏渲染須要屢次切換上下文環境:先是從當前屏幕(On-Screen)切換到離屏(Off-Screen);等到離屏渲染結束之後,將離屏緩衝區的渲染結果顯示到屏幕上又須要將上下文環境從離屏切換到當前屏幕,而上下文環境的切換是一項高開銷的動做。 會形成 offscreen rendering 的緣由有: 陰影(UIView.layer.shadowOffset/shadowRadius/…) 圓角(當 UIView.layer.cornerRadius 和 UIView.layer.maskToBounds 一塊兒使用時) 圖層蒙板 開啓光柵化(shouldRasterize = true)性能
因此咱們找到了緣由,因爲咱們的項目是基於地圖的,在地圖上直接添加頁面上去,以前地圖就有不少圓角設置,加上cell上的圓角,會形成GPU性能的損耗,因此相對來講頁面的滑動會損耗GPU啦。 因而回到了老生常談的問題了,關於圓角的優化。 以前看文章有說這樣去優化:優化
+ (void)cutRadiousWithView:(UIView *)view radious:(CGFloat)radious {
UIBezierPath *maskPath = [UIBezierPath bezierPathWithRoundedRect:view.bounds byRoundingCorners:UIRectCornerAllCorners cornerRadii:CGSizeMake(radious, radious)];
CAShapeLayer *maskLayer = [[CAShapeLayer alloc]init];
//設置大小
maskLayer.frame = view.bounds;
//設置圖形樣子
maskLayer.path = maskPath.CGPath;
view.layer.mask = maskLayer;
}
複製代碼
然而發現並無什麼用,其實mask遮罩仍是會發生離屏渲染的。並且親測這樣的FPS貌似更低???(黑人問號臉)spa
因而我繼續查資料,發現圖片的圓角能夠將圖片進行進行重繪,獲得一張新的圖片。方法以下:3d
+ (UIImage *)cutCircleImageWithImage:(UIImage *)image size:(CGSize)size radious:(CGFloat)radious {
UIGraphicsBeginImageContextWithOptions(size, NO, [UIScreen mainScreen].scale);
CGRect rect = CGRectMake(0, 0, size.width, size.height);
CGContextAddPath(UIGraphicsGetCurrentContext(),
[UIBezierPath bezierPathWithRoundedRect:rect cornerRadius:radious].CGPath);
CGContextClip(UIGraphicsGetCurrentContext());
[image drawInRect:rect];
UIImage *newImage = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
return newImage;
}
複製代碼
用這個方法能夠獲得新的圖片,對於圖片的圓角處理能夠這樣作,可是對於View的呢?code
View的話能夠給他蓋一層ImageView,設置下Imageview的圖片,方法以下:orm
+ (void)cutCicleViewWithView:(UIView *)view radious:(CGFloat)radius {
CGSize size = view.frame.size;
CGRect rect = CGRectMake(0, 0, size.width, size.height);
UIColor *bkColor = view.backgroundColor;
UIImage *image = [[UIImage alloc] init];
UIGraphicsBeginImageContextWithOptions(size, NO, UIScreen.mainScreen.scale);
CGContextRef context = UIGraphicsGetCurrentContext();
CGContextSetFillColorWithColor(context, bkColor.CGColor);
CGContextAddPath(context,
[UIBezierPath bezierPathWithRoundedRect:rect cornerRadius:radius].CGPath);
CGContextDrawPath(context, kCGPathFill);
[image drawInRect:rect];
UIImage *output = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
UIImageView *imageView = [[UIImageView alloc] initWithFrame:rect];
imageView.image = output;
[view insertSubview:imageView atIndex:0];
view.backgroundColor = [UIColor clearColor];
}
複製代碼
相信學過算法的同窗都知道,越快的算法,可能空間複雜度越高。當你爲了某一性能去優化,必然會損耗其餘的性能,所謂的算法優化是爲了達到最佳實現效果。因此這樣優化GPU的結果就是會損耗CPU。 過早的優化是魔鬼,可是到問題出來的時候 ,有些東西就有必要去作了!
參考資料:
http://www.reviewcode.cn/article.html?reviewId=7 http://ios.jobbole.com/92237/