1

When I try to display a UIAlertController from my app, the app terminates with an exception UIViewControllerHierarchyInconsistency.

The View Controller is created with a storyboard

From Storyboard editor

I create and (try to) display the Alert like this:

UIAlertController *alert = [UIAlertController alertControllerWithTitle:@"Title" message:@"Message" preferredStyle:UIAlertControllerStyleAlert];
UIAlertAction *yesButton = [UIAlertAction actionWithTitle:@"Yes" style:UIAlertActionStyleDefault handler:^(UIAlertAction *action){
...    
}];
[alert addAction:yesButton];

[self presentViewController:alert animated:YES completion:nil];

However, during execution I get this in the output:

2016-08-25 09:46:07.536 TrackYou[10554:3165715] *** Terminating app due to uncaught exception 'UIViewControllerHierarchyInconsistency', reason: 'child view controller:<UICompatibilityInputViewController: 0x13f5afd80> should have parent view controller:<ViewController: 0x13f549360> but requested parent is:<UIInputWindowController: 0x140043c00>'

From the same ViewController I use the presentViewController to present a custom ViewController, which works fine.

SettingsViewController *controller = [SettingsViewController new];
[self presentViewController:controller animated:YES completion:nil];

Any ideas what's causing the problem?

Smorka
  • 1,077
  • 7
  • 13
  • possibly dupe of http://stackoverflow.com/questions/24029113/error-when-adding-input-view-to-textfield-ios-8 .. – vaibhav Aug 25 '16 at 11:46

2 Answers2

1

I also got this exception and my app crashed. In my case I used UIAlertController and customised the UI,so that UIAlertController will have a label and textfield side by side.

For custom UI of UIAlertController I used following code.

    let alert = UIAlertController(title: "your title",
                                  message: "your msg",
                                  preferredStyle: .alert)


    let inputFrame = CGRect(x: 0, y: 90, width: 300, height: 60)
    let inputView: UIView = UIView(frame: inputFrame);

    let prefixFrame = CGRect(x: 10, y: 5, width: 60, height: 30)
    let prefixLabel: UILabel = UILabel(frame: prefixFrame);
    prefixLabel.text = "your label text";

    let codeFrame = CGRect(x: 80, y: 5, width: 235, height: 30)
    let countryCodeTextField: UITextField = UITextField(frame: codeFrame);
    countryCodeTextField.placeholder = "placeholder text";
    countryCodeTextField.keyboardType = UIKeyboardType.decimalPad;

    let submitAction = UIAlertAction(title: "Submit", style: .default, handler: { (action) -> Void in

        // your code after clicking submit
    })

    let cancel = UIAlertAction(title: "Cancel", style: .destructive, handler: { (action) -> Void in })


    alert.addTextField { (textField) in
        textField.inputView = countryCodeTextField
    }


    inputView.addSubview(prefixLabel);
    inputView.addSubview(countryCodeTextField);


    alert.view.addSubview(inputView);

    alert.addAction(submitAction)
    alert.addAction(cancel)


    present(alert, animated: false, completion: nil)    

When I run this code,I got the exception

  *** Terminating app due to uncaught exception 'UIViewControllerHierarchyInconsistency', reason: 'child view controller:<UICompatibilityInputViewController: 0x13f5afd80> should have parent view controller:<ViewController: 0x13f549360> but requested parent is:<UIInputWindowController: 0x140043c00>'

Then I have removed the below code

  alert.addTextField { (textField) in
        textField.inputView = countryCodeTextField
    }

My exception gone and no more crash in my app.

Hope this is helpful for somebody. Sorry if it is not understandable,my English is not so good.

V.S
  • 79
  • 1
  • 5
0

I also stuck this problem and find the solution is that you should find the top view controller and present the alert on the top view controller.

Find the top view controller:

-(UIViewController *)getTopViewController{
            UIViewController *topController = [UIApplication sharedApplication].keyWindow.rootViewController;

        while (topController.presentedViewController) {
            topController = topController.presentedViewController;
        }
        if (![topController isKindOfClass:[NSNull class]]) {
            return topController;
    }

and present the alert on top view controller:

UIAlertController *alert = [UIAlertController alertControllerWithTitle:@"Title" message:@"Message" preferredStyle:UIAlertControllerStyleAlert];
UIAlertAction *yesButton = [UIAlertAction actionWithTitle:@"Yes" style:UIAlertActionStyleDefault handler:^(UIAlertAction *action){
...    
}];
[alert addAction:yesButton];

[[self getTopViewController] presentViewController:alert animated:YES completion:nil];
Saurabh Jain
  • 1,688
  • 14
  • 28