“fatal error: unexpectedly found nil while unwrapping an Optional value” while calling a protocol method

三世轮回 提交于 2020-02-08 08:50:30

问题


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 variable weak 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

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!