Reputation: 2671
Usaly when you present a viewController from another viewController you do:
let vc : UIViewController = storyboard.instantiateViewControllerWithIdentifier("viewController") as UIViewController;
self.presentViewController(vc, animated: true, completion: nil);
I want to present a viewController from a SKScene. I haven't found any way of doing that. This question might be a duplicate, but i have just found answers in objective C that doesn't make sense to me
Upvotes: 4
Views: 3267
Reputation: 2224
Briefly -> You can't present a ViewController from SKScene directly but...
Today i was trying to solve this problem, in my game i need to present my PayWallViewController
, UIAlertViewController
, UIReferenceLibraryViewController
and actually didn't find any documentation about this case.
After thinking & googling couple of hours i found few methods to solve the problem and decided to share them here. Each method has its strengths and potential drawbacks, depending on your specific needs and the complexity of your project.
It allows you to direct access without the need for intermediaries and faster then other methods but may cause memory management problems & less modular and harder to maintain
Example Code:
In your scene declare vc reference (weak)
class GameScene: SKScene {
weak var gameViewController: GameViewController?
override func didMove(to view: SKView) {
// Use vc reference any where as you wish
}
override func willMove(from view: SKView) {
// Release resources
gameViewController = nil
}
}
An then then your view controller:
import UIKit
import SpriteKit
class GameViewController: UIViewController {
override func viewDidLoad() {
super.viewDidLoad()
if let skView = self.view as? SKView {
let scene = GameScene(size: skView.bounds.size)
scene.gameViewController = self // Assign you vc here
skView.presentScene(scene)
skView.ignoresSiblingOrder = true
}
}
}
Promotes loose coupling, allowing better separation of concerns, more flexible easy to broadcast to multiple listeners if needed and don't need to block the main thread. At the same time slightly slower then other methods and hard to debug
Example Code:
GameViewController.swift
: Observe notification that comes from GameScene
override func viewDidLoad() {
super.viewDidLoad()
if let skView = self.view as? SKView {
let scene = GameScene(size: skView.bounds.size)
skView.presentScene(scene)
}
NotificationCenter.default.addObserver(self, selector: #selector(presentAlert), name: NSNotification.Name("PresentAlert"), object: nil)
}
@objc func presentAlert() {
let alert = UIAlertController(title: "Alert", message: "This is an alert.", preferredStyle: .alert)
alert.addAction(UIAlertAction(title: "OK", style: .default, handler: nil))
present(alert, animated: true, completion: nil)
}
// Don’t forget to remove observer
deinit {
NotificationCenter.default.removeObserver(self)
}
GameScene.swift
: Post notification when you need
func triggerAlert() {
NotificationCenter.default.post(name: NSNotification.Name("PresentAlert"), object: nil)
}
Maintains loose coupling with clear communication paths, more flexible and readable but it needs to well document
Example Code:
var onRequestAlert: (() -> Void)? // Add it in your scene and call it when you need
scene.onRequestAlert = { [weak self] in self?.presentAlert() } // listen to trigger inside your ViewController
Upvotes: 0
Reputation: 955
Try the following in your scene class:
var currentViewController:UIViewController=UIApplication.sharedApplication().keyWindow.rootViewController!
currentViewController.presentViewController(viewController, animated: true, completion: nil)
I hope it helps.
Upvotes: 9