0

My app has a tab bar controller, one of the tab items is a split view controller. It's master view controller (ie. at index 0) is a navigation controller loaded from a nib, due to it's custom navbar.

If that sounds a bit obscure, well it's down to a combination of 1) not being able to add an SVC to a TBC in IB and 2) the iOS 4.2 splitview-navbar-colorTint bug. And indeed, it's only since implementing the workaround yesterday that I've been experiencing a problem with low memory warnings.

Before the workaround I was initting the SVC with 2 nav controllers and adding it to the TBC all programatically (due to IB's restricions with th tab bar) and without and problems - well, except for that apple bug.

The little workaround demo also works fine, even after low memory warnings. But it doesn't involve the additional overhead of a tab bar.

But in my adaption of the workaround demo it starts to all go pear shaped. Send a low memory warning whilst showing the split view and the whole left side (master view) disappears. Behaviour identical on device, in fact I first discovered it there.

I'm puzzled what's going on. The view on display (the nav cont's root view) is controlled by a table view subclass. I've overridden didReceiveMemoryWarning but that doesn't help. Furthermore (correspondingly!), the superview isn't nil. It's a UITableView. Perfectly correct.

So, I'm thinking the nav controller is getting released? But where? And why not in the original demo? The difference now is the addition of my tab bar controller. Here's my code that adds it to the tab bar:

- (void) addTabItemSplitViewWithNavConRoot:(BOOL)hasRootNC {

    // init master/detail views 
    SV1RootViewController *rvc = [[SV1RootViewController alloc] initWithNibName:@"SVC1RootView" bundle:nil];
    SV1DetailViewController *dvc = [[SV1DetailViewController alloc] initWithNibName:@"SVC1DetailView" bundle:nil];

    rvc.detailViewController = dvc;

    UINavigationController *nc = nil;
    if (hasRootNC) {
        nc = [self.pSVC1.viewControllers objectAtIndex:0];
        nc.viewControllers = [NSArray arrayWithObjects:rvc, nil];
        nc.navigationBar.tintColor = [UIColor redColor];
    } else {
        nc = nil;
    }

    UIViewController *vc = (hasRootNC)? (UIViewController*)nc :rvc;

    UISplitViewController *svc = [self newSplitViewControllerWithMasterVC:vc detailVC:dvc];
    svc.delegate = dvc;

    // init the tab bar item
    svc.tabBarItem = [[UITabBarItem alloc] initWithTitle:(hasRootNC)? @"SplitView with Nav Root":@"Simple SplitView"
                                                   image:nil 
                                                     tag:0];    
    // int the split view
    NSMutableArray *controllersArray = [NSMutableArray arrayWithArray:self.pTabBarController.viewControllers];
    [controllersArray addObject:svc];
    [self.pTabBarController setViewControllers:controllersArray];

    // cleanup
    [nc release];
    [rvc release];
    [dvc release];
    [svc release];
}

- (UISplitViewController*) newSplitViewControllerWithMasterVC:(UIViewController*)masterView
                                                     detailVC:(UIViewController*)detailView {

    UISplitViewController *svc = [[UISplitViewController alloc] init];
    NSMutableArray *controllersArray = [NSMutableArray arrayWithObjects:masterView, detailView, nil];
    [svc setViewControllers:controllersArray];

    return svc;
}

Anybody have ideas for me please? :)

It's driving me insane!!!

Rich
  • 532
  • 3
  • 17

2 Answers2

1

Resolved it. Had sth to do with that wierd mix of programatically initialising a split view controller, but injecting it with a nav controller read from the main window xib (all because of the custom toolbar needed for the Apple bug). But my guess is that the nav controller from the xib was having it's view unloaded.

So now I just take the entire SVC from the nib, rather than construct it by hand. Much neater and much simpler actually.

Oh man. I was led astray by an answer to this question (the 'designated' answer!). I've now just noticed that this much simpler method is also given as an answer and is actually the most popular. Completely overlooked it! ^^

Community
  • 1
  • 1
Rich
  • 532
  • 3
  • 17
  • THANK YOU! I was going crazy with the exact same problem. As soon as I organized things with IB things started to work as they should. – Enrique R. Jul 04 '11 at 22:59
0

Without seeing all of the code, I'm guessing the inactive view is destroyed during the mem warning. (The bit of code that says 'didReceiveMemoryWarning', you probably have [super didReceiveMemoryWarning])

You need to make sure that in your loadView method, any subviews that need to be added are re-added to the view, and layed out accordingly. Hope that helps.

Or if you are in a rush or lazy, just prevent all the usual things from happening. This is possible bad and may cause a crash, but it's an alternate approach if you are impatient.

- (void)didReceiveMemoryWarning {
     //do nothing
    //[super didReceiveMemoryWarning];
}
Jackie Treehorn
  • 826
  • 1
  • 7
  • 5
  • As I wrote "I've overridden didReceiveMemoryWarning but that doesn't help. Furthermore (correspondingly!), the superview isn't nil. It's a UITableView. Correctly so." I didn't explicitly say, but yes I did remove the msg to super. – Rich Jan 20 '11 at 19:11
  • what does the loadView look like? And can you try reloading the UITableView there from datasource/delegate? Something like [self.tableView reloadData] ? – Jackie Treehorn Jan 20 '11 at 19:24
  • Hm.. The view is loaded from the nib SVC1RootView belonging to (SV1RootViewController*)rvc. In turn, rvc is written to (UINavigationController*)nc.viewControllers, which used to init the split view controller, assigned to a tabBarItem, added to the tab bar controller of MainWindow.xib, whose view is added to the window immediately after calling the above method. So I don't directly have a loadView to hook into. Or do I?!? – Rich Jan 20 '11 at 21:23
  • My vague idea is that the navigation controller, sourced from MainWindow.xib is being released? The UITableView is it's own datasource/delegate so where would I call reloadData? From didReceiveMemoryWarning? – Rich Jan 20 '11 at 21:31