Aleksandar • Vacić

iOS bits and pieces

Auto layout exception thrown when deleting UICollectionViewCell

I am preparing my main apps to be compatible with iOS 8 and upcoming new devices of possibly varying physical sizes. First order of business: remove any hard-coded 320 values in various places.

In Units convert (note: the upcoming version 3.0 will be called Unitica) I have a very complex cell in the favorites screen.

When you swipe over that cell, you get the option to remove that particular favorited pair; doing that triggers cell removal and adjustment of the position of cells below. And it throws this lovely exception doing that:

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:0xb940870 UILabel:0xb93f930.width == UILabel:0xb935aa0.width>",
    "<NSLayoutConstraint:0xb9421c0 UILabel:0xb93f930.width == 0.5*UIView:0xb9dbe40.width - 20>",
    "<NSLayoutConstraint:0xb9a6590 H:|-(0)-[UIView:0xb9dbe40]   (Names: '|':UIView:0xb93e5d0 )>",
    "<NSLayoutConstraint:0xb9c4030 H:|-(0)-[UIView:0xb93e5d0]   (Names: '|':RTFavoriteCellScrollView:0xb9ca7f0 )>",
    "<NSLayoutConstraint:0xb9e9270 RTFavoriteCellScrollView:0xb9ca7f0.leading == RTFavoriteCell:0xb944db0.leading>",
    "<NSAutoresizingMaskLayoutConstraint:0xb9e0d50 h=-&- v=-&- UIView:0xb91c8b0.midX == RTFavoriteCell:0xb944db0.midX>",
    "<NSAutoresizingMaskLayoutConstraint:0xb9e0d80 h=-&- v=-&- UIView:0xb91c8b0.width == RTFavoriteCell:0xb944db0.width>",
    "<NSLayoutConstraint:0xb91aaa0 UIView:0xb9dbe40.right == UIView:0xb91c8b0.right>",
    "<NSLayoutConstraint:0xb9271a0 'UIView-Encapsulated-Layout-Width' H:[RTFavoriteCell:0xb944db0(0)]>"

But – not always: it throws this exception only when there are enough cells that at least one is fully below the bottom edge of the screen. Meaning - the exception is thrown on the cell that will go up and thus appear on the screen.

The culprit: autoresizesSubviews=YES on the UICollectionViewCell.

Look at the last line in the exception report:

"<NSLayoutConstraint:0xb9271a0 'UIView-Encapsulated-Layout-Width' H:[RTFavoriteCell:0xb944db0(0)]>"

At this moment, width of the cell is 0, and since I have many subviews inter-dependent on each other, some of them become impossible to satisfy. My guess: it’s the constraint that unit symbol and name labels are equal to 50% of the cell width minus 40 (the padding on both sides) and that width then becomes -40pt, which is not allowed, hence the exception.

Thus, unchecking that checkbox in the .xib and all is fine.

Caveat: it’s worth noting that setting autoresizesSubviews=NO will disable size auto-adjustment of the cell subviews when the cell bounds change. For example, if you have a layout where one can pan around and change container sizes, then cell content will be oblivious to that.
In that case it’s worth revisiting your constraints and see is it possible to remove the dependence on the bounds size.