How do I sizeToFit a UILabel by changing only the height and not the width?

You can achieve the same result with sizeThatFits.

CGSize size = [label sizeThatFits:CGSizeMake(label.frame.size.width, CGFLOAT_MAX)];
CGRect frame = label.frame;
frame.size.height = size.height;
label.frame = frame;

Or alternatively, with sizeToFit.

CGRect frame = label.frame;
[label sizeToFit];
frame.size.height = label.frame.size.height;
label.frame = frame;

This is how it is done. Because the label already contains the font information, including it in this method call is trivial.

CGSize size = [label.text sizeWithFont:label.font
                     constrainedToSize:CGSizeMake(maxWidth, MAXFLOAT)
                         lineBreakMode:UILineBreakModeWordWrap]; 
CGRect labelFrame = label.frame;
labelFrame.size.height = size.height;
label.frame = labelFrame;

Swift version using the more up-to-date boundingRectWithSize:

let maxHeight = CGFloat.infinity
let rect = label.attributedText?.boundingRectWithSize(CGSizeMake(maxWidth, maxHeight), 
       options: .UsesLineFragmentOrigin, context: nil)
var frame = label.frame
frame.size.height = rect.size.height
label.frame = frame