Everything was fine with iOS7 and Xcode and 5 - and after the upgrade to Xcode 6 and so iOS8, there is a sudden crash in the application where it was always working fine.
The error shown when it crashes is:
Terminating app due to uncaught exception
'UIViewControllerHierarchyInconsistency', reason: 'adding a root view
controller as a child of view
controller:'
I managed to find the single line creating the issue:
[self.navigationController
popToViewController:[self.navigationController.viewControllers
objectAtIndex:4] animated:YES];
The app adds views up to 8 whilst doing the exercise ; and when the exercise is done, just coming back to the last view which was the menu of the exercise so 4. A bit hard-coded but simple and efficient as it is always the case.
and I have no idea was the popToViewController is doing that.
Any help or thoughts would be greatly appreciated.
I finally found a solution that works - so here it is before for completion / records:
UINavigationController* savedUinvc = self.navigationController;
UIViewController *one = nil;
one = [savedUinvc popViewControllerAnimated:NO];
UIViewController *two = nil;
two = [savedUinvc popViewControllerAnimated:NO];
UIViewController *three = nil;
three = [savedUinvc popViewControllerAnimated:YES];
Related
I have been working on app for months without any popover issues. All of a sudden today popovers have gone to hell.
I have tried this a few different ways and no matter when I dismiss the popover by pressing a button in the popover OR tapping outside of the popover the app crashes.
Using Instruments, I can see there is a zombie reference that only happens after the popover has been dismissed:
*** -[UITransitionView willRemoveSubview:]: message sent to deallocated instance 0x7f9985bcd980
So I have logged that stack and there isn't much help as the whole stack has to do with UIKit and built in animations, etc.
Using standard UIPopovers
self.popover = [[UIPopoverController alloc] initWithContentViewController:self.navVC];
self.popover.backgroundColor = [UIColor accentColor];
self.popover.delegate =self;
[self.seatingChartPopover presentPopoverFromRect:CGRectMake(x,y, 1, 1)
inView:self.view permittedArrowDirections:UIPopoverArrowDirectionAny animated:YES];
Or use the new UIPopoverPresentationController method in ios8
self.navVC.modalPresentationStyle = UIModalPresentationPopover;
UIPopoverPresentationController* popover = self.navVC.popoverPresentationController;
self.navVC.preferredContentSize = [self.childVC preferredContentSize];
popover.sourceView = self.view;
popover.sourceRect = CGRectMake(x,y, 1, 1);
popover.permittedArrowDirections = UIPopoverArrowDirectionAny;
[self presentViewController:self.seatingChartNavController animated:YES completion:nil];
I have made sure that all of the view controllers involved have a strong reference.
As I mentioned, I have not changed the the code that presents this popover in months and it's been working fine until today. I have spent hours debugging this to no avail.
Also, If I just present self.navVC as a normal modal view, the view displays fine and dismisses fine. It's only when it's set as a popover that it fails
Thanks in advance for any help.
I'm ashamed to admit that I accidentally put a dealloc method in one of my UIView Categories.
I am surprised this didn't bring up any sort of compiler warning, but after removing that there hasn't been any more bizarre crashing.
I'm dealing with an odd error around an UISplitViewController
I created a library in order to deal with ViewControllers presentation and reuse code as much as possible. Within this code I instantiate ViewControllers using their storyboard IDs and I'm using to switch a ViewController with a SplitViewController.
Despite it works fine in iOS 8, it crashes in iOS 7 with this error.
Storyboard (<UIStoryboard: 0x7f94bb52ccd0>) doesn't contain a view controller with identifier 'MySplitViewControllerIdentifier'
The code where this happens is this
+(UIViewController *) instantiateStoryboard:(UIStoryboard *) storyboard
withViewIdentifier:(NSString *) identifier
{
#try {
if ([identifier isEqualToString:#""] || identifier == nil) {
return [storyboard instantiateInitialViewController];
}
else {
//HERE IT CRASHES !!!!!!
return [storyboard instantiateViewControllerWithIdentifier:identifier];
}
}
#catch (NSException *exception) {
NSLog(ERROR_NO_VIEWCONTROLLER_FOUND, [self class], identifier, storyboard.description);
}
}
I checked several times the config of this SplitViewController on my storyboard and the Storyboard ID is correct. If it helps, this SplitViewController is not subclassed.
Someone dealt with something similar?
Thanks
Well, I'm a little stupid xD
UISplitViewController supports iPhone in iOS 8 and later, but i was trying in iOS 7 simulator.
EDIT
But here comes the weird thing. Actually UISplitViewController is supported in iPhone with iOS 7, and it works IF IT'S THE INITIAL VIEW CONTROLLER. If you try to load after, as i tried in my question, you'll get the same error.
So I change my initial View Controller to my UISplitViewController and, when need it, I change my root view controller. I can came back to my SplitViewController because [storyboard instantiateInitialViewController] works fine in this case.
Thanks for your time
I'm currently working on a custom ViewController that manages at least one and up to five ViewController. They are aligned in a "plus", where the mandatory view controller is the center ViewController, and the other four can go on any side of the centre ViewController. The class is TDSlidingViewController in this project.
The problem I'm running into regards what view controllers are being passed into animateTransition. The following is the code preparing to transition (it's inside TDSlidingViewController.m):
targetViewController.transitioningDelegate = self;
targetViewController.modalPresentationStyle = UIModalPresentationNone;
if (_currentViewController == [self.slidingControllerDatasource viewControllerForLocation:SlidingViewCenter]) {
[_currentViewController presentViewController:targetViewController animated:YES completion:^(void) {
NSLog(#"%#\n%#\n%#", self.childViewControllers, self.view.subviews, self.currentViewController.childViewControllers);
[self.currentViewController.view addGestureRecognizer:[self gestureRecognizersForSlidingViewLocation:self.currentLocation][0]];
}];
} else {
[[self.slidingControllerDatasource viewControllerForLocation:self.previousLocation] dismissViewControllerAnimated:YES completion:^{}];
}
The following code runs in animateTransition:
UIView *container = transitionContext.containerView;
UIViewController *currentViewController = [transitionContext viewControllerForKey:UITransitionContextFromViewControllerKey];
UIViewController *targetViewController = [transitionContext viewControllerForKey:UITransitionContextToViewControllerKey];
NSLog(#"%#", [currentViewController class]);
What caught my attention is that NSLog is not printing the _currentViewController, but the container for the SlidingViewController, TDMainViewController; the transition removes the entire stack of ViewController and displays one ViewController.
I believe it is causing [[self.slidingControllerDatasource viewControllerForLocation:self.previousLocation] dismissViewControllerAnimated:YES completion:^{}]; to crash with the following output (TDEditorViewController is the controller that was displayed from the transition initially):
*** Terminating app due to uncaught exception 'UIViewControllerHierarchyInconsistency', reason: 'presentedViewController for controller is itself on dismiss for: <`TDEditorViewController`: 0x8d69250>'
I have searched and searched, and the only link I can find that is similar is this, which has not been answered.
Any help would be greatly, greatly appreciated.
So I researched a little bit more, and came to the conclusion that the flaw was in the design. Instead of trying to present view controllers inside of a container view, I simply passed the gestures around so it knows when to move back to the center. The StackViewController that was originally going to be the container view, now facilitates the transitions from the background, holding the gesture recognizers, managing animations and passing around data. All that's changed is it's not displayed.
I am using a storyboard to switch between views. Pretty simple, until I try to add ECSlidingViewController.
If I add the above slide menu to the first view I call using this:
self.topViewController = [self.storyboard instantiateViewControllerWithIdentifier:#"Main"];
If I set #"Main" to #"Speakers", the view loads just fine. I get the slide menu and everything. #"Main" also loads just fine.
However, if I load #"Main" first like in the code above, then switch views to the one I've designated "Speakers", it crashes as soon as I try to call the slide menu with this code:
if(![self.slidingViewController.underLeftViewController isKindOfClass:[MenuViewController class]]) {
self.slidingViewController.underLeftViewController = [self.storyboard instantiateViewControllerWithIdentifier:#"Menu"];
}
[self.view addGestureRecognizer:self.slidingViewController.panGesture];
I get a crash stating: * Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: '* -[__NSArrayM insertObject:atIndex:]: object cannot be nil'
I have tried switching views numerous ways.
I've tried:
SpeakersView *second= [self.storyboard instantiateViewControllerWithIdentifier:#"Speakers"];
[self presentViewController:second animated:YES completion:nil];
I've tried:
SpeakersView *svc = [self.storyboard instantiateViewControllerWithIdentifier:#"Speakers"];
[self presentViewController:svc animated:YES completion:nil];
Each one works just fine if I don't call up the slide menu, but each causes a crash when I do add the slide gesture.
Ideas?
Okay, I figured it out. After a long, arduous experience, I figured it out.
So I've got numerous files (.m and .h for each):
InitViewController
MenuViewController
MainViewController
SpeakersView
The objective was to switch from MainViewController using a button not on the slide menu to SpeakersView, but doing it directly caused the slide menu to be null, as was pointed out by Phillip Mills.
Instead, I put this in InitViewController.h, right underneath #Interface:
#property (nonatomic, retain) NSString *location;
Then this under #implementation in InitViewController.m:
#synthesize location;
I originally had this under ViewDidLoad in InitViewController.m:
self.topViewController = [self.storyboard instantiateViewControllerWithIdentifier:#"Main"];
I changed it to this:
if([location length] == 0){location = #"Main";}
self.topViewController = [self.storyboard instantiateViewControllerWithIdentifier:location];
That way if the variable was empty, it defaulted to #"Main".
Then in MainView.m, where I execute the code after pressing the button, I have this:
InitViewController *ini;
ini = [self.storyboard instantiateViewControllerWithIdentifier:#"Init"];
ini.location = #"Speakers";
And voilĂ , the view switches just fine to Speakers. More accurately, it switches to InitViewController which automatically switches to Speakers or whatever I set location to.
Thanks to everyone for your help.
In myAppDelegate.m:
MainViewController *mainViewController = [ [MainViewController alloc] init];
UINavigationController *navController = [[UINavigationController alloc]
initWithRootViewController:mainViewController];
[navController setNavigationBarHidden:YES];
[[self window] setRootViewController:navController];
In MainViewController.m nothing special, just one action tied to a button:
- (IBAction)go:(id)sender {
if (!whereamiViewController)
{
whereamiViewController = [[WhereamiViewController alloc] init];
}
[[self navigationController] pushViewController:whereamiViewController animated:YES];
}
And in WhereamiViewController.m just a button to show another screen in UINavigationViewController:
-(IBAction)showList:(id)sender
{
PointsViewController *container = [[PointsViewController alloc] init];
[[self navigationController] pushViewController:container animated:YES];
}
And:
#interface PointsViewController : UITableViewController
#end
Everything fine. But when I land on the last screen, PointsViewController, and I go back on WhereamiView, the app freeze, and Xcode shows a trap at CoureFoundation, CFHas.
Now, I know that Objective-C is not php, but this is a simple example indeed: what am I missing? There is a method to debug the problem?
The debugger says:
Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: '- [__NSCFType _forgetDependentConstraint:]: unrecognized selector sent to instance
This morning I ran the app inside the simulator and no crashes!! How is it possible? If I run inside the iPhone crash, in the simulator no crash.
Tim is right. Popping the PointsViewController is the way I would do it, too.
What does your Xcode saying? Can you provide the content of the debugger?
That would be more helpful to track down what's going wrong.
[PARTIALLY SOLVED]
This is very strange: After debugging everything and deleting every suspicious declaration, nothing improved. Same crash SIGABRT. After rebooting both iPhone and Mac, everything is fine!
I am not really seeing where the problem is as it occurs outside of the code you have posted. I may be missing something, but if the app crashes when you go back to whereamiViewController, how do you actually go back? I am not seeing where it's detailed here.
With navigationControllers like this, you would push (to add) or pop (to remove) viewControllers to move up and down the navcontroller tree. As it is at this point that the app seems to be crashing, it may be worth postings how you are dong this? Where are you popping the container (PointsViewController *).
From the code you've posted, I suspect you may be trying to move back to the whereamiViewController by re-pushing it again.