Swift SpriteKit: лучшая практика для доступа к UIViewController в GameScene

Я хотел посмотреть, каковы лучшие методы доступа к методам UIViewController из GameScene. Прямо сейчас я использую NSNotificationCenter, но я не хочу использовать это из-за определенных функций, которые я пытаюсь достичь.

Кроме того, если нет других способов получить доступ к UIViewController через GameScene, то на самом деле меня интересует способ представления UIAlertController в GameScene без UIViewController.

Я бы просто создал глобальную переменную для UIViewController, но я слышал, что это плохая практика.

Спасибо!

3 ответа

Решение

Вы можете показывать UIAlertControllers в SKScenes, просто показывать их в rootViewController, который, пожалуй, является лучшим местом для их отображения в любом случае.

self.view?.window?.rootViewController?.present...

Мне не нравится ссылаться на GameViewController в SKScenes, и я никогда не доходил до того момента, когда меня заставляли это делать. NSNotificationCenter, делегирование или расширения протокола - лучший способ.

На самом деле я использую помощника для оповещений, которые я сделал, используя расширения протокола Swift 2, потому что мне нравится чистый, многократно используемый и как можно меньше дублирующегося кода.

Просто создайте новый файл.swift и добавьте этот код

import SpriteKit

protocol Alerts { }
extension Alerts where Self: SKScene {

func showAlert(title title: String, message: String) {

    let alertController = UIAlertController(title: title, message: message, preferredStyle: .Alert)

    let okAction = UIAlertAction(title: "OK", style: .Cancel) { _ in }
    alertController.addAction(okAction)

    self.view?.window?.rootViewController?.presentViewController(alertController, animated: true, completion: nil)
}

func showAlertWithSettings(title title: String, message: String) {

    let alertController = UIAlertController(title: title, message: message, preferredStyle: .Alert)

    let okAction = UIAlertAction(title: "OK", style: .Cancel) { _ in }
    alertController.addAction(okAction)

    let settingsAction = UIAlertAction(title: "Settings", style: .Default) { _ in

        if let url = NSURL(string: UIApplicationOpenSettingsURLString) {
            UIApplication.sharedApplication().openURL(url)
        }
    }
    alertController.addAction(settingsAction)

    self.view?.window?.rootViewController?.presentViewController(alertController, animated: true, completion: nil)
    }
}

Теперь в ваших сценах вам нужно показывать оповещения, которые вы просто соответствуете протоколу

class GameScene: SKScene, Alerts {

} 

и вызвать методы как

showAlert(title: "Alert title", message: "Alert message")

как будто они являются частью самой сцены.

наслаждаться

Альтернативой предыдущему ответу, который я разместил (и более правильный метод), будет создание свойства в вашем классе сцены для хранения ссылки на контроллер представления и использование этого:

class MyGameScene: SKScene {

    weak var viewController: MyViewController?

    func somethingHappened() {
        viewController?.presentAlert()
    }

}

И когда вы представляете сцену в вашем контроллере, убедитесь, что установили ссылку на ваш контроллер вида:

if let scene = GameScene(fileNamed:"GameScene") {
    scene.viewController = self

    // other stuff
    skView.presentScene(scene)
}

Это немного странно, но для прямого доступа к функциям из контроллера представления используйте это:

(view?.nextResponder() as? MyViewController)?.presentAlert()

Это зависит от того, является ли ваш SKView основным видом в вашем контроллере представления. Если это не так, вам нужно добавить в .superview? после вашего view? вызов.

Другие вопросы по тегам