1

In my SDK 3.0 core data based app, I have a tab bar controller managing 4 tabs. From time to time, apparently randomly, when I launch the app, it crashes with the following message:

Terminating app due to uncaught exception 'NSInternalInconsistencyException', reason: 'Directly modifying a tab bar managed by a tab bar controller is not allowed.'

However, I am not modifying in my code any of the tabs except for the following. In practice, all of the navigation controllers or controllers in the tabs have been setup using IB, and in my code I have declared two of them as outlets, since I need to access them in my app delegate applicationDidFinishLaunching() method to setup their core data managedObjectContext as follows:

 [self managedObjectContext];
 [self managedObjectModel];
 [self persistentStoreCoordinator];
 [rootViewController retain];
 rootViewController.managedObjectContext = self.managedObjectContext;

Is this not correct? If so, why?

The only reference to the problem I have seen on the web is here:

http://discussions.apple.com/thread.jspa?messageID=9716886

However, the problem still persists even after deleting and recreating the tab bar controller from scratch in IB.

Any clue? Thanks in advance.

Massimo Cafaro
  • 25,429
  • 15
  • 79
  • 93

3 Answers3

5

I've had this problem too. Do you have an outlet to the UITabBar itself (not the UITabBarController) in the nib? When I removed that, I stopped having problems.

Sorry this isn't a 100% reliable explanation, but this workaround cleared the problem up for me.

Fraser Speirs
  • 4,642
  • 3
  • 21
  • 15
1

I've gotten this exception a few times, especially when changing things with localizations. Cleaning the targets and then rebuilding seems to work around the issue.

Isaac
  • 11
  • 1
  • Yes, I also noticed this. Recently I had to add again an outlet to the UITabBar, and I started facing the problem again. I hope Apple will fix this, meanwhile the most important thing is that applications do not crash at runtime on actual devices. – Massimo Cafaro Aug 28 '09 at 07:48
  • Do NOT let this bug exist in your code. My game HexaLex hit this bug once every few hundred builds. I wasn't able to figure out a permanent fix but I didn't worry about it too much since it was so rare. Naturally, my App Store build for v1.0 was affected, utterly ruining my launch. After that happened I dug in and realized that at some point I'd connected an outlet to the UITabBar in Interface Builder. Heed my warning: stay FAR FAR away from the UITabBar! – n8gray Nov 30 '09 at 21:45
1

I quickly wrote the following class and showing/hiding tab views from UITabBarController worked like magic:

TabBarDesigner.h

#import <Foundation/Foundation.h>
@interface TabBarDesigner : NSObject 
{

}

+(void) setTabBarController:(UITabBarController *)tabBarController
                      items:(NSArray *)tabBarItems 
            viewControllers:(NSArray *)viewControllers;

+(void) removeItemsInRange:(NSRange) range;

@end

TabBarDesigner.m

#import "TabBarDesigner.h"

static NSArray *_tabBarItems = NULL;
static NSArray *_viewControllers = NULL;
static UITabBarController *_tabBarController = NULL;

@implementation TabBarDesigner

+(void) setTabBarController:(UITabBarController *)tabBarController
                      items:(NSArray *)tabBarItems 
            viewControllers:(NSArray *)viewControllers
{
    if (tabBarItems && viewControllers && tabBarController)
    {
        if ([tabBarItems count] == [viewControllers count])
        {
            [_tabBarItems release];
            [_viewControllers release];
            _tabBarItems = [tabBarItems copy];
            _viewControllers = [viewControllers copy];
            _tabBarController = tabBarController;
        }
    }
}

+(void) removeItemsInRange:(NSRange) range
{
    if (_tabBarController)
    {
        if ( range.location < ([_tabBarItems count] - 1) )
        {
            if ( (range.length + range.location) < [_tabBarItems count] )
            {
                NSMutableArray *tabBarItems = [_tabBarItems mutableCopy];   
                [tabBarItems removeObjectsInRange:range];
                NSMutableArray *viewControllers = [_viewControllers mutableCopy];
                [viewControllers removeObjectsInRange:range];
                [_tabBarController setViewControllers:viewControllers];
                 NSUInteger i;
                for (i = 0; i< [viewControllers count]; i++) 
                {
                    UIViewController *vC = [viewControllers objectAtIndex:i];
                    vC.tabBarItem.image = [[tabBarItems objectAtIndex:i] image];
                    vC.tabBarItem.title = [[tabBarItems objectAtIndex:i] title];
                    vC.tabBarItem.tag = [[tabBarItems objectAtIndex:i] tag];
                }

                [tabBarItems release];
                [viewControllers release];

            }


        }
    }
}


@end

A sample of how to use this class: In your MyAppDelegate.m

#import "TabBarDesigner.h"
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
    [TabBarDesigner setTabBarController:_tabBarController
                                  items:[_tabBarController.tabBar items] 
                        viewControllers:[_tabBarController viewControllers]];
    // remove the first 3 tabs
    [TabBarDesigner removeItemsInRange:NSMakeRange(0,3)];
    // show all tabs
    [TabBarDesigner removeItemsInRange:NSMakeRange(0,0)];
    // continue with your code
}

Cheers!

Raunak
  • 3,314
  • 1
  • 22
  • 28