Ios 更新UILabel文本时出现问题

Ios 更新UILabel文本时出现问题,ios,swift,uilabel,Ios,Swift,Uilabel,我正在做一个小游戏,更新我创建的UILabel以显示当前分数时遇到了问题。每次我尝试更新分数标签时,整个屏幕都会冻结一秒钟,上一帧中的所有对象都会保留在屏幕上,而下一帧则在其顶部绘制,分数标签不会更新。这个问题只有在我尝试更新UILabel时才会发生,否则一切都会正常运行,不会出现任何问题 我了解到需要在主线程上更新UILabel,并尝试使用Dispatch.main.async进行更新,但问题仍然存在。下面我发布了给我带来问题的代码 fileprivate let scoreLabel: UI

我正在做一个小游戏,更新我创建的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)
}
这让我感到困惑,因为这段代码在Objective-C和Swift版本4以下的版本中工作。你知道我做错了什么吗

这也是Swift版本4.2中的内容

更新:

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

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

  • 不要使用自动布局设置标签,而是使用CGRect手动设置label.frame,并使用label.center和CGPoint设置位置。之后,您应该能够更新您的标签没有问题


  • 希望这能帮助其他可能遇到这个问题的人

    显示链接更新用于自定义绘制视图,而不是更新子视图(它们已经绘制自己);你真的需要你的标签每秒重画60次吗?只需更新文本,系统就会将标签标记为脏标签,并在下次重画时进行更新;您不需要强制计时。如果您确实需要计数器之类的东西,那么可以使用常规计时器,而不是displaylink计时器。

    尝试使用layoutifneed()
    布局需要提前进行部队布局

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

    事实上,我并不是每秒重画60次标签。我遗漏了一大块代码,因为它太多了,无法发布。我发布的代码就是一个小例子。抱歉出现任何错误/混乱。这对我不起作用的原因是因为自动布局。如果使用autolayout,则必须首先停用约束,更新标签,然后重新激活约束并调用layoutifneed()。我用解决方案更新了我的帖子。