UITableView性能优化
总结一些UITableView性能优化方案:
预排版
根据JSON数据后台线程进行渲染排版得到包含文本宽高、子视图高度和cell高度的CellLayout对象。CellLayout对象占用内存小,可缓存,TableView 在请求各个cell高度时,不会消耗任何多余计算量。
预渲染
图片圆角使用maskToBounds和cornerRadius属性会造成GPU离屏渲染,性能较差。使用CoreGraphic后台渲染圆角图片, 主要原理是使用CGContext绘制图片,然后添加圆角Path, 使用clip进行剪切。值得注意的是,渲染后的图片也要缓存到图片缓存中,以避免多次渲染。
// UIView渲染 func xy_drawRectWithRoundedCorner(size: CGSize, radius: CGFloat, borderWidth: CGFloat, backgroundColor: UIColor, borderColor: UIColor) -> UIImage? { var image: UIImage? = nil let width = size.width let height = size.height let offSetY = height/2 let offSetX = width/2 UIGraphicsBeginImageContextWithOptions(size, false, UIScreen.main.scale) guard let context = UIGraphicsGetCurrentContext() else { return image } context.setStrokeColor(borderColor.cgColor) context.setLineWidth(borderWidth) context.setFillColor(backgroundColor.cgColor) context.addArc(center: CGPoint(x: offSetX, y: offSetY), radius: radius-borderWidth, startAngle: 0, endAngle: CGFloat(2*Double.pi), clockwise: true) context.drawPath(using: .fillStroke) image = UIGraphicsGetImageFromCurrentImageContext() UIGraphicsEndImageContext() return image } // UIImage后台渲染圆角 extension UIImage { func xy_drawRectWithRoundedCorner(radius: CGFloat, sizetoFit: CGSize, finished: @escaping (UIImage?) -> Void) { DispatchQueue.global().async { var image: UIImage? = nil UIGraphicsBeginImageContextWithOptions(sizetoFit, false, UIScreen.main.scale) guard let context = UIGraphicsGetCurrentContext() else { DispatchQueue.main.async { finished(nil) } return } let rect = CGRect(origin: .zero, size: sizetoFit) context.addPath(UIBezierPath(roundedRect: rect, byRoundingCorners: UIRectCorner.allCorners, cornerRadii: CGSize(width: radius, height: radius)).cgPath) context.clip() self.draw(in: rect) context.drawPath(using: .fillStroke) image = UIGraphicsGetImageFromCurrentImageContext() UIGraphicsEndImageContext() DispatchQueue.main.async { finished(image) } } } }
异步绘制
详情参考 YYAsyncLayer原理。YYAsyncLayer异步绘制的过程大致如下:
- (void)display { dispatch_async(backgroundQueue, ^{ CGContextRef ctx = CGBitmapContextCreate(...); // draw in context... CGImageRef img = CGBitmapContextCreateImage(ctx); CFRelease(ctx); dispatch_async(mainQueue, ^{ layer.contents = img; }); }); }
减少Cell视图层级
视图层级较多时,GPU图层混合阶段会更耗时,会造成卡顿。
视图不透明translucent = true
视图设置半透明时,GPU图层混合、纹理渲染阶段会更耗时,会造成卡顿。
图片异步解码
CPU工作流程的准备阶段,默认主线程解码图片,比较消耗资源。
禁用离屏渲染
cornerRadius和maskToBounds同时使用可导致离屏渲染(采用预渲染可消除)
设置shadow相关属性可导致离屏渲染(设置shadowPath可消除)
设置layer的mask属性可导致离屏渲染
设置可光栅化shouldRasterize = true也可导致离屏渲染