1

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.

Shivam Tripathi
  • 1,405
  • 3
  • 19
  • 37
Francesco Piraneo G.
  • 882
  • 3
  • 11
  • 25
  • 1
    Possible duplicate of [What is NSLayoutConstraint "UIView-Encapsulated-Layout-Height" and how should I go about forcing it to recalculate cleanly?](https://stackoverflow.com/questions/25059443/what-is-nslayoutconstraint-uiview-encapsulated-layout-height-and-how-should-i) – Tamás Sengel Feb 09 '18 at 12:52
  • @the4kman - Unfortunately not... already studied. Note that the Button control has been programmatically created. – Francesco Piraneo G. Feb 09 '18 at 12:55
  • share your code with us – Milan Nosáľ Feb 09 '18 at 13:02
  • @MilanNosáľ - Consider that is a full Xcode project; a good resumee can be found at the indicated link without the risk that I miss to publish something important; what I think is that making the button 44 x 44 is conflicting with something predefined constant into the view. It's possible to programmatically set the width and height constraint priority to 1001, for example? – Francesco Piraneo G. Feb 09 '18 at 13:14
  • @FrancescoPiraneoG. I thought you are following a tutorial, and expected you are doing it on a clean project from the start. in that case, there should be no problem sharing that code. If otherwise (e.g., you are trying to add taht rating control to your own project), then you are not sharing enough information - at least you should include your full code of the rating control + all the relevant code that would give us a clue where and how you use it – Milan Nosáľ Feb 09 '18 at 13:16
  • 1
    It looks like you are constraining the button's edges to other elements, but then you're also trying to constrain the width and height. That won't work if the edges don't end up providing exactly the width and height values. – DonMag Feb 09 '18 at 13:24
  • Ah - in that point in the tutorial, it has not yet instructed you to add constraints for the Stack View. Either ignore it until you get further into the tutorial, or, for the time being, constrain the Stack View Leading to the `photoImageView` Leading, and the Stack View Top to the `photoImageView` Bottom (Vertical Spacing). – DonMag Feb 09 '18 at 13:40
  • Also note that a bit further into that section of the tutorial, you're instructed to make the `ratingControl` class `@IBDesignable` ... that will also get rid of the auto-layout constraint conflicts. – DonMag Feb 09 '18 at 13:44

4 Answers4

2

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.

Francesco Piraneo G.
  • 882
  • 3
  • 11
  • 25
1

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.)

DonMag
  • 69,424
  • 5
  • 50
  • 86
0

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

danim
  • 1
  • 2
0

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)
    }