I have a custom cell with dynamic height inside an XIB file that shows a message with a message and image. Since the image will be loaded asynchronously from my API, the aspect ratio of the image will be sent with the resource. Inside the method, updateConstraintsa restriction of the aspect ratio with the corresponding factor will be established.
XIB file:

Cell class:
import UIKit
import Alamofire
class PostTableViewCell: UITableViewCell {
@IBOutlet weak var userProfileImageView: TFImageView!
@IBOutlet weak var usersNameLabel: UILabel!
@IBOutlet weak var usernameLabel: UILabel!
@IBOutlet weak var userProfileButton: TFCellButton!
@IBOutlet weak var distanceLabel: UILabel!
@IBOutlet weak var messageLabel: UILabel!
@IBOutlet weak var postImageView: UIImageView!
@IBOutlet weak var likeCountLabel: UILabel!
@IBOutlet weak var timestampLabel: UILabel!
@IBOutlet weak var likeButton: UIButton!
@IBOutlet weak var constraintBetweenMessageLabelAndPostImageView: NSLayoutConstraint!
var post: Post! {
didSet {
post.author.profileImage(version: .Thumbnail) { image, _ in
self.userProfileImageView.image = image
}
if let name = post.author.fullName {
usersNameLabel.text = name
usernameLabel.text = post.author.username
} else {
usersNameLabel.text = post.author.username
usernameLabel.hidden = true
}
if let attributedMessage = post.attributedMessage {
messageLabel.attributedText = attributedMessage
messageLabel.hidden = false
constraintBetweenMessageLabelAndPostImageView.constant = 15
} else {
messageLabel.hidden = true
messageLabel.attributedText = nil
constraintBetweenMessageLabelAndPostImageView.constant = 0
}
post.image { image, _ in
if let image = image {
self.postImageView.image = image
self.setNeedsUpdateConstraints()
}
}
timestampLabel.text = "Posted \(post.createdAt.timeAgoSinceNow())"
distanceLabel.text = post.distanceText
likeCountLabel.text = "\(post.likesCount) Likes"
likeButton.setImage(post.likeButtonImage, forState: .Normal)
}
}
override func updateConstraints() {
if let aspectRatio = post.imageAspectRatio {
postImageAspectConstraint = NSLayoutConstraint(item: postImageView, attribute: NSLayoutAttribute.Width, relatedBy: NSLayoutRelation.Equal, toItem: postImageView, attribute: NSLayoutAttribute.Height, multiplier: CGFloat(aspectRatio), constant: 0)
}
super.updateConstraints()
}
func setupUserProfileButton(indexPath: NSIndexPath, viewController: UIViewController) {
userProfileButton.indexPath = indexPath
userProfileButton.addTarget(viewController, action: "userProfileButtonDidTouch:", forControlEvents: .TouchUpInside)
}
var postImageAspectConstraint: NSLayoutConstraint? {
didSet {
if let oldValue = oldValue {
postImageView.removeConstraint(oldValue)
}
if let postImageAspectConstraint = postImageAspectConstraint {
postImageView.addConstraint(postImageAspectConstraint)
}
}
}
override func prepareForReuse() {
super.prepareForReuse()
postImageAspectConstraint = nil
}
}
Method cellForRowAtIndexPath:
func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCellWithIdentifier("postCell", forIndexPath: indexPath) as! PostTableViewCell
cell.post = posts[indexPath.row]
cell.setupUserProfileButton(indexPath, viewController: self)
return cell
}
When the application starts, everything works as expected, but if I wave it a little, it leads to a break, and the aspect of the images is no longer right or some other strange things, as shown below:

Errors:
2015-09-28 11:58:27.546 Lome[32812:528936] 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:0x7f8a008bf6f0 V:[Lome.TFImageView:0x7f8a008bf470(35)]>",
"<NSLayoutConstraint:0x7f89f9fbc490 V:|-(15)-[Lome.TFCellButton:0x7f8a0087fde0] (Names: '|':UITableViewCellContentView:0x7f8a008bf270 )>",
"<NSLayoutConstraint:0x7f8a00831520 Lome.TFCellButton:0x7f8a0087fde0.top == Lome.TFImageView:0x7f8a008bf470.top>",
"<NSLayoutConstraint:0x7f8a008315c0 Lome.TFCellButton:0x7f8a0087fde0.bottom == Lome.TFImageView:0x7f8a008bf470.bottom>",
"<NSLayoutConstraint:0x7f8a00831750 V:[Lome.TFCellButton:0x7f8a0087fde0]-(18)-[UILabel:0x7f8a008806d0'Water']>",
"<NSLayoutConstraint:0x7f8a00831840 H:|-(0)-[UIImageView:0x7f8a00830910] (Names: '|':UITableViewCellContentView:0x7f8a008bf270 )>",
"<NSLayoutConstraint:0x7f8a00831890 H:[UIImageView:0x7f8a00830910]-(0)-| (Names: '|':UITableViewCellContentView:0x7f8a008bf270 )>",
"<NSLayoutConstraint:0x7f8a008318e0 V:[UILabel:0x7f8a008806d0'Water']-(15)-[UIImageView:0x7f8a00830910]>",
"<NSLayoutConstraint:0x7f8a00831930 V:[UIImageView:0x7f8a00830910]-(20)-[UILabel:0x7f8a00830b90'0 Likes']>",
"<NSLayoutConstraint:0x7f8a00831980 V:[UILabel:0x7f8a00830b90'0 Likes']-(20)-| (Names: '|':UITableViewCellContentView:0x7f8a008bf270 )>",
"<NSLayoutConstraint:0x7f8a00860870 UIImageView:0x7f8a00830910.width == 0.6672*UIImageView:0x7f8a00830910.height>",
"<NSLayoutConstraint:0x7f8a0084e990 'UIView-Encapsulated-Layout-Height' V:[UITableViewCellContentView:0x7f8a008bf270(611)]>",
"<NSLayoutConstraint:0x7f8a0084f930 'UIView-Encapsulated-Layout-Width' H:[UITableViewCellContentView:0x7f8a008bf270(375)]>"
)
Will attempt to recover by breaking constraint
<NSLayoutConstraint:0x7f8a008bf6f0 V:[Lome.TFImageView:0x7f8a008bf470(35)]>
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.
2015-09-28 11:58:27.547 Lome[32812:528936] 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:0x7f89f9fbc490 V:|-(15)-[Lome.TFCellButton:0x7f8a0087fde0] (Names: '|':UITableViewCellContentView:0x7f8a008bf270 )>",
"<NSLayoutConstraint:0x7f8a00831520 Lome.TFCellButton:0x7f8a0087fde0.top == Lome.TFImageView:0x7f8a008bf470.top>",
"<NSLayoutConstraint:0x7f8a008315c0 Lome.TFCellButton:0x7f8a0087fde0.bottom == Lome.TFImageView:0x7f8a008bf470.bottom>",
"<NSLayoutConstraint:0x7f8a00831750 V:[Lome.TFCellButton:0x7f8a0087fde0]-(18)-[UILabel:0x7f8a008806d0'Water']>",
"<NSLayoutConstraint:0x7f8a00831840 H:|-(0)-[UIImageView:0x7f8a00830910] (Names: '|':UITableViewCellContentView:0x7f8a008bf270 )>",
"<NSLayoutConstraint:0x7f8a00831890 H:[UIImageView:0x7f8a00830910]-(0)-| (Names: '|':UITableViewCellContentView:0x7f8a008bf270 )>",
"<NSLayoutConstraint:0x7f8a008318e0 V:[UILabel:0x7f8a008806d0'Water']-(15)-[UIImageView:0x7f8a00830910]>",
"<NSLayoutConstraint:0x7f8a00831930 V:[UIImageView:0x7f8a00830910]-(20)-[UILabel:0x7f8a00830b90'0 Likes']>",
"<NSLayoutConstraint:0x7f8a00831980 V:[UILabel:0x7f8a00830b90'0 Likes']-(20)-| (Names: '|':UITableViewCellContentView:0x7f8a008bf270 )>",
"<NSLayoutConstraint:0x7f8a00860870 UIImageView:0x7f8a00830910.width == 0.6672*UIImageView:0x7f8a00830910.height>",
"<NSLayoutConstraint:0x7f8a0084e990 'UIView-Encapsulated-Layout-Height' V:[UITableViewCellContentView:0x7f8a008bf270(611)]>",
"<NSLayoutConstraint:0x7f8a0084f930 'UIView-Encapsulated-Layout-Width' H:[UITableViewCellContentView:0x7f8a008bf270(375)]>"
)
Will attempt to recover by breaking constraint
<NSLayoutConstraint:0x7f8a00860870 UIImageView:0x7f8a00830910.width == 0.6672*UIImageView:0x7f8a00830910.height>
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.
, - , , prepareForReuse.
, .
, - .
.