AutoLayout, Unable to simultaneously satisfy constraints
Asked Answered
T

6

32

Just started learning iOS AutoLayout, Interface builder very straight forward, but when I try to archive the same thing on the code

    [self.view addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:@"H:|-(==2)-[_nextKeyboardButton]-(==2)-[_numPadButton]-(==2)-[_spaceButton]-(==2)-[_returnButton]-(==2)-|" options:0 metrics:0 views:NSDictionaryOfVariableBindings(_nextKeyboardButton,_numPadButton,_spaceButton,_returnButton)]];

it raises an exception,

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:0x6000000966c0 H:|-(2)-[UIButton:0x7fe4f1d1c760'Next']   (Names: '|':UIInputView:0x7fe4f1f04d00 )>",
 "<NSLayoutConstraint:0x600000096710 H:[UIButton:0x7fe4f1d1c760'Next']-(2)-[UIButton:0x7fe4f1d1d1d0'123']>",
 "<NSLayoutConstraint:0x600000096760 H:[UIButton:0x7fe4f1d1d1d0'123']-(2)-[UIButton:0x7fe4f1d1d6f0'Space']>",
 "<NSLayoutConstraint:0x6000000967b0 H:[UIButton:0x7fe4f1d1d6f0'Space']-(2)-[UIButton:0x7fe4f1d1d8d0'Return']>",
 "<NSLayoutConstraint:0x600000096800 H:[UIButton:0x7fe4f1d1d8d0'Return']-(2)-|   (Names: '|':UIInputView:0x7fe4f1f04d00 )>",
 "<NSLayoutConstraint:0x600000096e40 'UIView-Encapsulated-Layout-Width' H:[UIInputView:0x7fe4f1f04d00(0)]>"
 )

Will attempt to recover by breaking constraint
<NSLayoutConstraint:0x6000000967b0 H:[UIButton:0x7fe4f1d1d6f0'Space']-(2)-[UIButton:0x7fe4f1d1d8d0'Return']>

All 4 buttons .translatesAutoresizingMaskIntoConstraints = NO;

I wonder what is wrong ? help is really appreciated :)

FYI: I work on iOS8 SDK

Timberhead answered 2/9, 2014 at 18:52 Comment(7)
Seems like a perfectly logical set of constraints. I have been bashing my head over something similar for the past few DAYS. Btw, @Chamira Fernando are there any other width constraints on the buttons? Intrinsic content size etc? Have you tried setting the compressionResistancePriority or contentHuggingPriority to high or low values? Just see what happens?Aronarondel
The reason for the constraint failure is obviously caused by the width of UIView-Encapsulated-Layout-Width being 0. Where is the UIInputView located?Wilona
Silly me - I didn't see that (0). I had the same issue. It's a UIInputView provided by a UIInputViewController - root view of a Keyboard extension (iOS8). I don't know why it would want a width of 0, considering the default behavior (according to the docs) should be to stick to the width of the screen.Aronarondel
@DevKanchen is right here, the UIInputView being zero is the problem , technically by default it should at least get the size of available space for keyboard. but it doesn't. So i have to get the default keyboard sizes based on device type and initial UIInputView in viewDidLoad method.Timberhead
Have a look on this answer too- #11664615Decreasing
Add this line in code. view.translatesAutoresizingMaskIntoConstraints = NO;Premonish
hi @ChamiraFernando - you should tick the amazing answer below (the highly voted one)....Unwieldy
P
87

The easiest way how to find unsatisfiable constraints:

  • set unique identifier for every constraint in your view:

enter image description here

  • create simple extension for NSLayoutConstraint:

SWIFT:

extension NSLayoutConstraint {

    override public var description: String {
        let id = identifier ?? ""
        return "id: \(id), constant: \(constant)" //you may print whatever you want here
    }
}

OBJECTIVE-C

@interface NSLayoutConstraint (Description)

@end

@implementation NSLayoutConstraint (Description)

-(NSString *)description {
    return [NSString stringWithFormat:@"id: %@, constant: %f", self.identifier, self.constant];
}

@end
  • build it once again, and now you have more readable output for you:

enter image description here

  • once you got your id you can simple tap it in your Find Navigator:

enter image description here

  • and quickly find it:

enter image description here

HOW TO SIMPLE FIX THAT CASE?

  • try to change priority to 999 for broken constraint.

See the related answer here: Unable to simultaneously satisfy constraints, will attempt to recover by breaking constraint

Proximity answered 5/8, 2015 at 13:5 Comment(6)
This is the most useful thing I've ever read for debugging constraint issues. Hands down. Thank you!Veii
I agree that this is the best tip ever for constraint debugging. Thanks, Bartlmiej.Dynamite
Thank you for saving me an estimated 5 hours of my lifeDeformation
Thank you .very very important post for me .Pettitoes
really , this is very useful ,Thank youPettis
To set this identifier programmatically, constraint.identifier = "anIdentifierForTheConstraint", where constraint is first defined as e.g. let constraint = imageView.centerYAnchor.constraint(equalTo: layout.centerYAnchor)Yukyukaghir
A
8

I had to struggle with similar problem when I was trying to manually create all the auto layout constraints (in Swift, using Snappy - a Masonry port to Swift) in a view controller that is based on a Storyboard.

For some reason, Xcode generates own default set of auto layout constraints on a NIB at build time. This is why I couldn't add any more manual constraints, because they were conflicting with the automatically added ones.

I resolved this the following way:

  • Open up the Storyboard view controller you're handling.

  • Select the view controller and select Editor > Resolve Auto Layout Issues > All Views in [ ] View Controller > Add Missing Constraints from the menu:

enter image description here

(This will ensure that no additional build time constraints are created and all the constraints are now visible.)

  • Select all the constraints from your view controller:

enter image description here

  • Check from the right pane the following check box: Placeholder - Remove at build time:

enter image description here

Now you can add all the auto layout constraints manually in the code.

Agulhas answered 23/9, 2014 at 7:50 Comment(2)
This sorted the problem out perfectly for me.Kamalakamaria
I ran into a similar problem, I have seven UIButtons aligned in a row. In StoryBoard everything is fine, but when I build it, I got a lot of "Unable to simultaneously satisfy constraints" exceptions, but it looks fine on the simulator. I'm wondering if I should do something about them or not? And if I do, I can't use the editor to resolve constraint issues because there aren't any in my StoryBoard.Amateur
L
3

It may be not so difficult.The message console output says that the UIButton's constraints redefined.It means just like that you put a constraint that restrict the Height and the Width of the button, but needlessly you put another restriction that the button has a Aspect Ratio.In this condition Xcode can't make sure which constraint to follow,so that you can see this debug message in console.

There are two ways Useful for me:

  1. Analyse the constraints displayed in the console,and try to delete one or more constraint.

2.If you are using the storyboard or Xib ,Select a constraint ->Show the Attributes Inspector -> change the priority of some Constraints.


One more thing...

You can follow the article of Jason Jarrett. Add a symbol breakpoint to make sure which view make the error happen.

Lalittah answered 24/8, 2015 at 6:39 Comment(0)
A
3

In case anyone else runs into this, an easy way to visually check for problems with your constraints is this site (it's really useful!):

http://www.wtfautolayout.com

Here's the Github project in case the site goes down: https://github.com/johnpatrickmorgan/wtfautolayout

Acaudal answered 4/9, 2017 at 20:27 Comment(1)
While this link may answer the question, it is better to include the essential parts of the answer here and provide the link for reference. Link-only answers can become invalid if the linked page changesClutch
M
2

According to your question what i’ve understood that you have created control in nib and you are directly trying to change is constraints from your class.

What you can do here is set constraints in nib for view controller and then bind it with your class and use objects of constraints. Or you can create view programmatically and directly set the constraints.

// You also need to check that whether you need to “translatesAutoresizingMaskIntoConstraints” if “YES - the view’s superview looks at the view’s autoresizing mask, produces constraints that implement it, and adds those constraints to itself (the superview).” and if “NO - the view’s superview does not looks at the view’s autoresizing mask, and not produces constraints that implement it.”

I also got same issue and I fixed it as following

     [_nextKeyboardButton setTranslatesAutoresizingMaskIntoConstraints:YES];
    _numPadButton.translatesAutoresizingMaskIntoConstraints = YES;
    [_numPadButton updateConstraints];
    [_nextKeyboardButton updateConstraints];

    NSArray *constraints2 = [NSLayoutConstraint
                             constraintsWithVisualFormat:@"H:|-57-[_nextKeyboardButton(96)]"
                             options:0
                             metrics:nil
                             views:NSDictionaryOfVariableBindings(_nextKeyboardButton)];

    [self.view addConstraints:constraints2];

    NSArray *constraints4 = [NSLayoutConstraint
                             constraintsWithVisualFormat:@"V:|-123-[_nextKeyboardButton(30)]"
                             options:0
                             metrics:nil
                             views:NSDictionaryOfVariableBindings(_nextKeyboardButton)];

    [self.view addConstraints:constraints4];

    NSArray *constraints1 = [NSLayoutConstraint
                             constraintsWithVisualFormat:@"H:|-207-[_numPadButton(58)]"
                             options:0
                             metrics:nil
                             views:NSDictionaryOfVariableBindings(_numPadButton)];

    [self.view addConstraints:constraints1];

    NSArray *constraints3 = [NSLayoutConstraint
                             constraintsWithVisualFormat:@"V:|-123-[_numPadButton(30)]"
                             options:0
                             metrics:nil
                             views:NSDictionaryOfVariableBindings(_numPadButton)];

    [self.view addConstraints:constraints3];

// Create Controls  or view programmatically.

UILabel *label = [UILabel new];
    label.text = @"This is a Label";
    label.font = [UIFont systemFontOfSize:18];
    label.backgroundColor = [UIColor lightGrayColor];
    label.translatesAutoresizingMaskIntoConstraints = NO;
    [self.view addSubview:label];

    NSArray *constraints = [NSLayoutConstraint
                            constraintsWithVisualFormat:@"V:|-offsetTop-[label(100)]"
                            options:0
                            metrics:@{@"offsetTop": @100}
                            views:NSDictionaryOfVariableBindings(label)];
    [self.view addConstraints:constraints];

    UIView *spacer1 = [UIView new];
    spacer1.translatesAutoresizingMaskIntoConstraints = NO;
    [spacer1 setBackgroundColor:[UIColor redColor]];
    [self.view addSubview:spacer1];

    UIView *spacer2 = [UIView new];
    spacer2.translatesAutoresizingMaskIntoConstraints = NO;
    [spacer2 setBackgroundColor:[UIColor greenColor]];
    [self.view addSubview:spacer2];

    NSArray *constraints1 = [NSLayoutConstraint
                            constraintsWithVisualFormat:@"V:|-offsetTop-[spacer1(100)]"
                            options:0
                            metrics:@{@"offsetTop": @100}
                            views:NSDictionaryOfVariableBindings(spacer1)];

    [self.view addConstraints:constraints1];

    NSArray *constraints2 = [NSLayoutConstraint
                             constraintsWithVisualFormat:@"V:|-offsetTop-[spacer2(100)]"
                             options:0
                             metrics:@{@"offsetTop": @100}
                             views:NSDictionaryOfVariableBindings(spacer2)];

    [self.view addConstraints:constraints2];

    [self.view addConstraints:[NSLayoutConstraint
                               constraintsWithVisualFormat:@"H:|[spacer1]-10-[label]-20-[spacer2(==spacer1)]|"
                               options:0
                               metrics:nil
                               views:NSDictionaryOfVariableBindings(label, spacer1, spacer2)]];

    So when using AutoLayout, you should never directly set the frame of a view. Constraints are used to do this for you. Normally if you want to set your own constraints in a view, you should override the updateConstraintsmethod of your UIViews. Make sure the content views for the page controller allow for their edges to be resized since they will be sized to fit the page view's frame. Your constraints and view setup will need to account for this, or you you will get unsatisfiable constraint errors.

https://developer.apple.com/library/mac/documentation/userexperience/conceptual/AutolayoutPG/AutoLayoutConcepts/AutoLayoutConcepts.html#//apple_ref/doc/uid/TP40010853-CH14-SW1 You can also refer above link of apple to in-depth study and if you still face issue i’ll be try my level best to solve you issue.  

Minny answered 20/9, 2014 at 11:37 Comment(0)
I
0

I solved my problem with NSLayoutConstraint.deactivate(MystackView.constraints)

Ignazio answered 16/6, 2020 at 14:59 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.