I created a little game (not with Sprite Kit), I have a MenuViewController and a GameViewController.
On my GameViewController, I have a button "MENU" to go to the menu. I had this code to the GameViewController :
print("test")
It is executed every seconds with using a timer.
When I press the "MENU" button, I find myself on the menu but the timer is still running. I think the GameViewController is not completely removed, how can I do this ?
PS: to dismiss the GameViewController, I use this :
func goToMenuViewController() {
let menuViewController = MenuViewController()
menuViewController.modalTransitionStyle = UIModalTransitionStyle.CrossDissolve
self.presentViewController(menuViewController, animated: true, completion: nil)
}
EDIT 1
I add some infos about my app hierarchy :
When the user launch the app, he finds himself on the MenuViewController.
There is a play button on this ViewController which takes to the GameViewController.
On the MenuViewController, there is an other button which takes to the RulesEditorViewController, allowing to modify rules displayed on the GameViewController
you can not see if the GameViewController is removed in this way.
if you use a timer in a GameViewController, it will keep a ref to GameViewController until it stop executing.
By the way, present menu view controller won't make the game view controller be removed
Your try to dismiss GameViewController is wrong. You are create new Menu controller and showing it above the GameViewController. That's why this controller is still in app memory.
You have to use this function self.dismissViewControllerAnimated(true, completion: nil) or self.navigationController?.popToRootViewControllerAnimated(true) depending on your segue type.
For now if you want access RulesEditorViewController you have to stop the game and leave this controller. But if you want modify options while playing then it will be better if you will access RulesEditorViewController directly from your GameViewController like you trying to show Menu now.
Update:
First of all you should understand view controllers hierarchy and ways how to present it. I believe this tutorial on example of storyboards will help you: http://www.raywenderlich.com/50308/storyboards-tutorial-in-ios-7-part-1
Related
I have several views. Here's what it looks like: First view is StartViewController (arrow), which opens TabBarController which is owner of two other views - FavoriteViewController and MapViewController. How to close all of them and go back to the StartViewController?
This should work like starting the app from first view.
I found similar question, but unfortunately it doesn't work.
How to go back to the initial ViewController the right way?
1. First dismiss your current viewController by self.CurrentVC.dismiss(animated: true, completion: nil)
2. then, present/show your first or intial viewController present(firstVC,animated: true,completion: nil)
Here CurrentVC is the name for your current viewController and firstVC will be the name of your first viewController that you want to show.
I have a very linear app that uses a Navigation controller to go through a series of View Controllers. All segues are handled in the storyboard and set to "Push" (that's the only way I can get the navigation controller to work...)
Start with a 'menu' VC with options, select one and it takes you to another VC. Sometimes the next VC is another menu (more detailed) but sometimes the VC is an SCNView that shows an SCNNode. Navigating through the VCs is working perfectly, thanks to the Navigation Controller.
The problem comes whenever you go to one of the SCNViews and then back out (to a menu or previous VC). Particularly, switching from menu to SCNView, back to menu, back to same SCNView, over and over builds up memory until the app crashes.
ARC seems to not be releasing the SCNNodes/SCNViews when navigating out of them. Every SCNNode/Scene/View I set up as weak AND I've tried all kinds of combinations of the following code in each/all the VCs:
override func viewWillDisappear(_ animated: Bool) {
super.viewWillDisappear(true)
self.dismiss(animated: true, completion: nil)
}
I put this at the end of each VC but it still seems that the SCNNodes are getting retained and the memory builds up until it crashes.
How can I clear the SCNNodes when I exit the VC? Since I declare everything as weak inside ViewDidLoad, I can't call/set anything in the ViewWillDisappear func since it's outside of that.
Please help me with this. I have created a simple project with two views as shown. I have attached the images for my storyboard and swift files. So, I read that viewdidload will be executed only once while loading the view into the memory. But, when I make a transition from secondview to the firstview the viewdidload is executing again and so is the print statement in the viewdidload method.
Someone please explain me this.
viewDidLoad is not called once for the Application. It is get called once for that viewController when the view holds memory and loaded.
So as many number of of time you push to the viewController, that many times it will call the viewDidLoad
viewDidLoad() — Called when the view controller’s content view (the top
of its view hierarchy) is created and loaded
viewWillAppear() — Intended for any operations that you want always to
occur before the view becomes visible.
For more info about this look at the link : https://developer.apple.com/library/content/referencelibrary/GettingStarted/DevelopiOSAppsSwift/Lesson4.html
So if the view is already in memory (Like your case), then no need to push again, only need to pop back by this code
self.navigationController?.popViewControllerAnimated(true)
You should not make transition from secondViewController to firstViewController for back. Pop the second view controller by this code to back:
self.navigationController?.popViewControllerAnimated(true)
When you make a transition it makes a new instance from your firstViewController but when you pop the second view controller it dismiss your secondViewController and shows your last viewed viewController again.
Or
in the case that you are not using navigationController you should use below code to dismiss your secondViewController
self.dismissViewControllerAnimated(true, completion: {});
The main point is that you should not use new transition for back.
The simplest way:
1.First embed your ViewController in NavigationController
2.Call to this (instead of create segue for backing)
navigationController?.popToRootViewController(animated: true)
viewDidLoad will be called only once
I know this is probably an easy task but I can't get my head around how to solve it. I'm not using a NavigationController by the way. Basically I have 3 view controllers in my app:
-LoginVC (this has a register button. when tapped, it goes to the SignupVC)
-SignupVC (if user signs up, it will push to the MainAppVC)
-MainAppVC (has a logout button)
For the transitions, I use the method: present(viewController, animated:, completion:)
When the user logs in via the LoginVC, he'll be presented the MainAppVC as expected. When he logs out, I'll dismiss the current VC (which is the MainAppVC) to send him back to the LoginVC.
Now here is the case where I have questions about. When the user does not have an account and signs up, this is the VCs he will pass through (LoginVC > SignupVC > MainAppVC). Once he registers successfully, he'll be presented the MainAppVC. Now once he logs out, he'll be transitioned from the MainAppVC to the SignupVC because I used the same dismiss method.
What I want to do is to send the user back to the LoginVC from the MainAppVC. How do I accomplish that without using a navigation controller in my project? How do popular apps (Facebook, Twitter, Instagram, etc) handle this in their apps?
One way I can think of is to perform a segue from 3rd to 1st VC but I think that's a dirty way since it just adds to the stack, instead of popping it off which is a potential issue.
There are three solutions.
1.Use window root view controller.Set root view controller between login and main view controller.
let loginSb = UIStoryboard(name: "Login", bundle: nil)
let loginVc = loginSb.instantiateInitialViewController()
window!.rootViewController = loginVc
2.Dismiss the sign up view controller the first time you present main view controller.And present the main view controller from login view controller.
3.Try to dismiss the sign up view controller in the completion block when you dismiss the main view controller.
I think the first one is best.
If are forced to NOT use a rootViewController (with UINavigationController), you should check in MainAppVC which one is the previous VC (Pseudocode in the example) and do:
Note: Swift 3 Code.
// If previous VC is LoginVC
dismiss(animated: true)
// else if previous VC is SignupVC
// here's what you want
presentingViewController?.presentingViewController?.dismiss(animated: true)
Hope that helped.
Another option is to use unwind segues.
In the ViewController that you want to go back to, implement a method as follows
#IBAction func unwindToLogin(segue: UIStoryboardSegue) {
}
Then in Storyboard, from the last ViewController right click and drag from the button (for example) to Exit and choose unwindToLoginWithSegue.
Note that you can also do this programatically. Here is a good tutorial.
Best approach is :
Dismiss SignUpVC once User Register successfully, Then from LoginVC present MainVC.
In SignupVC :
self.dismissViewControllerAnimated(true, completion: {
self.LoginVC!.present(MainVC, animated: true, completion:nil)
})
This approach is used mostly.
I am making an app in xCode using Swift, and I need help with something. How do I program a UIButton that I added on a Scene on my Storyboard to navigate towards the previously used Scene (there are more than one Scenes in my app).For Example; if Im in scene3 and I'm navigated towards the scene with the UIButton, how can I program it to take me back to scene3 instead of the main menu? Or if I were in Scene2 and was navigated to the Scene with the UIButton, and I want it to take me to Scene2 instead of Scene3 or Main Menu.
Thank you
The Blue Scenes represent the levelScenes that will lead to the redScene after the level is done, however I want the UIButton to lead back to the exact same levelScene after it is pressed
You can use:
self.dismissViewControllerAnimated(true, completion: nil)
To dismiss the current view controller from the view hierarchy.
So you would create an IBAction for your UIButton that would execute that method.