You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在UIViewController中实现SKView的update(_ currentTime: CFTimeInterval)等效方法

UIViewController 实现 SKView 风格update回调的最优方案

UIKit 没有内置和 SKView.update(_ currentTime: CFTimeInterval) 对等的原生回调方法,要实现和屏幕刷新率同步的每帧更新逻辑,最优方案是使用 Core Animation 提供的 CADisplayLink,完全可以满足游戏元素持续移动的需求。

核心逻辑说明

SKView 的 update 回调本质是和屏幕渲染周期绑定的每帧触发机制,CADisplayLink 和它的运行逻辑完全一致:每次屏幕刷新前触发回调,默认和设备的屏幕刷新率(60Hz/120Hz ProMotion)完全对齐,精度远高于 NSTimer,不会出现动画卡顿、和渲染不同步的问题。

完整实现步骤

  • 声明必要属性:存储 CADisplayLink 实例和上一帧的时间戳,用来计算帧间隔保证不同设备移动速度一致
class GameViewController: UIViewController {
    // 你需要移动的目标元素示例
    private let gameElement = UIView(frame: CGRect(x: 0, y: 100, width: 50, height: 50))
    
    private var displayLink: CADisplayLink?
    private var lastFrameTimestamp: CFTimeInterval = 0
}
  • 启动更新循环:在页面可见时初始化 CADisplayLink 并加入主运行循环
override func viewDidLoad() {
    super.viewDidLoad()
    view.addSubview(gameElement)
    gameElement.backgroundColor = .red
}

override func viewDidAppear(_ animated: Bool) {
    super.viewDidAppear(animated)
    // 初始化displayLink,绑定update回调
    displayLink = CADisplayLink(target: self, selector: #selector(handleFrameUpdate(_:)))
    // 添加到common模式,避免滚动UIScrollView时更新被暂停
    displayLink?.add(to: .main, forMode: .common)
    // 初始化上一帧时间
    lastFrameTimestamp = CACurrentMediaTime()
}
  • 实现update回调,编写元素移动逻辑
@objc private func handleFrameUpdate(_ sender: CADisplayLink) {
    let currentTime = sender.timestamp
    // 计算两帧之间的时间差
    let deltaTime = currentTime - lastFrameTimestamp
    // 更新上一帧时间
    lastFrameTimestamp = currentTime
    
    // 这里写你的游戏逻辑,和SKView的update用法完全一致
    // 示例:让元素每秒横向移动150pt
    gameElement.frame.origin.x += 150 * deltaTime
    // 超出屏幕后重置位置
    if gameElement.frame.minX > view.bounds.width {
        gameElement.frame.origin.x = -gameElement.frame.width
    }
}
  • 页面不可见时销毁CADisplayLink,避免内存泄漏和不必要的性能消耗
override func viewDidDisappear(_ animated: Bool) {
    super.viewDidDisappear(animated)
    displayLink?.invalidate()
    displayLink = nil
}

注意事项

  • 不要使用 NSTimer 实现该逻辑:NSTimer 的触发精度受主线程任务调度影响很大,容易出现卡顿、跳帧,完全不适合游戏类的高实时性场景
  • 自适应高刷新率:CADisplayLink 会自动跟随设备的ProMotion刷新率触发,你只需要通过deltaTime计算位移,就能保证所有设备上元素移动速度一致
  • 自定义帧率需求:如果需要锁定30/60帧,iOS 15+可以通过displayLink?.preferredFrameRateRange = .init(minimum: 30, maximum: 30)设置,旧iOS版本使用displayLink?.preferredFramesPerSecond = 30即可

内容的提问来源于stack exchange,提问作者SanMu

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.09.25 14:36:11