简体   繁体   中英

iOS 11: “Unable to simultaneously satisfy constraints”

always running into the FoodTracker tutorial; following this step: "Implement a custom control"

https://developer.apple.com/library/content/referencelibrary/GettingStarted/DevelopiOSAppsSwift/ImplementingACustomControl.html#//apple_ref/doc/uid/TP40015214-CH19-SW1

and when executing the first checkpoint the simulator shows a red rectangle instead of a square as indicated on the tutorial; on the debug pane I get:

2018-02-09 11:19:42.130595+0100 FoodTracker[7439:80369] [MC] Lazy loading NSBundle MobileCoreServices.framework  
2018-02-09 11:19:42.131628+0100 FoodTracker[7439:80369] [MC] Loaded MobileCoreServices.framework  
2018-02-09 11:19:42.165143+0100 FoodTracker[7439:80369] [LayoutConstraints] 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.  
(  
    "<NSLayoutConstraint:0x60400028a3c0 UIButton:0x7f8a0bd0e330.width == 44   (active)>",  
    "<NSLayoutConstraint:0x60400028cda0 'UISV-canvas-connection' FoodTracker.RatingControl:0x7f8a0bd08890.leading == UIButton:0x7f8a0bd0e330.leading   (active)>",  
    "<NSLayoutConstraint:0x60400028ce40 'UISV-canvas-connection' H:[UIButton:0x7f8a0bd0e330]-(0)-|   (active, names: '|':FoodTracker.RatingControl:0x7f8a0bd08890 )>",  
    "<NSLayoutConstraint:0x60400028c940 'UIView-Encapsulated-Layout-Width' FoodTracker.RatingControl:0x7f8a0bd08890.width == 200   (active)>"  
)  

Will attempt to recover by breaking constraint  
<NSLayoutConstraint:0x60400028a3c0 UIButton:0x7f8a0bd0e330.width == 44   (active)>  

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.  
2018-02-09 11:19:42.165949+0100 FoodTracker[7439:80369] [LayoutConstraints] 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.  
(  
    "<NSLayoutConstraint:0x60400028a370 UIButton:0x7f8a0bd0e330.height == 44   (active)>",  
    "<NSLayoutConstraint:0x60400028a320 'UISV-canvas-connection' FoodTracker.RatingControl:0x7f8a0bd08890.top == UIButton:0x7f8a0bd0e330.top   (active)>",  
    "<NSLayoutConstraint:0x60400028cf30 'UISV-canvas-connection' V:[UIButton:0x7f8a0bd0e330]-(0)-|   (active, names: '|':FoodTracker.RatingControl:0x7f8a0bd08890 )>",  
    "<NSLayoutConstraint:0x60400028c990 'UIView-Encapsulated-Layout-Height' FoodTracker.RatingControl:0x7f8a0bd08890.height == 110   (active)>"  
)  

Will attempt to recover by breaking constraint  
<NSLayoutConstraint:0x60400028a370 UIButton:0x7f8a0bd0e330.height == 44   (active)>  

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.  

I think that something is changed when programmatically create the button and applying custom constraints here: (I'm working with Swift and Xcode 9)

// Add constraints  
button.translatesAutoresizingMaskIntoConstraints = false  
button.heightAnchor.constraint(equalToConstant: 44.0).isActive = true  
button.widthAnchor.constraint(equalToConstant: 44.0).isActive = true  

Any hint to solve the issue is welcome.

Please note that I'm building a custom control... All the notes I've found googling around seems not to be applicables.

Epilogue

The issue disappeared himself.

Proceeding with the excercise, Xcode IDE underlined some critical points on the view design where I was invited to "click on the icon" to fix; one of this issue was tied to the conflicting contrains.

As suggested by #DonMag, the RatingControl class has to be marked as @IBDesignable (this decorator will be added later on the excercise) to let Xcode immediately view the final result of the custom control. Almost: The stars doesn't appeared and the control doesn't automatically scale adding stars to the control property. This until I closed, opened again and rebuilt several times the whole project.

Differences on tutorial (written for Swift 3.2) and actual Xcode (default project opened in Swift 4 applies.

It's my idea that Apple has to update it's own online documentation to avoid people loose their mind trying to figure out why things doesn't work like expected.

Ignore my first two comments...

In that tutorial, you are adding the custom ratingControl as an arranged subview of a Vertical Stack View. That's why no constraints are needed.

The key is making the class @IBDesignable - that allows Interface Builder and the Auto-Layout engine to use the class' intrinsic size to properly size / position / display it.

(Just a little surprising it's not noted in the tutorial.)

I had the same issue. Also, the red squares appeared bigger than shown in the tutorial. For the red squares to accept the constraints of size 44, I had to ensure the RatingControl was positioned inside the stack view, not below.

I'm attaching images for clarification of what I mean by "inside" the stack view.

error reproduced, please note red rectangle outside the stack view hierarchy

error fixed, the red rectangle is inside the stack view hierarchy on the left

The issue is happening because of the total width of all sub views is not equal to the width of StackView.

Using this calculation can fix the problem:

let width = (self.frame.width - self.spacing * CGFloat(starCount-1))/CGFloat(starCount)
let height = self.frame.height

............

for _ in 0..<starCount {
        let button = UIButton()
        button.translatesAutoresizingMaskIntoConstraints = false
        button.backgroundColor = UIColor.red
        button.heightAnchor.constraint(equalToConstant: height).isActive = true
        button.widthAnchor.constraint(equalToConstant: width).isActive = true
        button.addTarget(self, action: #selector(RatingControl.ratingButtonTapped(button:)), for: .touchUpInside)
        addArrangedSubview(button)
    }

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM