SpriteKit: Black Screen after move from SKScene to UIViewController - ios

I'm stuck on transitioning from an SKScene to a ViewController that I've added to the Main.storyboard. I know there are tons of the same question but nothing works for me.
I would be grateful if I get an answer, anyway.
My code to transition:
func presentNextVC() {
let vc = UIViewController(nibName: "NextVC", bundle: nil) as UIViewController
if let responder = self.view?.nextResponder() {
let vc = responder as UIViewController
vc.presentViewController(NextVC(), animated:true, completion:nil)
}
This function will be called by a TouchedNode-event. When node is touched, I think it moves to the NextVC, but I only get a black screen.
// EDIT: The solution:
func presentNextVC() {
let vc = UIStoryboard(name: "Main", bundle:nil).instantiateViewControllerWithIdentifier("NextVc") as UIViewController
let currentViewController = (UIApplication.sharedApplication().delegate as AppDelegate)
currentViewController.window?.rootViewController?.presentViewController(vc, animated: true, completion: nil)
}

Related

Swift iOS -storyboard.instantiateViewController(withIdentifier:) causing retain cycle

I'm using my physical device and not the simulator.
I'm instantiating a vc using storyboard.instantiateViewController(withIdentifier:) and presenting it modally. I dismiss it using presentingViewController?.dismiss(animated: true, completion: nil). Inside the presented vc I have a print method inside Deinit that never runs.
I went to Instruments > Allocations > Statistics > Allocation Summary > MyApp.ThePresenedController and it shows 2 faces saying something is wrong. When I clicked them it took me to the presenting vc's code where I instantiated the vc to present and highlighted it green. After the presented vc is dismissed it's not removed from the Allocation Summary list. Inside the presented vc there isn't a reference to the presenting vc so it's not a weak var problem.
How come storyboard.instantiateViewController(withIdentifier:) is causing me a problem?
Presenting VC:
#IBAction func forgotPasswordButtonTapped(_ sender: UIButton) {
let mainStoryboard: UIStoryboard = UIStoryboard(name: "Main", bundle: nil)
let forgotPasswordVC = mainStoryboard.instantiateViewController(withIdentifier: "ForgotPasswordController") as! ForgotPasswordController
let navVC = UINavigationController(rootViewController: forgotPasswordVC)
present(navVC, animated: true, completion: nil)
}
Presented VC:
#IBAction func cancelButtonTapped(_ sender: UIButton) {
presentingViewController?.dismiss(animated: true, completion: nil)
}
deinit{
print("I've been dismissed")
}
I'm also using the same storyboard.instantiateViewController(withIdentifier:) code inside AppDelegate and the same 2 faces and highlighted green error is occurring.
AppDelegate didFinishLaunching:
let mainStoryboard: UIStoryboard = UIStoryboard(name: "Main", bundle: nil)
if userDoesThis {
// if true this first line will highlight green
let thisVC: ThisController = mainStoryboard.instantiateViewController(withIdentifier: "ThisController") as! ThisController
let nav = UINavigationController(rootViewController: thisVC)
} else {
// if false this first line will highlight green
let thatVC: ThatController = mainStoryboard.instantiateViewController(withIdentifier: "ThisController") as! ThatController
let nav = UINavigationController(rootViewController: thatVC)
}
window?.rootViewController = nav
window?.makeKeyAndVisible()
return true
As #StevenFisher suggested inside the comments the problem wasn’t the green highlighted line itself but instead was a closure that I overlooked and didn’t declare with [weak self]. I’ve read articles that says that pressing the faceless faces takes you to the offending line of code but Steve pointed it that might not be the issue and it can/will instead take you to where the problem starts. In my situation it let me know that I had a problem somewhere in the file as soon as it was instantiated and not the line itself.

iOS swift - go to the next custom UITabBarController programatically

I created a storyboard. The first screen is Launch screen(custom UIViewController called LaunchViewController) and the next screen is custom UITabBarController called SampleTabViewController.
I want to have it automatically go to the SampleTabViewController after 2 seconds on the LaunchViewController.
But some samples that I have found is only from the custom UIViewController to custom UIViewController.
I already set 'sampleTabViewController' on screen associated with "SampleTabViewController" on the storyboard.
Here is my code.
class LaunchViewController: UIViewController {
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view.
print("LaunchViewController is initialized");
let time = dispatch_time(dispatch_time_t(DISPATCH_TIME_NOW), 2 * Int64(NSEC_PER_SEC))
dispatch_after(time, dispatch_get_main_queue()) {
// Put your code which should be executed with a delay here
let storyboard = UIStoryboard(name: "Main", bundle: nil)
let controller = storyboard.instantiateViewControllerWithIdentifier("sampleTabViewController")
self.navigationController.pushViewController(controller, animated: true)
}
}
I tried "self.presentViewController(CareGiverViewController(), animated: true, completion: nil)". It works, but the next screen is blank.
I just started learning iOS app with Swift.
Thanks.
Try to set TabbarViewController as rootViewController .
Replace with your push ViewController lines :
let mainStoryboard: UIStoryboard = UIStoryboard(name: "Main", bundle: nil)
let controller = mainStoryboard.instantiateViewController(withIdentifier: "sampleTabViewController") as! UITabBarController
UIApplication.shared.keyWindow?.rootViewController = controller

Scene Transition not working anymore after having change ViewController

Here is the way I navigate between different ViewControllers:
let newViewController = UIStoryboard(name: "Main", bundle: nil).instantiateViewController(withIdentifier: "viewController3")
UIApplication.topViewController()?.present(newViewController, animated: true, completion: nil)
with the following extension:
extension UIApplication {
class func topViewController(base: UIViewController? = UIApplication.shared.keyWindow?.rootViewController) -> UIViewController? {
if let nav = base as? UINavigationController {
return topViewController(base: nav.visibleViewController)
}
if let tab = base as? UITabBarController {
if let selected = tab.selectedViewController {
return topViewController(base: selected)
}
}
if let presented = base?.presentedViewController {
return topViewController(base: presented)
}
return base
}
}
And here is the way I invoke scene transitions in my SKScene (several):
let transition = SKTransition.fade(withDuration: 2)
let nextScene = NewScene(size: scene!.size)
nextScene.scaleMode = .aspectFill
scene?.view?.presentScene(nextScene, transition: transition)
Everything work fine before switching ViewControllers. Once the switching has been succeeded, I can not invoke transition anymore in my SKScene, the app get frozen without any error from Xcode (iPad connected to the Mac with live debugging)
Do you know what happens ?
I use Swift 3 and SpriteKit with ViewControllers to be able to use Vuforia static lib in a direct ViewController scene (UIView).
I have finally found the solution, it's necessary to dismiss the actual ViewController before changing with the new one:
self.dismiss(animated: false)
let newViewController = UIStoryboard(name: "Main", bundle: nil).instantiateViewController(withIdentifier: "viewController2")
UIApplication.topViewController()?.present(newViewController, animated: true, completion: nil)
If the dismiss call is not done, it's not possible to do new transition scene in the new ViewController.

Load multiple viewcontrollers on app init

I'm trying to load 2 view controllers at the same time after the launchscreen.
Here's the stack I want to do:
SECOND VC - Currently being viewed
FIRST VC
Root VC
I did a workaround on it by calling presentViewController method under the viewDidAppear, but the result is the root vc is visible for a half second then the FIRST VC loads then finally loads the SECOND VC last.
The idea here is to have SECOND VC to be seen first then once dismissed it will slide down and shows the FIRST VC then hides to the ROOT VC last.
what methods should I use to accomplish this?
EDIT: Here's the example:
ROOT VC
override func viewDidAppear(animated: Bool){
let storyboard: UIStoryboard = UIStoryboard(name: "Main", bundle: nil)
let firstVC: firstViewController = storyboard.instantiateViewControllerWithIdentifier("firstVC") as! firstViewController
self.presentViewController(firstVC, animated: false, completion: nil)
}
FIRST VC
override func viewDidAppear(animated: Bool){
let storyboard: UIStoryboard = UIStoryboard(name: "Main", bundle: nil)
let secondVC: secondViewController = storyboard.instantiateViewControllerWithIdentifier("secondVC") as! secondViewController
self.presentViewController(secondVC, animated: false, completion: nil)
}
Then I would have a button on the SECOND VC and FIRST VC to dismiss it

How freeing memory during viewController transition

I explain my problem.
I just made a game with 3 views.
the game presentation with a playbutton
the game scene
the game over scene with a button to play again or go back to the presentation scene.
My problem is when there is a transition between two scenes, the active memory will be 30MB more and each scene transition will increase the active memory about 30MB and will never decrease.
How can I fix it and release memory ?
Thank you all
My transition code :
// Transition in presentationViewController file
func transition(sender:UIButton!)
{
println("transition")
let secondViewController = self.storyboard?.instantiateViewControllerWithIdentifier("GameViewController") as UIViewController
let window = UIApplication.sharedApplication().windows[0] as UIWindow
UIView.transitionFromView(
window.rootViewController!.view,
toView: secondViewController.view,
duration: 0.65,
options: .TransitionCrossDissolve,
completion: {
finished in window.rootViewController = secondViewController
})
}
// transition in GameScene file
func removeCountDownTimerView()
{
defaults.setInteger(balloonDestroyed, forKey: "score")
let storyboard = UIStoryboard(name: "Main", bundle: nil)
let gameOverScene: UIViewController = storyboard.instantiateViewControllerWithIdentifier("GameOverViewController") as UIViewController
let vc = self.view?.window?.rootViewController
vc?.presentViewController(gameOverScene, animated: true, completion: nil)
}
// transition in gameOverViewController file
func transition(sender:UIButton!)
{
println("play transition")
let secondViewController = self.storyboard?.instantiateViewControllerWithIdentifier("GameViewController") as UIViewController
let window = UIApplication.sharedApplication().windows[0] as UIWindow
UIView.transitionFromView(
window.rootViewController!.view,
toView: secondViewController.view,
duration: 0.65,
options: .TransitionCrossDissolve,
completion: {
finished in window.rootViewController = secondViewController
})
}
instantiateViewControllerWithIdentifier("GameViewController") as UIViewController
This code is creating new ViewController each time user press the button. I advise you to use singletone pattern for this.
private let _SomeManagerSharedInstance = GameViewController()
class GameOverViewController {
class var sharedInstance: GameOverViewController {
return _GameOverViewController
}
You can also create a private class method for instantiating the View Controller from storyboard.

Resources