I have a UITabBarController as my root controller, and in each tab I have a UIViewController.
I am using a singleton class for my location controller.
I would like to know the proper way to handle setting the delegate for the location controller.
When the app starts, the first tab is selected, and the UIVIewController on that tab loads the location controller, and sets itself as the delegate.
When I switch to the second tab, I also need the location controller, so I would like to know if I need to first set the delegate to nil in the first tab view controller's viewWillDisappear method, and then set it in the second tab view controller's viewWilAppear method, OR, can I just set it in the second one without first setting it to nil in the first one.
In short, must I nil the delegate before setting it again?
I'm fairly certain that I can just set the delegate again, but I want to make sure this is correct.
It is not necessary to set to nil, just set new delegate in the main thread.
Related
If I have multiple view controllers being presented and dismissed in any order, can I be sure that iOS calls viewWillAppear methods in the right order (i.e. order of appearance)?
I cannot find any specific information about this in the documentation.
I think this is all you need to know about viewWillAppear from the docs:
This method is called before the view controller's view is about to be added to a view hierarchy and before any animations are configured for showing the view. You can override this method to perform custom tasks associated with displaying the view. For example, you might use this method to change the orientation or style of the status bar to coordinate with the orientation or style of the view being presented. If you override this method, you must call super at some point in your implementation.
Only thing that comes to mind that might not be absolutely clear is that this callback is called on the presenting view controller when presented view controller is going to be dismissed (so presenting view controller is going to appear again).
Therefore if A is a root, A.viewWillAppear will be called before it will appear on the screen. Then, if A presents B, just before B becomes visible, B.viewWillAppear will be called. And when B is being dismissed, A.viewWillAppear will get called again, since its view will appear again.
viewWillAppear() is called the first time the view is displayed and it is also called when the view is displayed again, so it can be called multiple times during the life of the view controller object.
It’s called when the view is about to appear as a result of the user tapping the back button, closing dialog, or when the view controller’s tab is selected in a tab bar controller, or a variety of other reasons. Make sure to call super.viewWillAppear() at some point in the implementation
How can I know when a UIViewController has been just pushed from a UINavigationViewController ?
I obviously don't want to use viewDidAppear because that's method is called everytime that view appears, not just when it's pushed.
viewDidLoad is called before the view controller is pushed and I don't have the reference to the navigationController available
You can check this from of navigation viewcontrollers array
//Eg:
//Maintain your navigation object:
#property (strong, nonatomic) UINavigationController *navController;
//use:
if([[self.navController.viewControllers lastObject] class] == [your view controoler class]) {
// your view controller is present in navigation stack
}
There are multiple ways to do this:
The simplest way. When pushing the controller, set a flag on it. You know when you are pushing, you can run custom code at that moment.
UINavigationControllerDelegate and its navigationController:didShowViewController:animated:. Again, you can make the controller the delegate or just call a method on it externally.
Logic inside the controller - You can probably use a combination of viewDidAppear and willMoveToParentViewController:. Initially, when the controller appears, it has been pushed. After that, you can reset the "pushed" state when the controller is removed from the navigation controller when listening to changes of parent controller. Your use case is not very clear but in some cases you could just handle the first viewDidAppear call and it would work.
However, note the first two options are far easier to implement. That's because you are trying to listen to an event from a class that shouldn't know about that event.
The most sensible solution in that case is listen to that event somewhere else and setup the controller externally to handle that event.
You can do that from viewDidAppear. set a flag or bool status to true or YES when pushed from previous VC. and then put condition in viewDidAppear that if status or flag is true then only do some stuff that you want to do on push. when you pop from another view to current view set this flag or status to NO so, your condition from viewDidAppear will not execute.
I need a way to change text depending of user input, when user tap back button. I followed that solution: Find out if user pressed the back button in uinavigationcontroller?
and did add following code in viewDidLoad:
if ([self isMovingFromParentViewController]) {
NSLog(#"isMoved");
[self.delegate stringChangedTo:self.myTextField.text atIndex:self.indexToPass];
}
However, nothing changed. More to say, method is not called (NSLog dont output a string).
How could i find a way to call delegate when user tap back button?
That code needs to be in viewWillDisappear: or viewDidDisappear:. not viewDidLoad.
viewDidLoad is called when the view controller's view is loaded. You want to call the delegate when the view controller is being dismissed.
There is also a UINavigationControllerDelegate protocol. You can get notified when a given view controller is shown by implementing either of these:
-navigationController:willShowViewController:animated:
-navigationController:didShowViewController:animated:
ADDENDUM:
In my opinion, using the delegate is a cleaner design, because you get notified precisely when a navigation event occurs. View controller life cycle methods such as -viewDidDisappear:, etc. can get called when you present/dismiss a modal view controller, and require that you add logic to discern those.
I understand that you can use ViewDidLoad to run some code when a view is loaded. However that only happens once. How can I run a method every single time that view is shown. So for example: let says you are currently in ViewController A and you press a UIButton to go to ViewController B. Then you press a button to go back to ViewController A, how would you then re-run the ViewDidLoad code??
I hope my question makes sense. In essence I want to re-run a small method every single time the user is on a particular ViewController.
Thanks for your time, Dan.
viewWillAppear:
Notifies the view controller that its view is about to be added to a
view hierarchy.
or
viewDidAppear:
Notifies the view controller that its view was added to a view
hierarchy.
This answer didn’t help. I found myself in the same situation and the solution is simple.
Create a method with codes you want to be executed every time your view controllerA shows up.
Place your method under viewDidAppear()
Make sure that the modal type of your viewcontrollerB is set to fullscreen (fullscreen removes viewcontrollerA from the stack)
Under viewcontrollerB viewDidLoad()
Set its background other color than clear. White works for me
Dismiss from your viewControllerB and “voila!”
Create an AbstractController that every view controller inherits from that controller, and you override the viewDidLoad method and make it do whatever you want at every view opened.
I am using a Storyboard with a UINavigationController that is set as "is initial View Controller". It's attached RootViewControllers. viewDidLoad method gets called after application:didFinishLaunchingWithOptions: and applicationDidBecomeActive:.
Why does that happen?
Because the view is loaded before your application becomes active. Active is defined as the point at which your application begins responding to events, and you need a view for this.
If you want to know why viewDidLoad method gets called after those methed I suggest you to read the app-launch-sequence-ios. It's the normal bootstrap execeution in every iOS application.
When you istantiate a controller with an associated view, the view for that controller takes some time to load in memory. viewDidLoad is not called immediately but only when the view has been loaded completely. Here you are sure that outlet for that view are linked correctly.
Hope it helps.