问题
I've implemented a protocol to get some sort of message, that a game has already finished and passes the time to my controller (Game wrote in SpriteKit). But now I'm having this fatal error after finishing the game and executing the gameEnded method and the app just crashes. Does anyone know why?
Here is my code
GameViewController
class AcceleratorGameController: UIViewController {
var time: Float = 0.0
var challengeController: ChallengeViewController!
weak var delegate : GameEnded?
override func viewDidLoad() {
super.viewDidLoad()
if let scene = AcceleratorGame.unarchiveFromFile("AcceleratorGame") as? AcceleratorGame {
let skView = self.view as! SKView
skView.showsFPS = true
scene.viewController = self
skView.ignoresSiblingOrder = true
scene.scaleMode = .AspectFill
skView.presentScene(scene)
}
}
override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) {
var dest : ChallengeViewController = segue.destinationViewController as! ChallengeViewController
dest.gameHasFinished(time) //Dont know if this does anything...
println("Segue now!")
}
override func viewWillDisappear(animated: Bool) {
super.viewWillDisappear(true)
println("View will disapear")
delegate.gameHasFinished(self.time) // ###CRASHES HERE!###
}
Here is my other ViewController
protocol GameEnded : class {
func gameHasFinished(time: Float)
}
class ChallengeViewController : UIViewController, GameEnded {
var time : Float = 0.0
var acceleratorGameController : AcceleratorGameController!
override func viewDidLoad() {
super.viewDidLoad()
println("ChallengeViewController geladen")
startGame()
}
override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) {
if segue.identifier == "accelGame" {
acceleratorGameController = segue.destinationViewController as! AcceleratorGameController
acceleratorGameController.delegate = self
}
}
func startGame () {
println("Start Game")
self.showAccelGameView()
}
func gameHasFinished(time: Float) {
println("Game has finished")
self.time = time
}
func showAccelGameView() {
println("Show Accel Game")
let storyboard = UIStoryboard(name: "Main", bundle: nil)
let vc = storyboard.instantiateViewControllerWithIdentifier("AcceleratorGameController") as! AcceleratorGameController
self.navigationController?.pushViewController(vc, animated: true)
}
EDIT: I did all the things that you told me to, and it still crashes at the same point. Xcode told me to use a delegate. When I do delegate? It works, but that's not what I want. That function has to be called!
func gameOver(time: Float) {
println("Game Over")
self.time = time
//delegate!.gameHasFinished(time) still crashes here. added !. i commented it to test the prepareForSegue method
}
override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) {
var dest : ChallengeViewController = segue.destinationViewController as! ChallengeViewController
dest.gameHasFinished(time)
println("Segue now!") // Wont happen
self.navigationController?.popViewControllerAnimated(true) //Wont happen either. If i call this in gameOver() it works.
}
I've put in some println()
in the prepareForSegue()
methods, but somehow they won't get executed. Do I have to call them somehow? Here is a screenshot of my segue.
http://i.stack.imgur.com/oK4Ce.png
I also tried putting in one segue the other way round, but it doesn't help either.
http://i.stack.imgur.com/TVmdP.png (no identifier because it's the only segue.)
I forgot to say that the SpriteKit Game behind this AcceleratorGameController
calls the gameOver()
method when it has finished.
回答1:
I don't see how ChallengeViewController
will initialize the delegate of AccelerometerGameController
.
In your prepareForSegue
, you are setting the delegate for the GameController only if the segue identifier is accelGane
. But when firing the segue in showAccelGameView
, you are not using this identifier. If you already have the segue setup in your storyboard, use this to fire the segue
self.performSegueWithIdentifier("accelGane", sender: self)
回答2:
First of all, some tips :
Always try to declare your protocols (when refer to the delegate pattern) in the following way:
protocol GameEnded : class { func gameHasFinished(time: Float) }
With the above way you can then, declare your
delegate
variableweak
and avoid a strong reference.You class
weak var
should be in the following way:class AcceleratorGameController: UIViewController { weak var delegate : GameEnded? // rest of your code }
And for the last you should keep a reference as a global variable of the class AcceleratorGameController
to set as your delegate
in the prepareForSegue
, like in the following way:
class ChallengeViewController : UIViewController, GameEnded {
var acceleratorGameController : AcceleratorGameController!
override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) {
if segue.identifier == "accelGane" {
acceleratorGameController = segue.destinationViewController as! AcceleratorGameController
acceleratorGameController.delegate = self
}
}
}
And the above code should be fix your issue. I hope this help you.
来源:https://stackoverflow.com/questions/31253925/fatal-error-unexpectedly-found-nil-while-unwrapping-an-optional-value-while-c