Calling popToRootViewControllerAnimated causing crash. How should I be doing this?
- by Lewis42
The app is for taking body measurements. The user can say I want to measure: legs, arms and neck, in the settings tab and in the main tab there is a view which loops round to take each measurement.
This is achieved like so:
i have tab controller
the first tab has a navigation controller
the first view controller on the storyboard and has one segue to itself
the board loops round until it has all the measurements then it segues to a different controller
the problem is: if the user changes which measurements they are taking in the settings tab, the first tab needs to completely reload, as if the app was just starting up, clearing down the whole nav stack etc.
at the moment the tab controller calls popToRootViewControllerAnimated on the navigation controller in the measurements tab, but this is causing a crash. Each screen has a slider control and a call to titleForRow:forComponent: is being called on a deleted view causing it to crash.
What am I doing wrong?!
Here's the tab bar controller code
// TabBarController.m
//
#import "TabBarController.h"
#import "TodaysMeasurementObject.h"
#import "AppDelegateProtocol.h"
#import "AddMeasurementViewController.h"
#import "ReadPerson.h"
#import "AppDelegate.h"
@interface TabBarController () <UITabBarControllerDelegate>
@end
@implementation TabBarController
bool resetWizardView = false;
- (id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil
{
self = [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil];
if (self) {
}
return self;
}
- (void)viewDidLoad
{
[super viewDidLoad];
// Do any additional setup after loading the view.
self.delegate = self;
[[UIDevice currentDevice] beginGeneratingDeviceOrientationNotifications];
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(orientationChanged:)
name:UIDeviceOrientationDidChangeNotification object:nil];
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(measurementsSettingsUpdated:) name:@"MeasurementsSettingsUpdated" object:nil];
}
- (void) measurementsSettingsUpdated:(NSNotification *) notification
{
// UINavigationController *navigationController = [self.viewControllers objectAtIndex:0];
// AddMeasurementViewController *addMeasurement = [[AddMeasurementViewController alloc] init];
// [navigationController setViewControllers: [[NSArray alloc] initWithObjects:addMeasurement, nil]];
resetWizardView = YES;
}
- (void) viewDidAppear:(BOOL)animated
{
if (![ReadPerson userHasRecords]) {
[self setSelectedIndex:3];
}
}
- (void)orientationChanged:(NSNotification *)notification
{
// We must add a delay here, otherwise we'll swap in the new view
// too quickly and we'll get an animation glitch
[self performSelector:@selector(showGraphs) withObject:nil afterDelay:0];
}
- (void)showGraphs
{
UIDeviceOrientation deviceOrientation = [UIDevice currentDevice].orientation;
if (deviceOrientation == UIDeviceOrientationLandscapeLeft && !isShowingLandscapeView)
{
[self performSegueWithIdentifier: @"toGraph" sender: self];
isShowingLandscapeView = YES;
}
else if (deviceOrientation != UIDeviceOrientationLandscapeLeft && isShowingLandscapeView)
{
[self dismissModalViewControllerAnimated:YES];
isShowingLandscapeView = NO;
}
}
- (void)viewDidUnload
{
[super viewDidUnload];
// Release any retained subviews of the main view.
}
- (void)dealloc
{
[[NSNotificationCenter defaultCenter] removeObserver:self];
[[UIDevice currentDevice] endGeneratingDeviceOrientationNotifications];
}
- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation
{
if(interfaceOrientation == UIInterfaceOrientationLandscapeRight)
{
[self performSegueWithIdentifier: @"toGraph" sender: self];
}
return false;
}
- (void)tabBarController:(UITabBarController *)tabBarController didSelectViewController:(UIViewController *)viewController {
int tbi = tabBarController.selectedIndex;
if (tbi == 0) {
[[viewController view] setNeedsDisplay];
if (resetWizardView) {
[(UINavigationController*)[self.viewControllers objectAtIndex:0] popToRootViewControllerAnimated: NO]; // ******* POP CALLED HERE ******
resetWizardView = false;
}
}
}
- (TodaysMeasurementObject*) theAppDataObject
{
id<AppDelegateProtocol> theDelegate = (id<AppDelegateProtocol>) [UIApplication sharedApplication].delegate;
TodaysMeasurementObject* theDataObject;
theDataObject = (TodaysMeasurementObject*) theDelegate.theAppDataObject;
return theDataObject;
}
- (BOOL)shouldAutorotate {
return NO;
}
- (NSUInteger)supportedInterfaceOrientations {
return UIInterfaceOrientationMaskPortrait;
}
@end
UPDATED
- (void) measurementsSettingsUpdated:(NSNotification *) notification
{
NSMutableArray *viewControllers = [[NSMutableArray alloc] initWithArray: self.viewControllers];
UINavigationController *navigationController = [viewControllers objectAtIndex:0];
AddMeasurementViewController *addMeasurement = [[AddMeasurementViewController alloc] init];
[navigationController setViewControllers: [[NSArray alloc] initWithObjects:addMeasurement, nil]];
[viewControllers setObject:navigationController atIndexedSubscript:0];
self.viewControllers = viewControllers;
}
and removed the code from
- tabBarController:didSelectViewController:
but still the same error. I think the problem is that it's trying to get a value for the slide control after the view has been deleted. But some part of the view must still be alive...? Anyway to kill that off? Or leave it all alive??