简体   繁体   中英

Changing UILabel's text only works inside viewDidLoad()

I'm trying to make a function that I can call on to update my UILabel's scoreLabel.text . However, I get an error whenever I try to change it. What's confusing to me is that I don't receive an error when changing it inside viewDidLoad() . Everywhere else returns the following error:

图片链接

In the console I also get error:

fatal error: unexpectedly found nil while unwrapping an Optional value.

So what I've been lead to believe is that when calling my function to update the text, the view hasn't loaded the UILabel yet. But I'm certain that this function is called only once the view has loaded.

Things I've checked/tried for:

  • That my IBOutlet is properly connected
  • That my function is being called
  • Using both scoreLabel.text and self.scoreLabel.text
  • Using a Strong and Weak outlet connection

I am also positive that changeTextLabel is being called after scoreLabel is loaded into memory. But again my error seems to say otherwise.

Here's a complete markup of my code. I've removed some irrelevant details for readability:

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
    }
}
}

Thanks for your time

Edit: GameScene.swift

This is only the part that should be of concern

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()
}

The problem is with this line,

 let game = GameViewController()
 game.changeTextLabel()

You should create GameViewController object using XIB or Storyboard.

In your case it is just creating object using .swift file, formally class. You should create your object using View which is having IBOutlet connection with scoreLabel .

Try (If using Storyboard ),

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

or (If using XIB )

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

Update you changeTextLabel with following ( 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
    }
}

I dont fully know your project setup but your approach seems complicated, its not what you should do in SpriteKit games. So I dont think its a good idea to tell you how to fix your current problem.

You should create your UI, such as labels, buttons etc using SpriteKit APIs (SKLabelNodes, SKSpriteNodes, SKNodes etc) directly in the relevant SKScene(s).

Your GameViewController should only really handle presenting SKScenes. so there should be next to no code there apart from loading the 1st SKScene.

If you have multiple SKScenes (MenuScene, ShopScene, SettingScene etc) your approach will fall apart because the score label will show in all SKScenes. GameViewController presents all your SKScenes, so whats added to GameViewController shows in all SKscenes. That means you have to remove/add labels and other UI for each scene and it will be chaos.

So to create a score label you should do this directly in the relevant scene. I like to use the lazy var approach to keep the setup code for the label in the same spot.

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)
      }
} 

Than you can update it like this directly in the collision code you have.

scoreLabel.text = "NewText"

Now when you change from 1 SKScene to another SKScene you dont have to worry about removing this label, SpriteKit will do it for you.

You could also use xCodes level editor to add this label visually, similar to storyboards. This brings me to my final suggestion, which is that storyboards are not really used in SpriteKit games. Storyboards are for ViewControllers and in SpriteKit you are working with SKScenes.

Hope this helps

It happens because you are not getting memory of label in any other function.It happens because of so many reasons.

One reason could be @IBOutlet weak var scoreLabel: UILabel! Try to create a strong variable outlet.

@IBOutlet strong var scoreLabel: UILabel!

Second reason could be that you are calling changeTextLabel before the label gets memory. So call it later.

Replace this line

self.scoreLabel.text = "yay"

With

self.scoreLabel?.text = "yay"

Make these changes and try again:

   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()
}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM