【问题标题】:Changing UILabel's text only works inside viewDidLoad()更改 UILabel 文本仅适用于 viewDidLoad()
【发布时间】:2017-03-21 15:38:55
【问题描述】:

我正在尝试创建一个可以调用的函数来更新我的 UILabel 的scoreLabel.text。但是,每当我尝试更改它时都会出现错误。令我困惑的是,在viewDidLoad() 中更改它时没有收到错误消息。其他任何地方都返回以下错误:

在控制台中我也收到错误:

致命错误:在展开 Optional 值时意外发现 nil。

所以我一直相信,当调用我的函数来更新文本时,视图还没有加载 UILabel。但我确定只有在视图加载后才会调用此函数。

我检查过/尝试过的事情:

  • 我的 IBOutlet 已正确连接
  • 我的函数正在被调用
  • 同时使用scoreLabel.textself.scoreLabel.text
  • 使用强和弱插座连接

我也很肯定 changeTextLabelscoreLabel 加载到内存后被调用。但是我的错误似乎又说明了其他问题。

这是我的代码的完整标记。为了便于阅读,我删除了一些不相关的细节:

import UIKit
import SpriteKit

class GameViewController: UIViewController {



@IBOutlet weak var scoreLabel: UILabel!

override func viewDidLoad() {
    super.viewDidLoad()
    //This is where all my other code was
    print(scoreLabel.text)
    scoreLabel.text = "Testing" //This line can be run
}

func changeTextLabel() {
    print("changeTextLabel called")
    if self.scoreLabel != nil {
        self.scoreLabel.text = "yay"
    } else {
        print("scoreLabel is nil") //This is called every time
    }
}
}

感谢您的宝贵时间

编辑:GameScene.swift

这只是应该关注的部分

func projectileDidCollideWithMonster(projectile: SKSpriteNode, monster: SKSpriteNode) {
    print("Hit")
    let storyBoard = UIStoryboard(name: "Main", bundle: nil)
    let object = storyBoard.instantiateViewController(withIdentifier: "GameViewController") as! GameViewController

    object.changeTextLabel()
    projectile.removeFromParent()
    monster.removeFromParent()
}

【问题讨论】:

  • 您是否尝试打印self.scoreLabel 以检查其是否为零?
  • 你在哪里从其他控制器调用changeTextLabel 方法?
  • 检查断点是先调用 viewdidload 还是先调用 changetextlabel。
  • 是否有必要在你的func中的变量上调用self
  • @Tj3n 是的,从changeLabelText() 调用时值为nil,但从viewDidLoad() 调用时值为Testing 并且是普通字符串

标签: ios swift sprite-kit uikit uilabel


【解决方案1】:

我不完全了解您的项目设置,但您的方法似乎很复杂,这不是您在 SpriteKit 游戏中应该做的。所以我不认为告诉你如何解决你当前的问题是个好主意。

您应该直接在相关的 SKScene 中使用 SpriteKit API(SKLabelNodes、SKSpriteNodes、SKNodes 等)创建您的 UI,例如标签、按钮等。

您的 GameViewController 应该只真正处理呈现 SKScene。所以除了加载第一个 SKScene 之外,应该几乎没有代码。

如果您有多个 SKScene(MenuScene、ShopScene、SettingScene 等),您的方法将失败,因为分数标签将显示在所有 SKScene 中。 GameViewController 呈现您所有的 SKScene,因此添加到 GameViewController 的内容会显示在所有 SKscene 中。这意味着您必须为每个场景删除/添加标签和其他 UI,这将是混乱的。

因此,要创建乐谱标签,您应该直接在相关场景中执行此操作。我喜欢使用惰性 var 方法将标签的设置代码保持在同一位置。

class GameScene: SKScene {

      lazy var scoreLabel: SKLabelNode = {
          let label = SKLabelNode(fontNamed: "HelveticaNeue")
          label.text = "SomeText"
          label.fontSize = 22
          label.fontColor = .yellow
          label.position = CGPoint(x: self.frame.midX, y: self.frame.midY)
          return label
      }()

      override func didMove(to view: SKView) {

          addChild(scoreLabel)
      }
} 

你可以像这样直接在你拥有的碰撞代码中更新它。

scoreLabel.text = "NewText"

现在,当您从 1 个 SKScene 更改为另一个 SKScene 时,您不必担心删除此标签,SpriteKit 会为您完成。

您还可以使用 xCodes 级别编辑器以可视方式添加此标签,类似于故事板。这让我想到了我的最后一个建议,那就是在 SpriteKit 游戏中并没有真正使用故事板。 Storyboards 用于 ViewControllers,而在 SpriteKit 中,您正在使用 SKScenes。

希望对你有帮助

【讨论】:

    【解决方案2】:

    问题出在这一行,

     let game = GameViewController()
     game.changeTextLabel()
    

    您应该使用 XIB 或 Storyboard 创建 GameViewController 对象。

    在您的情况下,它只是使用 .swift 文件创建对象,正式的类。 您应该使用与 scoreLabel 有 IBOutlet 连接的 View 创建您的对象。

    尝试(如果使用故事板),

    let storyboard = UIStoryboard(name: "YourStoryBoard", bundle: nil)
    let gameVC = storyboard.instantiateViewController(withIdentifier: "GameViewController") as! UIViewController
    

    或(如果使用XIB

    var gameVC = GameViewController(nibName: "GameViewController", bundle: nil)
    

    更新您的changeTextLabel 关注 (Ref),

    func changeTextLabel() {
        print(self.view)
        print("changeTextLabel called")
        if self.scoreLabel != nil {
            self.scoreLabel.text = "yay"
        } else {
            print("scoreLabel is nil") //This is called every time
        }
    }
    

    【讨论】:

    • 更新了我的 GameScene 以现在使用它,知道我做错了非常有帮助!但是,它并没有解决我的错误。而 scoreLabel.text 仍然 = nil
    • @Mathperson 请更新您的问题,您做了哪些更改,这样我可以更仔细地查看我们是否走在正确的轨道上。
    【解决方案3】:

    发生这种情况是因为您没有在任何其他函数中获得标签的记忆。发生这种情况的原因有很多。

    一个原因可能是@IBOutlet weak var scoreLabel: UILabel! 尝试创建一个强大的变量出口。

    @IBOutlet strong var scoreLabel: UILabel!
    

    第二个原因可能是您在标签获取内存之前调用了 changeTextLabel。所以稍后再调用。

    【讨论】:

    • 我已经尝试过使用强变量和弱变量出口,并且在标签初始化到内存后肯定会调用 changeTextLabel。感谢您的帮助!
    • 它应该也适合你。它对我有用。
    • 再添加一个断点并检查 label 是否为 nil 然后执行 self.scoreLabel?.text = "yay"
    【解决方案4】:

    进行这些更改并重试:

       func changeTextLabel() {
            print("changeTextLabel called")
            if self.scoreLabel != nil {
               self.scoreLabel.text = "yay"
            }
    
       }
    
    
    func projectileDidCollideWithMonster(projectile: SKSpriteNode, monster: SKSpriteNode) {
        print("Hit")
        let game =  STORYBOARD.instantiateViewControllerWithIdentifier("STORYBOARD_IDENTIFIER") as! GameViewController
        game.changeTextLabel()
        projectile.removeFromParent()
        monster.removeFromParent()
    }
    

    【讨论】:

    • 更新了我的 GameScene 以现在使用它,知道我做错了非常有帮助!但是,它并没有解决我的错误。而 scoreLabel.text 仍然 = nil
    • 标签没有进入内存,除非视图被加载,你需要在使用标签之前加载视图。在这种情况下,您创建了 Game View Controller 的实例,但它的视图尚未加载,即标签仍为 nil。如果您提供可以解决您的问题的 viewcontroller 或 pushviewcontroller。
    • 您能否详细说明“呈现”视图控制器的含义?
    • 你可以发布你使用 projectileDidCollideWithMonster 委托的课程吗?
    【解决方案5】:

    替换这一行

    self.scoreLabel.text = "yay"
    

    self.scoreLabel?.text = "yay"
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2012-04-03
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2013-05-17
      相关资源
      最近更新 更多