Welcome to OStack Knowledge Sharing Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
253 views
in Technique[技术] by (71.8m points)

swift - How to pass data between view controllers - not working

Im trying to pass an player score from VC1 to a view that displays the current scores of all players(4). the display view is on a separate view controller than where the player(s) score is defined and stored.

I have done the prepare(segue) and im able to pass other variables to the display VC(ThirdViewController). but when I try to assign the player score to the uilabel.text It tells me that I have unwrapped a nil value

I have even tried to just set the label text to a static string and still get the nil error.

class ViewController: UIViewController {

var name = String()

var player1Score = 1
var player2Score = 2
var player3Score = 3
var player4Score = 4

//MARK: ********* IBOutlets **********
@IBOutlet weak var playerSegmentOutlet: UISegmentedControl!
@IBOutlet weak var diceSegmentOutlet: UISegmentedControl!
@IBOutlet weak var targetScoreSliderOutlet: UISlider!
@IBOutlet weak var matchTargetSwitchOutlet: UISwitch!
@IBOutlet weak var targetScoreLabel: UILabel!


override func viewDidLoad() {
    super.viewDidLoad()

}


override func prepare(for segue: UIStoryboardSegue, sender: Any?) {

    if let VC = segue.destination as? SecondViewController {

        VC.player1CurrentScore = player1Score
        VC.player2CurrentScore = player2Score
        VC.player3CurrentScore = player3Score
        VC.player4CurrentScore = player4Score
    }
}

Second view Controller

class SecondViewController: UIViewController {

@IBOutlet weak var CurrentRoundScoreLabel: UILabel!

@IBOutlet weak var CurrentPlayerScoreLabel: UILabel!

var player1CurrentScore = 1
var player2CurrentScore = 1
var player3CurrentScore = 1
var player4CurrentScore = 1


override func viewDidLoad() {
    super.viewDidLoad()

}

override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
    if let VC = segue.destination as? ThirdViewController {

        VC.player1ScoreLabel.text = String(player1CurrentScore)
        VC.player2ScoreLabel.text = String(player2CurrentScore)
        VC.player3ScoreLabel.text = String(player3CurrentScore)
        VC.player4ScoreLabel.text = String(player4CurrentScore)

    }
}

Third View Controller

class ThirdViewController: UIViewController {

@IBOutlet var player1ScoreLabel: UILabel!
@IBOutlet var player2ScoreLabel: UILabel!
@IBOutlet var player3ScoreLabel: UILabel!
@IBOutlet var player4ScoreLabel: UILabel!

override func viewDidLoad() {
    super.viewDidLoad()
}

}

no matter what I try to do with with UILabel.text it shows up as nil

I'm totally frustrated and I'm sure I am missing something simple because of my frustration, please someone help me.

See Question&Answers more detail:os

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Answer

0 votes
by (71.8m points)

This is an inefficient way to do this as you are passing data through 3 different objects. However, going on with this methodology, the problem is the label's are not created yet inside

override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
    if let VC = segue.destination as? ThirdViewController {

        VC.player1ScoreLabel.text = String(player1CurrentScore)
        VC.player2ScoreLabel.text = String(player2CurrentScore)
        VC.player3ScoreLabel.text = String(player3CurrentScore)
        VC.player4ScoreLabel.text = String(player4CurrentScore)

    }
}

See, the label isn't created yet. So, you are setting text on aUILabel that isn't initialized. Therefore, you need to create variables for the labels inside ThirdViewController.

Third View Controller

class ThirdViewController: UIViewController {

    @IBOutlet var player1ScoreLabel: UILabel!
    @IBOutlet var player2ScoreLabel: UILabel!
    @IBOutlet var player3ScoreLabel: UILabel!
    @IBOutlet var player4ScoreLabel: UILabel!

    var score0:Int!
    var score1:Int!
    var score2:Int!
    var score3:Int!

    override func viewDidLoad() {
        super.viewDidLoad()
        self.player1ScoreLabel.text = String(score0)
        self.player2ScoreLabel.text = String(score1)
        self.player3ScoreLabel.text = String(score2)
        self.player4ScoreLabel.text = String(score3)
    }
}

and change the segue in SecondViewController

override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
    if let VC = segue.destination as? ThirdViewController {

        VC.score0 = player1CurrentScore
        VC.score1 = player2CurrentScore
        VC.score2 = player3CurrentScore
        VC.score3 = player4CurrentScore

    }
}

Another Way:

Let's create a singleton called Game. Within this (assuming you only have 4 players) we can create 4 players that will never change. This allows us to create instances of players in one location and call upon them as necessary.

NOTE: A singleton can be misused EASILY.

https://cocoacasts.com/what-is-a-singleton-and-how-to-create-one-in-swift https://cocoacasts.com/are-singletons-bad/

class Game {

    static var score0:Int = 0
    static var score1:Int = 0
    static var score2:Int = 0
    static var score2:Int = 0

}        

Then, anywhere in your code you can access Game.score0, Game.score1.

CAUTION:

I would caution you to very carefully use singletons. You don't want everything with public access. You need to determine if this is good for you or not. Cheers.


与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome to OStack Knowledge Sharing Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...