2015-07-06 3 views
0

Я реализовал протокол, чтобы получить какое-то сообщение, что игра уже завершена и передает время моему контроллеру (Game wrote в SpriteKit). Но теперь у меня эта роковая ошибка после завершения игры и выполнения метода gameEnded, и приложение просто сработает. Кто-нибудь знает, почему?«Неустранимая ошибка: неожиданно найден nil во время разворачивания необязательного значения» при вызове метода протокола

Вот мой код

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

Вот мой другой 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: Я сделал все, что вы сказали мне, и он по-прежнему падает в той же точке. 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. 
} 

Я поместил в некоторых println() в prepareForSegue() методов, но так или иначе они не будут выполнены. Должен ли я их как-то называть? Вот скриншот моего segue.

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

Я также попытался положить в одну Segue наоборот, но это не помогает.

http://i.stack.imgur.com/TVmdP.png (не идентификатор, потому что это единственный переход.)

Я забыл сказать, что SpriteKit игры за этим AcceleratorGameController вызывает метод gameOver(), когда он закончил.

ответ

1

Я не вижу, как ChallengeViewController инициализирует делегат AccelerometerGameController.

В вашем prepareForSegue вы устанавливаете делегат для GameController только в том случае, если идентификатор segue равен accelGane. Но при запуске segue в showAccelGameView, вы не используете этот идентификатор. Если у вас уже есть настройка segue в вашем раскадровке, используйте это, чтобы сжечь segue

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

Спасибо большое, что помогло мне! :) – Dastyla

2

Прежде всего, несколько советов:

  • Всегда старайтесь объявлять протоколы (если обратиться к делегата образца) следующим образом:

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

    С указанным выше способом вы можете затем объявить переменную delegateweak и избежать сильной ссылки.

  • Вы класс weak var должен быть следующим образом:

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

И последнее, вы должны сохранить ссылку как глобальную переменную класса AcceleratorGameController, чтобы установить в качестве delegate в prepareForSegue , как это делается следующим образом:

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

И вышеприведенный код должен исправить вашу проблему. Надеюсь, это поможет вам.

+0

Зачем нам беспокоиться о слабых/сильных ссылках? Я думал, что ARC должна была избавиться от нашей необходимости беспокоиться об этом. –

+0

Да, и не может существовать циклы сохранения, вы можете больше узнать об этом в ответ @matt в этом http://stackoverflow.com/questions/27327545/how-does-swift-memory-management-work. –

+0

Да, это делает его более ясным. Я должен помнить об этом при принятии шаблона делегата. –

Смежные вопросы

 Смежные вопросы