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

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

我已经实现了一个协议来获取某种消息,游戏已经完成并将时间传递给我的控制器(在 SpriteKit 中编写的游戏)。但是现在我在完成游戏并执行 gameEnded 方法后遇到了这个致命错误,应用程序崩溃了。有谁知道为什么?

这是我的代码

游戏ViewController

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

这是我的另一个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)
}

编辑: 我做了你告诉我的所有事情,但它仍然在同一点崩溃。 Xcode 告诉我使用委托。我什么时候做委托?它有效,但这不是我想要的。必须调用该函数!

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

我在 prepareForSegue() 方法中加入了一些 println(),但不知何故它们不会被执行。我必须以某种方式给他们打电话吗?这是我的 segue 的截图。

http://i.stack.imgur.com/oK4Ce.png

我也试过把一个 segue 反过来,但也没用。

http://i.stack.imgur.com/TVmdP.png(没有标识符,因为它是唯一的 segue。)

我忘了说这个 AcceleratorGameController 背后的 SpriteKit Game 在完成时调用了 gameOver() 方法。

首先,一些提示:

  • 始终尝试以下列方式声明您的协议(当参考 delegate 模式时):

    protocol GameEnded : class {
        func gameHasFinished(time: Float)
    }
    

    通过上述方式,您可以声明 delegate 变量 weak 并避免强引用。

  • 你classweak var应该是这样的:

    class AcceleratorGameController: UIViewController {
    
       weak var delegate : GameEnded?
    
       // rest of your code
    }
    

最后,您应该将 class AcceleratorGameController 的引用作为全局变量,以便在 prepareForSegue 中设置为您的 delegate,就像在以下方式:

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

上面的代码应该可以解决您的问题。希望对你有帮助。

我不明白 ChallengeViewController 将如何初始化 AccelerometerGameController 的委托。

在您的 prepareForSegue 中,您仅在 segue 标识符为 accelGane 时才为 GameController 设置委托。但是在 showAccelGameView 中触发 segue 时,您没有使用此标识符。如果你的故事板中已经有 segue 设置,使用它来触发 segue

self.performSegueWithIdentifier("accelGane", sender: self)