1 复用Cell(dequeueReusableCellWithIdentifier:);
2 异步解码图片、离屏渲染(如使用CATiledLayer);
3减少AutoLayout计算,预计算Cell高度;
4 使用willDisplayCell延迟加载非关键资源
异步解码图片、离屏渲染(如使用CATiledLayer)这两个之前没有开发过,今天写一个demo记录一下
swift
/*
异步解码图片,避免单元格卡顿
当你用 UIImage(named:) 或 UIImage(data:) 加载图片时,系统会延迟解码(lazy decode):
• 图片只在真正显示到屏幕上时才会解码。
• 解码操作发生在主线程上 → 容易造成 UI 卡顿(掉帧)。
*/
class DecodeImages {
//可以结合 DispatchSemaphore 控制并发,避免同时解码过多大图导致内存暴涨
//信号量限制最大解码数量为2
let semaphore = DispatchSemaphore(value: 2)
let queue = DispatchQueue(label: "www.baidksk.com",attributes: DispatchQueue.Attributes.concurrent)
func asyncDecodeImage(_ data: Data, complete: @escaping (UIImage?)->Void) {
semaphore.wait()
defer {semaphore.signal()}
guard let imageSource = CGImageSourceCreateWithData(data as CFData, nil),
let cgImage = CGImageSourceCreateImageAtIndex(imageSource, 0, nil) else {
DispatchQueue.main.async {
complete(nil)
}
return
}
let decodedImage = UIImage(cgImage: cgImage,scale: UIScreen.main.scale,orientation: .up)
DispatchQueue.main.async {
complete(decodedImage)
}
}
}
/*
当一张超大图(如地图、PDF、超高清图)显示在 UIScrollView 或 CALayer 上时,
如果一次性全部解码、渲染,会非常消耗内存。
解决思路
使用 CATiledLayer 分块(tile)绘制:
系统只绘制当前可见区域的部分图块,每块独立解码与渲染。
• CATiledLayer 自动多线程渲染;
• 每个 tile 的渲染在后台进行;
• iOS 系统内部使用 GCD 调度线程;
• 你可以通过 DispatchSemaphore 控制最大渲染任务数量,以防 GPU/CPU 占用过高。
*/
class OutScreenRenderView : UIView {
private let image: CGImage
override class var layerClass: AnyClass {
CATiledLayer.self
}
init(image: CGImage) {
self.image = image
super.init(frame: .zero)
let titleLayer = self.layer as! CATiledLayer
titleLayer.levelsOfDetail = 4
titleLayer.tileSize = CGSize(width: 256, height: 256)
contentScaleFactor = 1.0
}
required init?(coder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
override func draw(_ layer: CALayer, in ctx: CGContext) {
let rect = ctx.boundingBoxOfClipPath
let scale = layer.contentsScale
let imageRect = CGRect(x: 0, y: 0, width: CGFloat(image.width), height: CGFloat(image.height))
ctx.saveGState()
ctx.translateBy(x: 0, y: imageRect.size.height)
ctx.draw(image, in: rect)
ctx.restoreGState()
}
}