2

Im building slider inside UIAlertController and it actually worked fine on iPhone but gives breaking constraint error on iPad, i gave the alert 140 of height as constraint before presenting.

Here is my code:

let alertController = UIAlertController(title:"Title", message: "", preferredStyle: UIAlertControllerStyle.Alert)
let slider = UISlider(frame: CGRectMake(35, 50, 200, 20))
alertController.view.addSubview(slider)

let height:NSLayoutConstraint = NSLayoutConstraint(item: alertController.view, attribute: NSLayoutAttribute.Height, relatedBy: NSLayoutRelation.Equal, toItem: nil, attribute: NSLayoutAttribute.NotAnAttribute, multiplier: 1, constant: 140)
alertController.view.addConstraint(height);

alertController.addAction(UIAlertAction(title: "close", style: UIAlertActionStyle.Cancel, handler: { (error) -> Void in

}))

self.presentViewController(alertController, animated: true, completion: nil)

The error:

Unable to simultaneously satisfy constraints.
    Probably at least one of the constraints in the following list is one you don't want. Try this: (1) look at each constraint and try to figure out which you don't expect; (2) find the code that added the unwanted constraint or constraints and fix it. (Note: If you're seeing NSAutoresizingMaskLayoutConstraints that you don't understand, refer to the documentation for the UIView property translatesAutoresizingMaskIntoConstraints) 
(
    "<NSLayoutConstraint:0x7b555900 V:[_UIAlertControllerView:0x788d2a60'Title'(140)]>",
    "<NSLayoutConstraint:0x789db3f0 V:[_UIAlertControllerView:0x788d2a60'Title'(1024)]>"
)

Will attempt to recover by breaking constraint 
<NSLayoutConstraint:0x789db3f0 V:[_UIAlertControllerView:0x788d2a60'Title'(1024)]>

Make a symbolic breakpoint at UIViewAlertForUnsatisfiableConstraints to catch this in the debugger.
The methods in the UIConstraintBasedLayoutDebugging category on UIView listed in <UIKit/UIView.h> may also be helpful.
Nata Mio
  • 2,168
  • 3
  • 22
  • 46
  • Running into the same problem myself - it is almost as if the documentation which says, “Should be used AS-IS” is the final word. The only solution that works on both platforms is putting “\n\n\n” in the title. – Lloyd Sargent Jul 21 '16 at 14:38

1 Answers1

0

Okay, I have an answer, but you’re not going to like it.

If you do the following (with no constraints added):

print("Alert frame" + String(alertController.view.frame))
self.presentViewController(alertController, animated: true, completion: nil)

You will get the following:

Alert frame(0.0, 0.0, 768.0, 1024.0)

Which just happens to be the iPad Air’s width and height in portrait mode. Okay, that’s obviously not the views width and height. Let’s modify our code a bit.

self.presentViewController(alertController, animated: true)
{
    print("Alert frame" + String(alertController.view.frame))
}

This time I get the following:

Alert frame(0.0, 0.0, 300.0, 85.5)

Please note that I have two “\n\n” in my title. So let us ASSUME they are doing something funky prior to presenting it (remember Apple tells us this is an opaque class).

So let’s add the following:

self.presentViewController(alertController, animated: true)
{
    let height:NSLayoutConstraint = NSLayoutConstraint(item: alertController.view,
                                            attribute: NSLayoutAttribute.Height,
                                            relatedBy: NSLayoutRelation.Equal,
                                            toItem: nil,
                                            attribute: NSLayoutAttribute.NotAnAttribute,
                                            multiplier: 1,
                                            constant: self.view.frame.height * 1.20)
    alertController.view.addConstraint(height);

}

Now, cross our fingers for luck, and see what happens.

Unable to simultaneously satisfy constraints.

This suggests, to me, that Apple has constraints on the iPad that it does not on the iPhone. When we toss in our height constraint we have set up a situation where the internal constraint code is attempting to solve for two conflicting commands. As such, it can only do so by breaking the constraints.

I’m using .ActionSheet but I’m getting the same issue. It appears that Apple doesn’t use constraints for the iPhone. If you aren’t building a universal app, then you should be fine.

However, and this is important, Apple could impose constraints on the iPhone in the future which could cause the same issue.

The bottom line is this:

The UIAlertController class is intended to be used as-is and does not support subclassing. The view hierarchy for this class is private and must not be modified.

To me, Apple should be far more explicit and say, “We do not support modifications at all.” I suspect they think the “as-is” covers it, but as you have probably seen (as I have) many people don’t test all cases.

As such, I plan to look for a third party version that supports both the iPhone and iPad (see UIAlertController - add custom views to actionsheet - it is a similar issue.

Wasting my time on something that could break in an interim release of iOS is not worth it.

Community
  • 1
  • 1
Lloyd Sargent
  • 599
  • 4
  • 13
  • i will check it out ^_^ – Nata Mio Jul 24 '16 at 13:58
  • I’m filing a bug report that Apple’s documentation really needs to clarify that there should be no (as in zero) attempts to modify UIAlertController (whether subclassed or not). This includes, but is not limited to, adding constraints, etc. – Lloyd Sargent Jul 25 '16 at 18:09
  • I guess it should be subclassed, you can imagine a scrollView and you need to add things into it, without customizing its none since to use it. nothing is wrong with that i guess !! – Nata Mio Jul 26 '16 at 11:14
  • UIAlertController **does not support subclassing per Apple documentation** - ideally, you would make your own class that would have the look and feel. But you can **not use** UIAlertController as a base class. – Lloyd Sargent Jul 27 '16 at 15:05
  • Hmm actually you are right, i have checked that in apple documentation. and it will be just easier to add my own class. – Nata Mio Jul 28 '16 at 07:59
  • Be aware that UIAlertController looks different on an iPad vs iPhone. Also, iPhone looks different depending if it is portrait or landscape. It gets complicated really fast if you are building a universal app. Good luck! – Lloyd Sargent Jul 28 '16 at 16:42
  • Also please check this as answering your question. Thanks! – Lloyd Sargent Jul 28 '16 at 16:44