5

Context:

I am using TabViewController and NavigationController at the same time. The two tabs are RECENT and POPULAR and they show a list of posts. Imagine you're inside RECENT tab and click a post, and you go into a postsShow view. So you're one deeper in a navigation stack. When you go to POPULAR tab and come back to RECENT tab, you are still seeing the post you clicked before. But I want to show a list of posts instead.

What I am trying:

I am setting PostsShowViewController a TabBarControllerDelegate and when a tab item is selected, I am trying to pop to its root view controller. Then, when the user comes back, he will see the rootViewController, which is the list of posts instead of PostsShow view.

Code:

viewDidAppear self.tabBarController.delegate = self;

viewDidDisappear self.tabBarController.delegate = nil;

header UITabBarControllerDelegate

- (BOOL) tabBarController:(UITabBarController *)tabBarController shouldSelectViewController:(UIViewController *)viewController {
    [self.navigationController popToRootViewControllerAnimated:NO];
    return YES;
}

How it doesn't work:

  1. Go to recent tab
  2. Click a post to go to PostsShow view
  3. Go to popular tab
  4. Go back to recent tab (I am expecting to see a list of posts instead of PostsShow view)
  5. Error! EXC_BAD_ACCESS

EDIT: Following what the answers suggest doing, I get a slightly better behavior but still end up with an error.

Code

- (void)tabBarController:(UITabBarController *)tabBarController didSelectViewController:(UIViewController *)viewController{
    UINavigationController *navigation = (UINavigationController*) viewController;
    [navigation popToRootViewControllerAnimated:NO];
}
  1. go to recent tab
  2. click post to go to PostsShowview
  3. go to popular tab
  4. go back to recent tab
  5. I see a list of posts (no error!)
  6. go back to popular tab : ERR_BAD_ACCESS!

EDIT: this is my storyboard enter image description here

EDIT2:

full stack track:

* thread #1: tid = 0x4a37c, 0x0000000197bb7bd0 libobjc.A.dylib`objc_msgSend + 16, queue = 'com.apple.main-thread', stop reason = EXC_BAD_ACCESS (code=1, address=0x10)
    frame #0: 0x0000000197bb7bd0 libobjc.A.dylib`objc_msgSend + 16
    frame #1: 0x000000018ab52078 UIKit`-[UITabBarController _tabBarItemClicked:] + 104
    frame #2: 0x000000018a9891ec UIKit`-[UIApplication sendAction:to:from:forEvent:] + 96
    frame #3: 0x000000018ab51fb4 UIKit`-[UITabBar _sendAction:withEvent:] + 468
    frame #4: 0x000000018a9891ec UIKit`-[UIApplication sendAction:to:from:forEvent:] + 96
    frame #5: 0x000000018a9722c8 UIKit`-[UIControl _sendActionsForEvents:withEvent:] + 612
    frame #6: 0x000000018ab51bec UIKit`-[UITabBar(Static) _buttonUp:] + 128
    frame #7: 0x000000018a9891ec UIKit`-[UIApplication sendAction:to:from:forEvent:] + 96
    frame #8: 0x000000018a9722c8 UIKit`-[UIControl _sendActionsForEvents:withEvent:] + 612
    frame #9: 0x000000018a988b88 UIKit`-[UIControl touchesEnded:withEvent:] + 592
    frame #10: 0x000000018a947da8 UIKit`_UIGestureRecognizerUpdate + 8536
    frame #11: 0x0000000185e8fff0 CoreFoundation`__CFRUNLOOP_IS_CALLING_OUT_TO_AN_OBSERVER_CALLBACK_FUNCTION__ + 32
    frame #12: 0x0000000185e8cf7c CoreFoundation`__CFRunLoopDoObservers + 360
    frame #13: 0x0000000185e8d35c CoreFoundation`__CFRunLoopRun + 836
    frame #14: 0x0000000185db8f74 CoreFoundation`CFRunLoopRunSpecific + 396
    frame #15: 0x000000018f8136fc GraphicsServices`GSEventRunModal + 168
    frame #16: 0x000000018a9bad94 UIKit`UIApplicationMain + 1488
  * frame #17: 0x0000000100023ff4 toaster-objc`main(argc=1, argv=0x000000016fdeba50) + 124 at main.m:14
    frame #18: 0x000000019824ea08 libdyld.dylib`start + 4
Maximus S
  • 10,759
  • 19
  • 75
  • 154
  • What is your hierarchy? TabBarViewController -> NavigationController? – Miknash Sep 07 '15 at 12:41
  • @NickCatib Yes. Each tabItem is connected to a NavigationController. – Maximus S Sep 07 '15 at 12:42
  • see this link may be helps you http://stackoverflow.com/questions/21017985/call-poptorootviewcontroller-from-another-tab – Anbu.Karthik Sep 07 '15 at 12:43
  • Shouldn't you cast viewController to UINavigationController and then pop it? – Miknash Sep 07 '15 at 12:43
  • I tried doing that (the way @coder1010's answer describes), and this is what happens: 1. go to recent tab 2. click post to go to PostsShowview 3. go to popular tab 4. go back to recent tab 5. I see a list of posts (no error!) 6. go back to popular tab : ERR_BAD_ACCESS! – Maximus S Sep 07 '15 at 13:10
  • I figured the `pop` function is called even after the `delegate` is set to nil. – Maximus S Sep 07 '15 at 13:59

3 Answers3

4

Here is how I did it in swift:

func tabBarController(tabBarController: UITabBarController, didSelectViewController viewController: UIViewController) {

    self.tabBarSelectedIndex = tabBarController.selectedIndex
    var navigation = viewController as! UINavigationController
    navigation.popToRootViewControllerAnimated(false)
    // rest of the logic
}

Similar in objective-C:

- (void)tabBarController:(UITabBarController *)tabBarController didSelectViewController:(UIViewController *)viewController {
    self.tabBarSelectedIndex = tabBarController.selectedIndex;
    UINavigationController *navigation = (UINavigationController*) viewController;
    [navigation popToRootViewControllerAnimated:NO];
}

Notice that I used didSelectViewController method for UITabBarController.

You can check it here:

Anbu.Karthik
  • 82,064
  • 23
  • 174
  • 143
Miknash
  • 7,888
  • 3
  • 34
  • 46
  • Thanks for your answer. Please see my updated question. – Maximus S Sep 07 '15 at 13:15
  • This could happen because you have UINavigationController on one and not on the other tab. You can do this pop only for certain selectedIndex, i.e. if (tabBarController.selectedIndex == 0) cast to navigation and pop. – Miknash Sep 07 '15 at 13:17
  • Also, you could enable exception breakpoint to be sure where it is crashing. – Miknash Sep 07 '15 at 13:20
  • It's happening at `UIApplicationMain`. All the tabs are connected to their own navigation controllers. – Maximus S Sep 07 '15 at 13:27
  • 1
    Yes, because it is the main thread that actually catches it. If you try this: http://stackoverflow.com/questions/17802662/exception-breakpoint-in-xcode you will get where it is failing in tabbar exactly. Also, you can write 'bt' in the console after crash occurs so you can see full stacktrace – Miknash Sep 07 '15 at 13:28
  • I still wasn't able to figure out why this was happening, so I updated it with more information. – Maximus S Sep 07 '15 at 13:37
  • Your crash occurs you click on the button - that means it actually occurs in uitabbarcontroller - again if you add exception breakpoint you will see where exactly. other then that seems like you are accessing dead object. Please try to add exception breakpoint and then see where exactly is it failling. Also, do you have tabBarItemClicked method implemented – Miknash Sep 07 '15 at 14:01
  • I think I got a lead thanks to your help. It seems `popRootVC` function is called even after I set `self.tabBarController.delegate = nil`. I thought once I set the delegate to nil, `didSelectViewController` shouldn't be called anymore. Is it not true? So the exact problem is that `popping` happens twice when it should happen only once. – Maximus S Sep 07 '15 at 14:05
  • I am not sure what are you trying to achieve with setting delegate to nil, but yeah, it should be calling didSelectViewController. you can check for the amount of view controllers before poping with navigation.viewControllers, it is an array of the stack – Miknash Sep 07 '15 at 14:11
  • Let us [continue this discussion in chat](http://chat.stackoverflow.com/rooms/89006/discussion-between-maximus-s-and-nickcatib). – Maximus S Sep 07 '15 at 14:13
  • I ended up creating a separate class that subclasses UITabBarController and made that the delegate. – Maximus S Sep 07 '15 at 17:26
  • great, glad I helped :) – Miknash Sep 07 '15 at 17:26
0

Try This:

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

if ([viewController isKindOfClass:[UINavigationController class]])
{
    UINavigationController *navController = (UINavigationController *)viewController;

    [navController popToRootViewControllerAnimated:NO];

}
}
Bhavin Bhadani
  • 22,224
  • 10
  • 78
  • 108
coder1010
  • 412
  • 5
  • 15
  • Thanks for your answer. Please see my updated question. – Maximus S Sep 07 '15 at 13:15
  • May be you do not have navigationcontroller on popular tab. Please try adding below if condition as i mentioned in my answer if ([viewController isKindOfClass:[UINavigationController class]]) – coder1010 Sep 07 '15 at 13:29
  • I do (please see the updated question), and I tried adding the condition too :( – Maximus S Sep 07 '15 at 13:49
0
- (void)tabBarController:(UITabBarController *)tabBarController didSelectViewController:(UIViewController *)viewController
{
    if ([viewController isKindOfClass:[UINavigationController class]]) {
        [(UINavigationController *)viewController popToRootViewControllerAnimated:YES];
    }
}
John
  • 525
  • 3
  • 14