How does a delegate method get invoked - ios

How to delegate methods actually get called?
Like lets say I add this to my UIViewController.m:
- (void)navigationController:(UINavigationController *)navigationController willShowViewController:(UIViewController *)viewController animated:(BOOL)animated
{
// code
}
Does the method get called when the view controller appears? How does delegation work?

According to the docs, the delegate is called just before the navigation controller displays a viewController’s view and navigationItem properties.
But, it appears that your question is, "how?".
In your Storyboard or somewhere in code, the UINavigationController is set up. Wherever that is, it has a delegate property (a variable). That property is set to some object that implements the UINavigationControllerDelegate protocol.
For example:
MySpecialViewController *myViewController = [[MySpecialViewController alloc] init];
UINavigationController *navigationController = [[UINavigationController alloc] initWithRootViewController:myViewController];
navigationController.delegate = self;
Now, whenever that navigationController is about to present a view controller, the navigationController:willShowViewController:animated: delegate method will be called on your object.

If you set your object as the delegate of the navigation controller, the navigation controller will call this method when a view controller is about to appear.
For delegate method implementation details, see this question and Concepts in Objecctive-C Programming: Delegates and Data Sources.

Well it's probably something like this inside UINavigationController class:
- (void)pushViewController:(UIViewController *)viewController animated:(BOOL)animated
{
[self.delegate navigationController:self willShowViewController:viewController animated:animated];
//do stuff to actually push the view controller
}
If the delegate is nil nothing happens because messages to nil make no effect, but if you set the delegate that method is invoked. I'm not sure if it happens directly inside pushViewController: method, but that doesn't really matter. Whenever the navigation controller is about to show next view controller it sends a message to its delegate

Related

Use prepareForSegue:Sender when switching VC in UITabBarController

I have googled far and wide, but everything is extremely confusing. I need it so when the tab bar gets switched to a different view controller, is there a method that gets called when the view controllers are about to switch, get the destination controller and set some variables to add some annotations to a MKMapView. How can I do this?
There are many options, but one of them is to implement the UITabBarControllerDelegate protocol and then set the class that implements it as the delegate of your UITabBarController. The delegate receives a message - tabBarController:didSelectViewController:
In that method you can implement the behavior you desire by looking at the last view controller and the next one. To get access to those view controllers from your delegate, you may need to add them as weak properties to your delegate class. You can also access all of your UITabBarController's sub view controllers through its viewControllers property which is an array of view controllers.
After some experimentation with the delegate methods, I was able to find an answer.
I used the - (BOOL)tabBarController:(UITabBarController *)tabBarController shouldSelectViewController:(UIViewController *)viewController method.
This feels like a fairly decent replacement because you can get each controller easily.
Warning: This method should not be used to handle large blocks of code, but to set up a view controller to run large blocks of code.
A test implementation:
- (BOOL)tabBarController:(UITabBarController *)tabBarController shouldSelectViewController:(UIViewController *)viewController
{
FirstViewController *currentController = (FirstViewController *)[tabBarController selectedViewController];
SecondViewController *destinationController = (SecondViewController *)viewController;
// If you want, do some code on these here. For more precision, read on.
return YES;
}
This can be used with logic to determine whether you should execute some specific code: EX:
if ([[tabBarController selectedViewController] class] == [FirstViewController class]) {
if ([viewController class] == [SecondViewController class]) {
// It is going from first to second. Do some code here.
}
}
Also, you have to have set the delegate
TabBarController .h
#interface TabBarController : UITabBarController<UITabBarControllerDelegate>
...
TabBarController .m
...
- (void)viewDidLoad
{
self.delegate = self;
}
...

How to know when the root view controller of a navigation controller is going to be loaded?

I need to pass an object to the root view controller of an UINavigationController before it appears. I have its root view controller relationship set in storyboard, and it seems that I can't handle it like the other types of segues.
How could I do this?
Thanks
You could assign the UINavigationController a delegate and implement the method -
- (void)navigationController:(UINavigationController *)navigationController
willShowViewController:(UIViewController *)viewController
animated:(BOOL)animated {
// check viewController is kind of class, check any flags
// pass object to vc
}

want to call myMethod() when selecting same tab bar in IOS

I Want to call my own method, i.e. myMethod() when same tab bar is selected which is already selected.
I had tried to call didSelectMethod() but it is not called in my ViewController class.
Please help me in this,
Thank you
Jagveer Rana
Where you own your tabBarController instance there you set delegate
tabBarController.delegate= self; // It is must to set delegate
add the below delegate method
- (void)tabBarController:(UITabBarController *)tabBarController didSelectViewController:(UIViewController *)viewController
{
if ([viewController respondsToSelector:#selector(myMethod)]) {
[viewController performSelector:#selector(myMethod)];
}
}
It sounds like your ViewController class is not the delegate for your UITabBarController, otherwise tabBarController:didSelectViewController: would be called.
Make sure your delegate is linked up properly.
If that's not the problem, then there are a few other StackOverflow questions asking the same thing:
Tab bar, reload every time tab is pressed
Detect a re-tab on selected UITabbarItem

Can I invoke the delegate method after popViewcontroller?

1) I have two controllers, fistViewController, secondViewController.
2) first controller implements the delegate say "xyzDelegate".
#interface FirstViewController : UIViewController <xyzDelegate>
3) The delegate method in First View Controller refreshes the UIViewTable.
4) First Controller : Pushing Second View Controller.
SecondviewController *svc = [[SecondViewController alloc] initWithNibName:#"SecondViewController" bundle:nil];
svc.delegate = self;
[self.navigationController pushViewController:svc animated:YES];
4) In second View Controller:
id<xyzDelegate> strongDelegate = self.delegate;
[self.navigationController popViewControllerAnimated:YES];
NSLog (#"After popViewControler");
[strongDelegate dateSelected:dateChoosen]; // Invoking Delegate Method.
Question:
1) Is it the general practice to invoke the delegate method after Popping View Controller?
as i am refreshing the UITable, once the delegate method is invoked in FirstView Controller.
Usually, a view controller is an independent unit of screens. Especially if it's switched by navigation-controller. You are expected to reconfigure views to bind their data in one of overriding of viewWillAppear: or viewDidAppear: method.
Usually viewDidAppear: is preferred. Because in many cases, switching view needs reloading of underlying data, and this usually causes asynchronous I/O. In this case, this asynchronous I/O may interfere simultaneously performing view-switching animation.
Anyway, if your view setup operation is lightweight, it's fine and better to go with viewWillAppear: because it will make your user to wait less.
In this case, IMO, it seems your best bet is just marking to refresh the data on the target view controller, and handle refreshing in the view-controller's viewDidAppear: method.
You should call the delegate methods BEFORE POP action occurs.
[strongDelegate dateSelected:dateChoosen];
popViewControllerAnimated Will call second view controller dealloc method to destroy, where you would release the strongDelegate. So no more strongDelegate to receive the dateSelected: method.
[self.navigationController popViewControllerAnimated:YES];

Why does my tabbar controller execute code from a different view controller than the active one?

Firstly, I have set both viewcontrollers to be UITabBarController delegates. Both are part of a tab bar controller. I did this by putting the following code into each viewDidLoad:
self.tabBarController.delegate = self;
Then I added the following delegate method to CalculatorsViewController:
- (void)tabBarController:(UITabBarController *)tabBarController didSelectViewController:(UIViewController *)viewController {
[self presentCalculatorsView];
}
Where presentCalculators view simply reveals a subview within the same view controller.
I also added the following delegate method to the OptionsViewController:
-(void)tabBarController:(UITabBarController *)tabBarController didSelectViewController:(UIViewController *)viewController {
[self presentHomeScreen];
}
Again this method simply reveals another subview within the viewController.
The problem I am having is that the OptionsViewController presentHomeScreen method is only called if I do not visit the CalculatorsViewController. Once I do visit the CalculatorsViewController in the app and then return to OptionsViewController,
[self presentHomeScreen]
is never called. In fact, it appears that it still calls the method from the CalculatorsViewController. I tested it with an NSLog statement.
Any ideas why one method overrides the other? Or why the tab bar button executes code from another viewController, other than the one that is active?
EDIT* It is almost as if the one viewController 'steals' the delegate from the other.
By calling self.tabBarController.delegate = self; on each viewDidLoad method, you are basically telling the tab bar controller to use abandon the current delegate and use the current view controller as delegate.
Note that the viewDidLoad method is called only once under normal circumstances. (It may be called again when the view of your view controller is unloaded due to memory warning, for example, then you access the view of your view controller again, which calls loadView/awakeFromNib and viewDidLoad. I'm not entirely sure on this scenario though.) In your scenario:
Open OptionsViewController for the first time - tab bar controller's delegate is OptionsViewController
Open CalculatorsViewController for the first time - tab bar controller's delegate is now CalculatorsViewController
Go back to OptionsViewController - tab bar controller's delegate is still CalculatorsViewController, as the viewDidLoad is not called again
If you must change the delegate, you can do it instead in the viewWillAppear method.

Resources