首页 > 解决方案 > 更新 UILabel 文本时出现问题

问题描述

我正在制作一个小游戏,但无法更新我创建的 UILabel 以显示当前分数。每次我尝试更新乐谱标签时,整个屏幕都会冻结一瞬间,前一帧中的所有对象都保留在屏幕上,而下一帧则绘制在屏幕上,而乐谱标签不会更新。仅当我尝试更新 UILabel 时才会出现此问题,否则一切运行正常而不会出现任何问题。

我读到更新 UILabel 需要在主线程上完成,并尝试使用 Dispatch.main.async 这样做,但问题仍然存在。下面我发布了导致我出现问题的代码。

fileprivate let scoreLabel: UILabel = {
  let newLabel = UILabel()
  newLabel.textAlignment = .center
  newLabel.textColor = .white
  newLabel.text = "0"
  newLabel.translatesAutoresizingMaskIntoConstraints = false
  return newLabel
}()

var score: Int = 0

fileprivate lazy var displayLink: CADisplayLink = {
  let newLink = CADisplayLink(target: self, selector: #selector(update))
  return newLink
}()

@objc func update() {
  score += 1

  //Method 1: cause screen split second screen lockup
  scoreLabel.text = "\(score)" //doesn't work

  //Method 2: cause screen split second screen lockup
  DispatchQueue.main.async {
    self.scoreLabel.text = "\(score)" //also doesn't work
    self.scoreLabel.setNeedsDisplay()
  }
}

func setupLayout() {
   view.addSubview(scoreLabel)

   NSLayoutConstraint.activate([
     scoreLabel.centerYAnchor.constraint(equalTo: view.centerYAnchor),
     scoreLabel.centerXAnchor.contraint(equalTo: view.centerXAnchor)
     ])
}

override func viewDidLoad() {
   super.viewDidLoad()

   setupLayout()

   displayLink.add(to: .main, forMode: .default)
}

这让我感到困惑,因为这段代码在版本 4 以下的 Objective-C 和 Swift 中工作。关于我做错了什么有什么想法吗?

这也在 Swift 4.2 版上

更新:

所以我找到了解决方案。显然自动布局是导致问题的原因。为了解决这个问题,我找到了两种方法:

  1. 在 DispatchQueue.main.async 中,首先停用您的布局约束。然后更新您的标签并重新激活您的布局约束并调用 layoutIfNeeded()。

  2. 而不是使用自动布局设置您的标签,而是使用 CGRect 手动设置 label.frame,使用 label.center 和 CGPoint 设置位置。之后,您应该可以毫无问题地更新您的标签。

希望这可以帮助其他可能遇到此问题的人。

标签: iosswiftuilabel

解决方案


尝试 layoutIfNeeded()
layoutIfNeeded 尽早强制布局

Dispatch.main.async {
  self.scoreLabel.text = "\(score)" //also doesn't work
  self.scoreLabel.layoutIfNeeded()
}

推荐阅读