I have a small problem I sadly couldn't solve. I have a few ViewControllers. I need to call a function when going back from a ViewController to the previous ViewController (which does not reload, so viewDidLoad / Appear is not called).
Mustn't there be anything like viewDidLoad, but gets called every time the ViewController is visible?
This is how I open the ViewControllers:
let vc = storyboard?.instantiateViewController(identifier: "levels_vc") as! LevelsViewController
present(vc, animated: true)
This is the way I try to get the event, but it only gets called the first time (when the ViewController loads the first time), but not when I open a new ViewController from this one and close the new one.
override func viewDidAppear(_ animated: Bool) {
super.viewDidAppear(animated)
print("VC appeared!")
}
You can use viewWillAppear or viewDidAppear for that purpose!.
viewWillAppear() is called every time the view will appear on the screen.
This can be useful for views that need to be updated every time they’re scrolled to. For example, the Now Playing section in a music app or any view that is updated when it is scrolled to.
viewDidAppear is called when the view has appeared on the users screen.
This is a good place to “lazy-load” any other elements onto your screen. If your user interface is very complicated, you don’t want to stall or cause a delay in the previous mentioned methods.
It’s better to load something onto the screen and then call some methods to update the views for some large applications.
This is also a create place to start any animations.
That would be ViewDidAppear() ViewDidAppear() - Apple Developer
Related
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.
Now I created a new project to test unwind segue.
In Storyboard the story entry is on VC0, a button in VC0 goes to VC1 (modally), a button in VC1 goes to VC2 (modally).
VC2 has a button to dismiss itself and in the function it looks like this:
#IBAction func btnDismiss(_ sender: Any) {
dismiss(animated: true, completion: nil)
}
in VC1 I added an unwind function as follows:
#IBAction func unwindSecondView(segue: UIStoryboardSegue){
print("unwinded")
}
Then in storyboard I linked VC2's exit icon to unwindSecondview as action.
It works pretty well, however after I clicked "dismiss" button in VC2, VC1 appeared briefly and jumped back to VC0.
??? Anything wrong that caused jumping back to VC0?
--------------Initial question -----------------
I'm new to iOS and got a little confused for how VCs are created and activated.
Say I created 2 ViewControllers in my single view app. MainController(VC_M) and SettingsController(VC_S). I added the segues in storyboard, a setting button in VC_M goes to VC_S, VCS collects information, writes to standardDefaults, then ok button goes back to VC_M and refresh its view.
When I try to preserve some information in VC_M, I found that after I click ok button in VC_S and go back to VC_M, VC_M gets recreated and viewDidLoad() gets called. In the debugger, it shows the VC_M object (self) now has a different address in memory, so seems it's another instance of the class.
Is this a normal behavior? It's best that the old VC_M object gets saved so some data doesn't need to be reloaded. Initially I thought I could put some data loading stuff in init(), but when VC_M gets re-created init() got called, too. Some older posts suggested that ViewDidLoad() should not be called again but rather ViewDidAppear() should get called, but I'm not sure if it's the same case now.
In my case is it better to just use standardDefaults to reload everything, or is there a different kind of segue I should use? (I used push segue).
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
Right now I'm doing this:
override func viewWillAppear(animated: Bool) {
super.viewWillAppear(animated);
self.loadObjects()
}
But every time I use loadObjects(), the screen briefly flashes. I don't know how to fix it. I am using a TabBarController (no segues between views), so each view is only loaded once, and I want to update each view when I navigate to it. loadObjects() works, it just creates this annoying visual bug. I assume that the old view is cached and is desplayed before the new one is loaded, and that's why I see this flash. Any suggestions?
I'm working on a app which has a button to open a view that access the camera.
So, I have a button to trigger a segue (using the storyboard) and in my other view, inside viewDidLoad(), I'm doing all I need to start the video capture.
The problem is that between touching the button and view been showed it take some small amount of time and I don't like it.
If I comment all the stuff regarding the video capture, the view show up instantly.
So, I think the lag is du to the preparation to access the camera.
How to display the view, an empty view, and then doing the stuff to show the camera?
If you want to show the new view controller and then activate the camera, move your code from viewDidLoad into viewDidAppear. You could try viewWillAppear, but depending on what your code does, you may just see the same issue you have now.
You have to be careful here to only do your activation once as viewWill/DidAppear can be called multiple times: especially as a result of being exposed when a controller you push on top is popped.
Just use viewDidAppear to load all the methods in that view controller instead of using the viewDidLoad method like so:
override func viewDidAppear(animated: Bool) {
super.viewDidAppear(animated)
}