In iOS 7, sizeWithFont:
is now deprecated. How do I now pass in the UIFont object into the replacement method sizeWithAttributes:
?

- 10,710
- 4
- 28
- 38
20 Answers
Use sizeWithAttributes:
instead, which now takes an NSDictionary
. Pass in the pair with key UITextAttributeFont
and your font object like this:
CGRect rawRect = {};
rawRect.size = [string sizeWithAttributes: @{
NSFontAttributeName: [UIFont systemFontOfSize:17.0f],
}];
// Values are fractional -- you should take the ceil to get equivalent values
CGSize adjustedSize = CGRectIntegral(rawRect).size;

- 4,752
- 2
- 38
- 38

- 10,710
- 4
- 28
- 38
-
60when working with an `NSString` and a `UILabel` (not ALWAYS the case, but often so), to prevent duplicated code/etc, you can also replace `[UIFont systemFontOfSize:17.0f]` with `label.font` - helps code maintenance by referencing existing data vs. you typing it multiple times or referencing constants all over the place, etc – toblerpwn Oct 30 '13 at 21:38
-
8@toblerpwn it's possible the label doesn't exist and you're trying to calculate a theoretical label. – botbot Dec 18 '13 at 02:28
-
5How would I use this example to get the size.height with a label that got a fixed width of for example 250? OR if its a label with autolatyout witch takes up a procentage of the width and I go to landscapemode. – Pedroinpeace Dec 18 '13 at 15:55
-
12@Pedroinpeace You would use `boundingRectWithSize:options:attributes:context:` instead, passing in `CGSizeMake(250.0f, CGFLOAT_MAX)` in most cases. – James Kuang Dec 18 '13 at 16:07
-
9Something else to note sizeWithAttributes: is not 100% equivalent. sizeWithFont used to round up the sizes to integer (pixel) values. Suggest use ceilf on the resultant height/width or you may get blurry artefacts (esp non retina HW) if you use this for positional calculations. – Nick Hingston Jul 16 '14 at 08:17
-
What about word wrap, how to add that? – jjxtra Nov 21 '14 at 21:36
-
@PsychoDad you would use `boundingRectWithSize:options:attributes:context:` like mentioned in a previous comment. – James Kuang Nov 21 '14 at 23:06
-
Are we sure ceiling function is the right function to use? I always thought fractional pixels were rounded not ceiling or floored— I may be wrong though. – Albert Renshaw Dec 05 '14 at 18:03
-
1@AlbertRenshaw Yes, according to Apple documentation "This method returns fractional sizes; to use a returned size to size views, you must raise its value to the nearest higher integer using the `ceil` function." (https://developer.apple.com/library/ios/documentation/UIKit/Reference/NSString_UIKit_Additions/index.html#//apple_ref/occ/instm/NSString/sizeWithAttributes:) – James Kuang Dec 05 '14 at 19:34
-
@incyc thank you for the reference! :D Much more confident in my code now! – Albert Renshaw Dec 05 '14 at 20:11
-
3No need to introduce another variable for ceiling. `size = CGSizeMake(ceilf(size.width), ceilf(size.height));` – martinjbaker Dec 16 '14 at 12:57
-
1@martinjbaker The extra variable is for clarity and the comment for purposes of demonstration. However someone chooses to structure their code should be up to them. – James Kuang Dec 16 '14 at 14:12
-
thanks martinjbaker, the adjustedSize variable actually confused me, until I saw your comment. – Elijah Jan 03 '15 at 14:54
I believe the function was deprecated because that series of NSString+UIKit
functions (sizewithFont:...
, etc) were based on the UIStringDrawing
library, which wasn't thread safe. If you tried to run them not on the main thread (like any other UIKit
functionality), you'll get unpredictable behaviors. In particular, if you ran the function on multiple threads simultaneously, it'll probably crash your app. This is why in iOS 6, they introduced a the boundingRectWithSize:...
method for NSAttributedString
. This was built on top of the NSStringDrawing
libraries and is thread safe.
If you look at the new NSString
boundingRectWithSize:...
function, it asks for an attributes array in the same manner as a NSAttributeString
. If I had to guess, this new NSString
function in iOS 7 is merely a wrapper for the NSAttributeString
function from iOS 6.
On that note, if you were only supporting iOS 6 and iOS 7, then I would definitely change all of your NSString
sizeWithFont:...
to the NSAttributeString
boundingRectWithSize
. It'll save you a lot of headache if you happen to have a weird multi-threading corner case! Here's how I converted NSString
sizeWithFont:constrainedToSize:
:
What used to be:
NSString *text = ...;
CGFloat width = ...;
UIFont *font = ...;
CGSize size = [text sizeWithFont:font
constrainedToSize:(CGSize){width, CGFLOAT_MAX}];
Can be replaced with:
NSString *text = ...;
CGFloat width = ...;
UIFont *font = ...;
NSAttributedString *attributedText =
[[NSAttributedString alloc] initWithString:text
attributes:@{NSFontAttributeName: font}];
CGRect rect = [attributedText boundingRectWithSize:(CGSize){width, CGFLOAT_MAX}
options:NSStringDrawingUsesLineFragmentOrigin
context:nil];
CGSize size = rect.size;
Please note the documentation mentions:
In iOS 7 and later, this method returns fractional sizes (in the size component of the returned
CGRect
); to use a returned size to size views, you must use raise its value to the nearest higher integer using the ceil function.
So to pull out the calculated height or width to be used for sizing views, I would use:
CGFloat height = ceilf(size.height);
CGFloat width = ceilf(size.width);

- 1,440
- 18
- 27

- 12,795
- 5
- 39
- 47
-
-
2@Nirav I don't see any mention of the deprecation. Can you point me to where it says it's deprecated? Thanks! (https://developer.apple.com/library/ios/documentation/uikit/reference/NSAttributedString_UIKit_Additions/Reference/Reference.html) – Mr. T Oct 02 '13 at 22:26
-
2Maybe @Nirav meant that it wasn't available for *NSString* in iOS 6 (which is mentioned indirectly in the answer)? – newenglander Oct 17 '13 at 19:33
-
Mr.T you must set your deployment target to iOS 7 to see that it is deprecated. – Chewie The Chorkie Dec 12 '13 at 16:57
-
1@VagueExplanation I just tried that and boundingRectForSize still isn't deprecated for NSAttributedString. It also doesn't say deprecated in the documentation. – Mr. T Dec 12 '13 at 21:41
-
5Fantastic for mentioning using ceilf(). Nowhere else mentioned that and my size was always slightly too small. Thanks! – Jonathan Brown Aug 06 '14 at 05:29
-
How do we set the text? text = self.cell.label.text; like this? This isn't working for me. – durazno Aug 13 '15 at 08:47
-
In my case I had to set options to: NSStringDrawingUsesLineFragmentOrigin | NSStringDrawingUsesFontLeading, otherwise wrong height was calcualted. – Vojta Aug 22 '17 at 12:13
As you can see sizeWithFont
at Apple Developer site it is deprecated so we need to use sizeWithAttributes
.
#define SYSTEM_VERSION_LESS_THAN(v) ([[[UIDevice currentDevice] systemVersion] compare:v options:NSNumericSearch] == NSOrderedAscending)
NSString *text = @"Hello iOS 7.0";
if (SYSTEM_VERSION_LESS_THAN(@"7.0")) {
// code here for iOS 5.0,6.0 and so on
CGSize fontSize = [text sizeWithFont:[UIFont fontWithName:@"Helvetica"
size:12]];
} else {
// code here for iOS 7.0
CGSize fontSize = [text sizeWithAttributes:
@{NSFontAttributeName:
[UIFont fontWithName:@"Helvetica" size:12]}];
}
-
17In this case better to use `[NSObject respondsToSelector:]` method like here: http://stackoverflow.com/a/3863039/1226304 – derpoliuk Sep 23 '13 at 14:42
I created a category to handle this problem, here it is :
#import "NSString+StringSizeWithFont.h"
@implementation NSString (StringSizeWithFont)
- (CGSize) sizeWithMyFont:(UIFont *)fontToUse
{
if ([self respondsToSelector:@selector(sizeWithAttributes:)])
{
NSDictionary* attribs = @{NSFontAttributeName:fontToUse};
return ([self sizeWithAttributes:attribs]);
}
return ([self sizeWithFont:fontToUse]);
}
This way you only have to find/replace sizeWithFont:
with sizeWithMyFont:
and you're good to go.

- 2,800
- 2
- 17
- 19
-
1though this will produce a compiler warning on ios7+ for referencing sizeWithFont, or a compile warning/error on < ios7 for referencing sizeWithAttributes! Probably best to use a macro instead of checking respondsToSelector - if necessary. But as you can't deliver to apple with ioS6 SDK any more...it probably isn't! – Nick Hingston Jul 16 '14 at 08:32
-
Add this to supress warning #pragma GCC diagnostic ignored "-Wdeprecated-declarations" – Ryan Heitner Jan 02 '15 at 09:58
In iOS7 I needed the logic to return the correct height for the tableview:heightForRowAtIndexPath method, but the sizeWithAttributes always returns the same height regardless of the string length because it doesn't know that it is going to be put in a fixed width table cell. I found this works great for me and calculates the correct height taking in consideration the width for the table cell! This is based on Mr. T's answer above.
NSString *text = @"The text that I want to wrap in a table cell."
CGFloat width = tableView.frame.size.width - 15 - 30 - 15; //tableView width - left border width - accessory indicator - right border width
UIFont *font = [UIFont systemFontOfSize:17];
NSAttributedString *attributedText = [[NSAttributedString alloc] initWithString:text attributes:@{NSFontAttributeName: font}];
CGRect rect = [attributedText boundingRectWithSize:(CGSize){width, CGFLOAT_MAX}
options:NSStringDrawingUsesLineFragmentOrigin
context:nil];
CGSize size = rect.size;
size.height = ceilf(size.height);
size.width = ceilf(size.width);
return size.height + 15; //Add a little more padding for big thumbs and the detailText label

- 101
- 1
- 2
Multi-line labels using dynamic height may require additional information to set the size properly. You can use sizeWithAttributes with UIFont and NSParagraphStyle to specify both the font and the line-break mode.
You would define the Paragraph Style and use an NSDictionary like this:
// set paragraph style
NSMutableParagraphStyle *style = [[NSParagraphStyle defaultParagraphStyle] mutableCopy];
[style setLineBreakMode:NSLineBreakByWordWrapping];
// make dictionary of attributes with paragraph style
NSDictionary *sizeAttributes = @{NSFontAttributeName:myLabel.font, NSParagraphStyleAttributeName: style};
// get the CGSize
CGSize adjustedSize = CGSizeMake(label.frame.size.width, CGFLOAT_MAX);
// alternatively you can also get a CGRect to determine height
CGRect rect = [myLabel.text boundingRectWithSize:adjustedSize
options:NSStringDrawingUsesLineFragmentOrigin
attributes:sizeAttributes
context:nil];
You can use the CGSize 'adjustedSize' or CGRect as rect.size.height property if you're looking for the height.
More info on NSParagraphStyle here: https://developer.apple.com/library/mac/documentation/cocoa/reference/applicationkit/classes/NSParagraphStyle_Class/Reference/Reference.html

- 649
- 8
- 9
-
1It seems like there's a syntax issue immediately after adjustedSize. – Chris Prince Oct 05 '15 at 21:01
// max size constraint
CGSize maximumLabelSize = CGSizeMake(184, FLT_MAX)
// font
UIFont *font = [UIFont fontWithName:TRADE_GOTHIC_REGULAR size:20.0f];
// set paragraph style
NSMutableParagraphStyle *paragraphStyle = [[NSMutableParagraphStyle alloc] init];
paragraphStyle.lineBreakMode = NSLineBreakByWordWrapping;
// dictionary of attributes
NSDictionary *attributes = @{NSFontAttributeName:font,
NSParagraphStyleAttributeName: paragraphStyle.copy};
CGRect textRect = [string boundingRectWithSize: maximumLabelSize
options:NSStringDrawingUsesLineFragmentOrigin
attributes:attributes
context:nil];
CGSize expectedLabelSize = CGSizeMake(ceil(textRect.size.width), ceil(textRect.size.height));

- 12,572
- 4
- 76
- 80
-
1This saved me hours of headaches, thanks Kirit, defining the attributes and dictionaries prior to the CGRect block was what did it for me... also much easier to read. – Azin Mehrnoosh Feb 20 '18 at 07:10
Create a function that takes a UILabel instance. and returns CGSize
CGSize constraint = CGSizeMake(label.frame.size.width , 2000.0);
// Adjust according to requirement
CGSize size;
if([[[UIDevice currentDevice] systemVersion] floatValue] >= 7.0){
NSRange range = NSMakeRange(0, [label.attributedText length]);
NSDictionary *attributes = [label.attributedText attributesAtIndex:0 effectiveRange:&range];
CGSize boundingBox = [label.text boundingRectWithSize:constraint options: NSStringDrawingUsesLineFragmentOrigin attributes:attributes context:nil].size;
size = CGSizeMake(ceil(boundingBox.width), ceil(boundingBox.height));
}
else{
size = [label.text sizeWithFont:label.font constrainedToSize:constraint lineBreakMode:label.lineBreakMode];
}
return size;

- 2,138
- 1
- 13
- 9
-
I my case for dynamicaly Row height I completely removed HeightForRow method and used UITableViewAutomaticDimension. `tableView.estimatedRowHeight = 68.0 tableView.rowHeight = UITableViewAutomaticDimension` – Eugene Braginets Apr 09 '15 at 13:24
Alternate solution-
CGSize expectedLabelSize;
if ([subTitle respondsToSelector:@selector(sizeWithAttributes:)])
{
expectedLabelSize = [subTitle sizeWithAttributes:@{NSFontAttributeName:subTitleLabel.font}];
}else{
expectedLabelSize = [subTitle sizeWithFont:subTitleLabel.font constrainedToSize:subTitleLabel.frame.size lineBreakMode:NSLineBreakByWordWrapping];
}

- 902
- 8
- 21
-
1This will produce a compiler warning on both iOS6 & 7. And will have quite different behaviour for each! – Nick Hingston Jul 16 '14 at 08:40
Building on @bitsand, this is a new method I just added to my NSString+Extras category:
- (CGRect) boundingRectWithFont:(UIFont *) font constrainedToSize:(CGSize) constraintSize lineBreakMode:(NSLineBreakMode) lineBreakMode;
{
// set paragraph style
NSMutableParagraphStyle *style = [[NSParagraphStyle defaultParagraphStyle] mutableCopy];
[style setLineBreakMode:lineBreakMode];
// make dictionary of attributes with paragraph style
NSDictionary *sizeAttributes = @{NSFontAttributeName:font, NSParagraphStyleAttributeName: style};
CGRect frame = [self boundingRectWithSize:constraintSize options:NSStringDrawingUsesLineFragmentOrigin attributes:sizeAttributes context:nil];
/*
// OLD
CGSize stringSize = [self sizeWithFont:font
constrainedToSize:constraintSize
lineBreakMode:lineBreakMode];
// OLD
*/
return frame;
}
I just use the size of the resulting frame.

- 7,288
- 2
- 48
- 66
You can still use sizeWithFont
. but, in iOS >= 7.0 method cause crashing if the string contains leading and trailing spaces or end lines \n
.
Trimming text before using it
label.text = [label.text stringByTrimmingCharactersInSet:
[NSCharacterSet whitespaceAndNewlineCharacterSet]];
That's also may apply to sizeWithAttributes
and [label sizeToFit]
.
also, whenever you have nsstringdrawingtextstorage message sent to deallocated instance
in iOS 7.0 device it deals with this.

- 23,815
- 10
- 63
- 101
Better use automatic dimensions (Swift):
tableView.estimatedRowHeight = 68.0
tableView.rowHeight = UITableViewAutomaticDimension
NB: 1. UITableViewCell prototype should be properly designed (for the instance don't forget set UILabel.numberOfLines = 0 etc) 2. Remove HeightForRowAtIndexPath method
VIDEO: https://youtu.be/Sz3XfCsSb6k

- 856
- 6
- 16
-
It's take static cell height that are define in storyboard prototype cell – Kirit Vaghela Apr 15 '15 at 13:59
-
Added those two lines and made sure my UILabel was set to 0 number of lines. Did not work as advertised. What else did you do to make it work with just those two lines of code? – Will Jan 13 '17 at 15:49
-
1hm, also you have to pin your label constraints to the top and bottom of the cell – Eugene Braginets Feb 03 '17 at 15:12
-
1No, this should be enough. Do you have autolayout constraints for label pinned to superview? – Eugene Braginets Feb 03 '17 at 15:31
Accepted answer in Xamarin would be (use sizeWithAttributes and UITextAttributeFont):
UIStringAttributes attributes = new UIStringAttributes
{
Font = UIFont.SystemFontOfSize(17)
};
var size = text.GetSizeUsingAttributes(attributes);

- 1
- 1

- 3,102
- 2
- 30
- 52
As the @Ayush answer:
As you can see
sizeWithFont
at Apple Developer site it is deprecated so we need to usesizeWithAttributes
.
Well, supposing that in 2019+ you are probably using Swift and String
instead of Objective-c and NSString
, here's the correct way do get the size of a String
with predefined font:
let stringSize = NSString(string: label.text!).size(withAttributes: [.font : UIFont(name: "OpenSans-Regular", size: 15)!])

- 671
- 8
- 16
-
-
@JosephAstrahan this isn't for determine the font size, it's for getting the size(CGSize) of an string with determined font. If you want to get the font size of a label you can easily use label.font – Romulo BM May 11 '20 at 22:05
-
using your idea, I created a way to get the font size more or less (https://stackoverflow.com/questions/61651614/detect-tap-for-uilabel-with-autoshrink-to-minimum-font-size-enabled/61693334#61693334), label.font would would not work in my case due to some complicated issues with labels being clickable only if the exact font is known you can read about it on my post. – Joseph Astrahan May 12 '20 at 03:36
- (CGSize) sizeWithMyFont:(UIFont *)fontToUse
{
if ([self respondsToSelector:@selector(sizeWithAttributes:)])
{
NSDictionary* attribs = @{NSFontAttributeName:fontToUse};
return ([self sizeWithAttributes:attribs]);
}
return ([self sizeWithFont:fontToUse]);
}

- 115
- 1
- 10
Here is the monotouch equivalent if anyone needs it:
/// <summary>
/// Measures the height of the string for the given width.
/// </summary>
/// <param name="text">The text.</param>
/// <param name="font">The font.</param>
/// <param name="width">The width.</param>
/// <param name="padding">The padding.</param>
/// <returns></returns>
public static float MeasureStringHeightForWidth(this string text, UIFont font, float width, float padding = 20)
{
NSAttributedString attributedString = new NSAttributedString(text, new UIStringAttributes() { Font = font });
RectangleF rect = attributedString.GetBoundingRect(new SizeF(width, float.MaxValue), NSStringDrawingOptions.UsesLineFragmentOrigin, null);
return rect.Height + padding;
}
which can be used like this:
public override float GetHeightForRow(UITableView tableView, NSIndexPath indexPath)
{
//Elements is a string array
return Elements[indexPath.Row].MeasureStringHeightForWidth(UIFont.SystemFontOfSize(UIFont.LabelFontSize), tableView.Frame.Size.Width - 15 - 30 - 15);
}

- 2,459
- 1
- 25
- 36
CGSize maximumLabelSize = CGSizeMake(label.frame.size.width, FLT_MAX);
CGSize expectedLabelSize = [label sizeThatFits:maximumLabelSize];
float heightUse = expectedLabelSize.height;

- 81
- 1
- 2
Try this syntax:
NSAttributedString *attributedText =
[[NSAttributedString alloc] initWithString:text
attributes:@{NSFontAttributeName: font}];

- 479
- 1
- 6
- 16
None of this worked for me in ios 7. Here is what I ended up doing. I put this in my custom cell class and call the method in my heightForCellAtIndexPath method.
My cell looks similar to the description cell when viewing an app in the app store.
First in the storyboard, set your label to 'attributedText', set the number of lines to 0 (which will resize the label automatically (ios 6+ only)) and set it to word wrap.
Then i just add up all the heights of the content of the cell in my custom Cell Class. In my case I have a Label at the top that always says "Description" (_descriptionHeadingLabel), a smaller label that is variable in size that contains the actual description (_descriptionLabel) a constraint from the top of the cell to the heading (_descriptionHeadingLabelTopConstraint). I also added 3 to space out the bottom a little bit (about the same amount apple places on the subtitle type cell.)
- (CGFloat)calculateHeight
{
CGFloat width = _descriptionLabel.frame.size.width;
NSAttributedString *attributedText = _descriptionLabel.attributedText;
CGRect rect = [attributedText boundingRectWithSize:(CGSize){width, CGFLOAT_MAX} options: NSStringDrawingUsesLineFragmentOrigin context:nil];
return rect.size.height + _descriptionHeadingLabel.frame.size.height + _descriptionHeadingLabelTopConstraint.constant + 3;
}
And in my Table View delegate:
- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath;
{
if (indexPath.row == 0) {
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:@"descriptionCell"];
DescriptionCell *descriptionCell = (DescriptionCell *)cell;
NSString *text = [_event objectForKey:@"description"];
descriptionCell.descriptionLabel.text = text;
return [descriptionCell calculateHeight];
}
return 44.0f;
}
You can change the if statement to be a little 'smarter' and actually get the cell identifier from some sort of data source. In my case the cells are going to be hard coded since there will be fixed amount of them in a specific order.

- 1,052
- 8
- 10
-
`boundingRectWithSize` in ios 9.2 present problems, is different results to ios < 9.2. You found or know any other best way for make this. – jose920405 Feb 03 '16 at 21:23