I am trying to use a default AlertViewController with style .actionSheet. For some reason, the alert causes a constraint error. As long as
The solution for Objective-C:
Define prune-function like in previous reply
@implementation TemplateAlertController
-(void) viewDidLoad {
[super viewDidLoad];
[self mPruneNegativeWithConstraints];
}
-(void) mPruneNegativeWithConstraints {
for (UIView* iSubview in [self.view subviews]) {
for (NSLayoutConstraint* iConstraint in [iSubview constraints]) {
if ([iConstraint.debugDescription containsString:@"width == - 16"]) {
[iSubview removeConstraint:iConstraint];
}
}
}
}
@end
It's a new bug in iOS versions:
The only thing we can do is to file a bug report to Apple (I just did that and you should too).
I'll try to update answer for a new version(s) of iOS when it come out.
You should not remove the constraint because it is used in the future with a correct value.
As an alternative, you can change its constant to a positive value:
class PXAlertController: UIAlertController {
override func viewDidLoad() {
super.viewDidLoad()
for subview in self.view.subviews {
for constraint in subview.constraints {
if constraint.firstAttribute == .width && constraint.constant == -16 {
constraint.constant = 10 // Any positive value
}
}
}
}
}
And then to initialize your controller use:
let controller = PXAlertController(title: "Title", message: "Message", preferredStyle: .actionSheet)
Interesting ideas here. Personally I don't like the idea of deleting the constraint or changing it's value (size).
As the issue hinges on the constraint resolution being forced into a position where it must break a mandated (priority 1000) constraint, a less brutal approach is just to tell the framework that this constraint could be broken if needed.
So (based on Josh's "Safe" class):
class PXAlertController: UIAlertController {
override func viewDidLoad() {
super.viewDidLoad()
tweakProblemWidthConstraints()
}
func tweakProblemWidthConstraints() {
for subView in self.view.subviews {
for constraint in subView.constraints {
// Identify the problem constraint
// Check that it's priority 1000 - which is the cause of the conflict.
if constraint.firstAttribute == .width &&
constraint.constant == -16 &&
constraint.priority.rawValue == 1000 {
// Let the framework know it's okay to break this constraint
constraint.priority = UILayoutPriority(rawValue: 999)
}
}
}
}
}
This has the advantages that it doesn't change any layout dimensions, it also stands a good chance of being well behaved in the event of a fix in the framework.
Tested in iPhone SE simulator (which was giving me my original problem) - constraint related debug has gone.
An alternative way of getting away from the NSLayoutConstraint bug, is to use preferredStyle: .alert
instead of preferredStyle: .actionSheet
. This works without generating warnings, but it will display the menu modally.
The following removes the warning without needing to disable animation. And assuming Apple eventually fixes the root cause of the warning, it shouldn't break anything else.
extension UIAlertController {
func pruneNegativeWidthConstraints() {
for subView in self.view.subviews {
for constraint in subView.constraints where constraint.debugDescription.contains("width == - 16") {
subView.removeConstraint(constraint)
}
}
}
}
This can then be used like this:
// After all addActions(...), just before calling present(...)
alertController.pruneNegativeWidthConstraints()