“致命错误:在展开可选值时意外发现 nil”,同时调用协议方法
Posted
技术标签:
【中文标题】“致命错误:在展开可选值时意外发现 nil”,同时调用协议方法【英文标题】:"fatal error: unexpectedly found nil while unwrapping an Optional value" while calling a protocol method 【发布时间】:2015-07-06 19:20:39 【问题描述】:我已经实现了一个协议来获取某种消息,即游戏已经完成并将时间传递给我的控制器(游戏在 SpriteKit 中编写)。但是现在我在完成游戏并执行 gameEnded 方法后遇到了这个致命错误,并且应用程序崩溃了。有谁知道为什么?
这是我的代码
游戏视图控制器
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
我也尝试过反之亦然,但也无济于事。
http://i.stack.imgur.com/TVmdP.png(没有标识符,因为它是唯一的转场。)
我忘了说这个AcceleratorGameController
背后的SpriteKit 游戏在完成后会调用gameOver()
方法。
【问题讨论】:
【参考方案1】:首先,一些提示:
始终尝试通过以下方式声明您的协议(当参考 delegate 模式时):
protocol GameEnded : class
func gameHasFinished(time: Float)
然后,您可以通过上述方式,声明您的 delegate
变量 weak
并避免强引用。
你的weak var
类应该是这样的:
class AcceleratorGameController: UIViewController
weak var delegate : GameEnded?
// rest of your code
最后,您应该将引用保留为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
上面的代码应该可以解决您的问题。希望对您有所帮助。
【讨论】:
我们为什么要担心弱/强引用?我认为 ARC 应该消除我们对此的担忧。 是的,不,它可能存在保留循环,您可以在***.com/questions/27327545/…@matt 的答案中阅读更多相关信息。 是的,这样更清楚。在采用委托模式时,我必须记住这一点。 我用你的提示编辑了这个问题,但它仍然不起作用【参考方案2】:我不知道ChallengeViewController
将如何初始化AccelerometerGameController
的委托。
在您的prepareForSegue
中,只有当segue 标识符为accelGane
时,您才为GameController 设置委托。但是在showAccelGameView
中触发segue 时,您没有使用此标识符。如果您已经在情节提要中设置了 segue,请使用它来触发 segue
self.performSegueWithIdentifier("accelGane", sender: self)
【讨论】:
非常感谢对我的帮助! :)以上是关于“致命错误:在展开可选值时意外发现 nil”,同时调用协议方法的主要内容,如果未能解决你的问题,请参考以下文章
@IBInspectable 致命错误:在展开可选值时意外发现 nil