问题
I wanted to see what the best practice(s) of accessing UIViewController methods from GameScene is/are. Right now I have been using NSNotificationCenter, but I don't want to use this due to specific functionality that I am trying to achieve.
Also, if there are not any other ways of gaining access to UIViewController through GameScene, then really what I am wondering is a method of being able to present an UIAlertController within the GameScene without UIViewController.
I would just create a global variable to the UIViewController, but I heard this is bad practice.
Thanks!
回答1:
You can show UIAlertControllers in SKScenes, simply show them on the rootViewController, which is probably the best place to show them anyway.
self.view?.window?.rootViewController?.present...
I dont like referencing the GameViewController in SKScenes and I never actually got to a point where I was forced to do so. NSNotificationCenter, delegation or protocol extensions are the better way.
I actually use a helper for Alerts I made using Swift 2's protocol extensions because I like clean, reusable and as little duplicate code as possible.
Just make a new .swift file and add this code
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)
}
}
Now in your scenes you need to show alerts you simply conform to the protocol
class GameScene: SKScene, Alerts {
}
and call the methods like
showAlert(title: "Alert title", message: "Alert message")
as if they are part of the scene itself.
Enjoy
回答2:
This is a bit hacky, but to directly access functions from the view controller use this:
(view?.nextResponder() as? MyViewController)?.presentAlert()
This relies upon your SKView being the main view in your view controller. If it isn't then you'll need to add in .superview?
after your view?
call.
回答3:
An alternative to the previous answer I posted (and the more proper method) would be to create a property in your scene class to store a reference to the view controller and use that:
class MyGameScene: SKScene {
weak var viewController: MyViewController?
func somethingHappened() {
viewController?.presentAlert()
}
}
And when you present the scene in your controller make sure to set a reference to your view controller:
if let scene = GameScene(fileNamed:"GameScene") {
scene.viewController = self
// other stuff
skView.presentScene(scene)
}
来源:https://stackoverflow.com/questions/35875674/swift-spritekit-best-practice-to-access-uiviewcontroller-in-gamescene