Objective-C: How to properly set didSelectViewCont

2019-01-20 17:45发布

问题:

Trying to accomplish

Tap on the tabbaritem and it will called the respective method on the tabbaritem VC.

Issue

When I tap on tabbaritem2 it will call didSelectViewController on tabbaritem2 and then the respective method. Then when I tap on tabbaritem3it will still call the didSelectViewController on tabbaritem3 and the respective method.

But when I switch back and tap on tabbaritem2. It will still call the didSelectViewController on tabbaritem3 and not didSelectViewController on tabbaritem2 and the respective method doesn't work anymore

The issue without break

The issue with break

Question

How to properly set up the didSelectViewController method so that when tabbaritem is tapped it will call and load the method respectively?

Code

MyTabBarController.m (Do I need to do something here?)

- (void)tabBarController:(UITabBarController *)tabBarController didSelectViewController:(UIViewController *)viewController {
    NSLog(@"didSelectViewController... ");

   // if ([viewController isKindOfClass:[UINavigationController class]]) {
   //      [(UINavigationController *)viewController popToRootViewControllerAnimated:NO];
   // }

    //=== I tried the following but it is not loading the method=====================
    //if ([viewController isKindOfClass:[ClassNavigationController class]]) {   // Here newViewController is the controller where the webview reload happens.
      //  [[[Classes alloc] init] reloadWebViewData];  // We create and instance for the new controller and call the delegate method where the reload works.
    //}

    //if (viewController == [tabBarController.viewControllers objectAtIndex:2]){
     //   [(UINavigationController *)viewController popToRootViewControllerAnimated:YES];
     //   [[[Classes alloc] init] LoadClasses];

    //}else if (viewController == [tabBarController.viewControllers objectAtIndex:3]){

      //  [(UINavigationController *)viewController popToRootViewControllerAnimated:YES];
      //  [[[Gym alloc] init] handleRefreshGym:nil];

    //}else{
        //=== The following code will make viewWillAppear load on each tab bar item
        //=== Without it, tapping on new tab bar item will not load viewWillAppear
      //  [(UINavigationController *)viewController popToRootViewControllerAnimated:NO];
    //}
    //=================================================================================
}

Classes.m

- (void)viewDidLoad {

    [super viewDidLoad];

    UITabBarController *tabBarController = (UITabBarController*)[UIApplication sharedApplication].keyWindow.rootViewController ;

    [tabBarController setDelegate:self];

}

-(void)tabBarController:(UITabBarController *)tabBarController didSelectViewController:(UIViewController *)viewController {

    NSLog(@" Classes Called ");

    if (viewController == [tabBarController.viewControllers objectAtIndex:2])
    {
        [(UINavigationController *)viewController popToRootViewControllerAnimated:YES];
        [self handleRefresh:nil];

    }else{
        [(UINavigationController *)viewController popToRootViewControllerAnimated:NO];
    }

}

Gym.m

    - (void)viewDidLoad {

    [super viewDidLoad];

    UITabBarController *tabBarController1 = (UITabBarController*)[UIApplication sharedApplication].keyWindow.rootViewController ;

    [tabBarController1 setDelegate:self];

}

-(void)tabBarController:(UITabBarController *)tabBarController didSelectViewController:(UIViewController *)viewController {

    NSLog(@" Gym Called ");

    if (viewController == [tabBarController.viewControllers objectAtIndex:3])
    {
        [(UINavigationController *)viewController popToRootViewControllerAnimated:YES];
        [self handleRefreshGym:nil];

    }else{
        [(UINavigationController *)viewController popToRootViewControllerAnimated:NO];
    }

}

MyStoryBoard

回答1:

So the TabBarController can only have one delegate at a time. In the code you posted you're setting the tabBarController.delegate = self in each respective view controllers lifecycle method of viewDidLoad (called once when the view is first loaded). So whatever the last view controller is to load will be the final tabBarControllerDelegate.

Here's a very simple example to show what I mean:

FirstViewController

#import "FirstViewController.h"

@interface FirstViewController () <UITabBarControllerDelegate>

@end

@implementation FirstViewController

- (void)viewDidLoad {
    [super viewDidLoad];
    self.tabBarController.delegate = self;
    // Do any additional setup after loading the view, typically from a nib.
}

- (void)viewWillAppear:(BOOL)animated {
    [super viewWillAppear:animated];
    NSLog(@"Who's my tab bar controller delegate = %@", self.tabBarController.delegate);
}

- (void)tabBarController:(UITabBarController *)tabBarController didSelectViewController:(UIViewController *)viewController {
    NSLog(@"Delegate called on %@", NSStringFromClass([self class]));
}


@end

SecondViewController

#import "SecondViewController.h"

@interface SecondViewController () <UITabBarControllerDelegate>

@end

@implementation SecondViewController

- (void)viewDidLoad {
    [super viewDidLoad];
    self.tabBarController.delegate = self;
    // Do any additional setup after loading the view, typically from a nib.
}

- (void)viewWillAppear:(BOOL)animated {
    [super viewWillAppear:animated];
    NSLog(@"Who's my tab bar controller delegate = %@", self.tabBarController.delegate);
}

- (void)tabBarController:(UITabBarController *)tabBarController didSelectViewController:(UIViewController *)viewController {
    NSLog(@"Delegate called on %@", NSStringFromClass([self class]));
}

@end

If I run this and start by selecting the FirstViewController's tab, then select the SecondViewController's tab, then go back to selecting the FirstViewController's tab this is the log result I get:

First Tab Selected:
Who's my tab bar controller delegate = <FirstViewController: 0x7ff9eb406970>
Delegate called on FirstViewController

Second Tab Selected:
Who's my tab bar controller delegate = <SecondViewController: 0x7fa33ac0a540>
Delegate called on FirstViewController (this is still FirstViewController here because the tab bar selection occurred prior to setting the SecondViewController to the tabBarControllerDelegate)

First Tab Selected:
Who's my tab bar controller delegate = <SecondViewController: 0x7fa33ac0a540>
Delegate called on SecondViewController

Second Tab Selected:
Who's my tab bar controller delegate = <SecondViewController: 0x7fa33ac0a540>
Delegate called on SecondViewController

...
 and it continues on that the SecondViewController will remain the delegate

So my recommendation would be to use a different pattern that just maintains one coordinator to handle the TabBarDelegation.

Edit in response to your comment about other recommendations

A rather standard idiom in iOS is loading your data from the server once (usually in viewDidLoad of the respective view controllers then storing it), then having a pull to refresh control which allows users to refresh the data on command: https://medium.com/ios-os-x-development/ios-tips-pull-to-refresh-in-less-than-30-seconds-ef884520f0df If you definitely require the tab bar delegate to do something on each view controller selection, I'd recommend having one central object that is the only tab bar delegate and having it handle what tasks to do based on the view controller passed in through the delegate method tabBarController:didSelectViewController: as one additional example.