CAMetalLayer.nextDrawable()应该不是一个非常耗时的方法,但有时候它往往会花费很多时间,甚至超过8ms
1.复制下面的代码
1.遵循viewDidLoad
中的注解指南
1.参见日志打印
class TestVC: UIViewController {
let metalLayer:CAMetalLayer = CAMetalLayer()
var displayLink:CADisplayLink!
var thread:Thread!
var animationView:AnimationView!
override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) {
self.displayLink.isPaused = true
}
override func touchesEnded(_ touches: Set<UITouch>, with event: UIEvent?) {
self.displayLink.isPaused = false
}
override func viewDidLayoutSubviews() {
super.viewDidLayoutSubviews()
print("ahhhaa")
}
override func viewDidLoad() {
super.viewDidLoad()
self.view.backgroundColor = .red
let scale = UIScreen.main.scale
metalLayer.frame = self.view.bounds
metalLayer.drawableSize = CGSize(width: self.view.frame.width * scale, height: self.view.frame.height * scale)
self.view.layer.addSublayer(metalLayer)
self.addDisplayLinkInUITaskRunner()
// Wait screen loading complete,and next,You can:
// 1. Swipe down the control center, you will see a lot log print in console, and it will
// constantly exists.
// 2. Move the app to bg, and then move to fg, you will see a lot of log,
// it also will constantly exist for a long time.
// 3. Just don't do anything, you might see it the log print constantly....
// And when you tap the screen, it may disappear, and After a while, you may see log again....
}
func addDisplayLinkInUITaskRunner() {
self.thread = Thread(block: {
RunLoop.current.add(NSMachPort(), forMode: .common)
RunLoop.current.run()
})
self.thread.name = ""
self.thread.start()
self.perform(#selector(addDisplayLink), on: thread, with: nil, waitUntilDone: false)
}
@objc func addDisplayLink() {
self.displayLink = CADisplayLink(target: self, selector: #selector(onDisplayLink))
if #available(iOS 15.0, *) {
self.displayLink.preferredFrameRateRange = .init(minimum: 60, maximum: 120, preferred: 120)
} else {
self.displayLink.preferredFramesPerSecond = 120
}
self.displayLink.add(to: .current, forMode: .common)
}
@objc private func onDisplayLink() {
let startTime = CACurrentMediaTime()
let frameDrawable = metalLayer.nextDrawable()!
let timeUsed = CACurrentMediaTime() - startTime
// If time used to get next drawble over 3ms,
// we print it here to indicate this method take much time!
if (timeUsed > 0.005) {
print("CAMetalLayer.nextDrawable take much time!! -> \(String(format: "%.2f", timeUsed * 1000)) ms")
}
frameDrawable.present()
}
}
1条答案
按热度按时间83qze16e1#
如果
displaySyncEnabled
设置为true
(默认值),它将等待下一个vsync来显示可绘制对象,这意味着你可能很快就用完可绘制对象,因此nextDrawable
将等待直到有一个可用(或最多1秒)。换句话说,由于您已经有可绘制对象排队等待显示,因此在一个可绘制对象真正可用之前,您无法获得另一个可绘制对象。
如果您确实希望尽快显示它们-将
displaySyncEabled
设置为false
。然而,当前行为可能正是您所希望的,因为您很少从显示帧的速度快于显示器的刷新率中获得任何好处。