146

In iOS 7, the method:

- (CGSize)sizeWithFont:(UIFont *)font
     constrainedToSize:(CGSize)size
         lineBreakMode:(NSLineBreakMode)lineBreakMode 

and the method:

- (CGSize)sizeWithFont:(UIFont *)font

are deprecated. How can I replace

CGSize size = [string sizeWithFont:font
                 constrainedToSize:constrainSize
                     lineBreakMode:NSLineBreakByWordWrapping];

and:

CGSize size = [string sizeWithFont:font];
JOM
  • 8,139
  • 6
  • 78
  • 111
user_Dennis_Mostajo
  • 2,279
  • 4
  • 28
  • 38
  • 2
    the substitute method is `-sizeWithAttributes:`. – holex Sep 19 '13 at 21:57
  • ok holex thanks but, how can I use a font from label like a NSDIctionary? if my code is like: sizeWithFont:customlabel.font ;the void ask "sizeWithAttributes:<#(NSDictionary *)#>" – user_Dennis_Mostajo Sep 19 '13 at 22:26
  • 1
    here is the official documentation of how you can define attributes: https://developer.apple.com/library/ios/documentation/UIKit/Reference/NSAttributedString_UIKit_Additions/Reference/Reference.html#//apple_ref/doc/uid/TP40011688 – holex Sep 20 '13 at 06:46

8 Answers8

221

You could try this:

CGRect textRect = [text boundingRectWithSize:size
                                 options:NSStringDrawingUsesLineFragmentOrigin
                              attributes:@{NSFontAttributeName:FONT}
                                 context:nil];

CGSize size = textRect.size;

Just change "FONT" for an "[UIFont font....]"

Robert Altman
  • 5,355
  • 5
  • 33
  • 51
Xavier Maroñas
  • 3,124
  • 1
  • 14
  • 7
  • 13
    And where do you mention NSLineBreakByWordWrapping? Wherre did it go? – user4951 Nov 04 '13 at 09:57
  • 32
    `NSLineBreakByWordWrapping` would go within a `NSParagraphStyle`. So for example: `NSMutableParagraphStyle *paragraphStyle = [[NSMutableParagraphStyle alloc] init]; paragraphStyle.lineBreakMode = NSLineBreakByWordWrapping;` In the attributes you would then need to add `NSParagraphStyleAttributeName: paragraphStyle.copy`... – Florian Friedrich Dec 19 '13 at 07:49
  • 1
    @ffried in my case adding the paragraphStyle with line break other than NSLineBreakByWordWrapping caused size to be calculated for just one line… Any thoughts? – manicaesar Feb 03 '14 at 10:42
  • @manicaesar Except for `NSLineBreakByWordWrapping` and `NSLineBreakByCharWrapping` all line break modes are made for only one line (by truncating the string). I've just tested it and all line break modes work as expected. – Florian Friedrich Feb 03 '14 at 13:26
  • 9
    Don't forget that `boundingRectWithSize:options:attributes:context:` returns fractional values. You need to do `ceil(textRect.size.height)` and `ceil(textRect.size.width)` respectively to get the real height/width. – Florian Friedrich Feb 03 '14 at 13:29
  • 1
    Hmm, you are right, having (for example) NSLineBreakModeByTruncatingMiddle makes no sense for multiple lines. If someone want to have last line with tail truncated, he can use NSStringDrawingTruncatesLastVisibleLine. Thanks! – manicaesar Feb 03 '14 at 13:41
  • Does this return exact size same as sizeWithFont ? I am facing this issue and using the above method still has a height difference of 3 to 4 pixels which causes lot of difference in UI for iOS 6.0 and iOS 7.0 when compared side by side – Javal Nanda Feb 19 '14 at 05:13
  • boundingRectWithSize is not returning correct width and height. – Nirav Jain Mar 05 '14 at 07:39
  • 20
    What the heck is BOLIVIASize? – JRam13 Jun 03 '14 at 21:10
  • 1
    boundingRectWithSize is still returning wrong output as i test it. The scenario is when you are testing for long and multiple paragraphs. – Nirav Jain Jul 02 '14 at 09:37
  • @Nirav I faced the same problem for long paragraph, but after investigating the problem I found that I provide not accurate attributes like the font size. It was 12 and it should be 14 as in the interface builder in my case – Sawsan Jul 07 '14 at 12:31
  • 1
    `NSLineBreakByWordWrapping` is represented by `NSStringDrawingUsesLineFragmentOrigin`. – Marius Soutier Sep 20 '14 at 23:20
36

As we cant use sizeWithAttributes for all iOS greater than 4.3 we have to write conditional code for 7.0 and previous iOS.

1) Solution 1:

if (SYSTEM_VERSION_GREATER_THAN_OR_EQUAL_TO(@"7.0")) {
   CGSize size = CGSizeMake(230,9999);
   CGRect textRect = [specialityObj.name  
       boundingRectWithSize:size
                    options:NSStringDrawingUsesLineFragmentOrigin
                 attributes:@{NSFontAttributeName:[UIFont fontWithName:[AppHandlers zHandler].fontName size:14]}
                    context:nil];
   total_height = total_height + textRect.size.height;   
}
else {
   CGSize maximumLabelSize = CGSizeMake(230,9999); 
   expectedLabelSize = [specialityObj.name sizeWithFont:[UIFont fontWithName:[AppHandlers zHandler].fontName size:14] constrainedToSize:maximumLabelSize lineBreakMode:UILineBreakModeWordWrap]; //iOS 6 and previous. 
   total_height = total_height + expectedLabelSize.height;
}

2) Solution 2

UILabel *gettingSizeLabel = [[UILabel alloc] init];
gettingSizeLabel.font = [UIFont fontWithName:[AppHandlers zHandler].fontName size:16]; // Your Font-style whatever you want to use.
gettingSizeLabel.text = @"YOUR TEXT HERE";
gettingSizeLabel.numberOfLines = 0;
CGSize maximumLabelSize = CGSizeMake(310, 9999); // this width will be as per your requirement

CGSize expectedSize = [gettingSizeLabel sizeThatFits:maximumLabelSize];

The first solution is sometime fail to return proper value of height. so use another solution. which will work perfectly.

The second option is quite well and working smoothly in all iOS without conditional code.

Nirav Jain
  • 5,088
  • 5
  • 40
  • 61
9

Here is simple solution :

Requirements :

CGSize maximumSize = CGSizeMake(widthHere, MAXFLOAT);
UIFont *font = [UIFont systemFontOfSize:sizeHere];

Now As constrainedToSizeusage:lineBreakMode: usage is deprecated in iOS 7.0:

CGSize expectedSize = [stringHere sizeWithFont:font constrainedToSize:maximumSize lineBreakMode:NSLineBreakByWordWrapping];

Now usage in greater version of iOS 7.0 will be:

// Let's make an NSAttributedString first
NSMutableAttributedString *attributedString = [[NSMutableAttributedString alloc] initWithString:stringHere];
//Add LineBreakMode
NSMutableParagraphStyle *paragraphStyle = [NSMutableParagraphStyle new];
[paragraphStyle setLineBreakMode:NSLineBreakByWordWrapping];
[attributedString setAttributes:@{NSParagraphStyleAttributeName:paragraphStyle} range:NSMakeRange(0, attributedString.length)];
// Add Font
[attributedString setAttributes:@{NSFontAttributeName:font} range:NSMakeRange(0, attributedString.length)];

//Now let's make the Bounding Rect
CGSize expectedSize = [attributedString boundingRectWithSize:maximumSize options:NSStringDrawingUsesLineFragmentOrigin context:nil].size;
Paresh Navadiya
  • 38,095
  • 11
  • 81
  • 132
7

Below are two simple methods that will replace these two deprecated methods.

And here are the relevant references:

If you are using NSLineBreakByWordWrapping, you don't need to specify the NSParagraphStyle, as that is the default: https://developer.apple.com/library/mac/documentation/Cocoa/Reference/ApplicationKit/Classes/NSParagraphStyle_Class/index.html#//apple_ref/occ/clm/NSParagraphStyle/defaultParagraphStyle

You must get the ceil of the size, to match the deprecated methods' results. https://developer.apple.com/library/ios/documentation/UIKit/Reference/NSString_UIKit_Additions/#//apple_ref/occ/instm/NSString/boundingRectWithSize:options:attributes:context:

+ (CGSize)text:(NSString*)text sizeWithFont:(UIFont*)font {    
    CGSize size = [text sizeWithAttributes:@{NSFontAttributeName: font}];
    return CGSizeMake(ceilf(size.width), ceilf(size.height));
}

+ (CGSize)text:(NSString*)text sizeWithFont:(UIFont*)font constrainedToSize:(CGSize)size{
    CGRect textRect = [text boundingRectWithSize:size
                                     options:NSStringDrawingUsesLineFragmentOrigin
                                  attributes:@{NSFontAttributeName: font}
                                     context:nil];
    return CGSizeMake(ceilf(textRect.size.width), ceilf(textRect.size.height));
}
Elijah
  • 8,381
  • 2
  • 55
  • 49
6

In most cases I used the method sizeWithFont:constrainedToSize:lineBreakMode: to estimate the minimum size for a UILabel to accomodate its text (especially when the label has to be placed inside a UITableViewCell)...

...If this is exactly your situation you can simpy use the method:

CGSize size = [myLabel textRectForBounds:myLabel.frame limitedToNumberOfLines:mylabel.numberOfLines].size;

Hope this might help.

roberto.buratti
  • 2,487
  • 1
  • 16
  • 10
3
UIFont *font = [UIFont boldSystemFontOfSize:16];
CGRect new = [string boundingRectWithSize:CGSizeMake(200, 300) options:NSStringDrawingUsesFontLeading attributes:@{NSFontAttributeName: font} context:nil];
CGSize stringSize= new.size;
Pang
  • 9,564
  • 146
  • 81
  • 122
user3575114
  • 993
  • 7
  • 13
  • 3
    Welcome to StackOverFlow. Do not post a same answer again. If you need to add something to an answer, make a comment or do an edit to the answer. – Ramaraj T Jul 18 '14 at 04:47
  • ok..I will take that into consideration next time.Thank you for your advice. – user3575114 Jul 18 '14 at 07:27
2

[Accepted answer works nicely in a category. I'm overwriting the deprecated method names. Is this a good idea? Seems to work with no complaints in Xcode 6.x]

This works if your Deployment Target is 7.0 or greater. Category is NSString (Util)

NSString+Util.h

- (CGSize)sizeWithFont:(UIFont *) font;
- (CGSize)sizeWithFont:(UIFont *)font constrainedToSize:(CGSize)size;

NSString+Util.m

- (CGSize)sizeWithFont:(UIFont *) font {
    NSDictionary *fontAsAttributes = @{NSFontAttributeName:font};
    return [self sizeWithAttributes:fontAsAttributes];
}

- (CGSize)sizeWithFont:(UIFont *)font constrainedToSize:(CGSize)size {
    NSDictionary *fontAsAttributes = @{NSFontAttributeName:font};
    CGRect retVal = [self boundingRectWithSize:size
                                     options:NSStringDrawingUsesLineFragmentOrigin
                                  attributes:fontAsAttributes context:nil];
    return retVal.size;
}
Dan Rosenstark
  • 68,471
  • 58
  • 283
  • 421
1
UIFont *font = [UIFont fontWithName:@"Courier" size:16.0f];

NSMutableParagraphStyle *paragraphStyle = [[NSParagraphStyle defaultParagraphStyle] mutableCopy];
paragraphStyle.lineBreakMode = NSLineBreakByTruncatingTail;
paragraphStyle.alignment = NSTextAlignmentRight;

NSDictionary *attributes = @{ NSFontAttributeName: font,
                    NSParagraphStyleAttributeName: paragraphStyle };

CGRect textRect = [text boundingRectWithSize:size
                                 options:NSStringDrawingUsesLineFragmentOrigin
                              attributes:attributes
                                 context:nil];

CGSize size = textRect.size;

from two answers 1 + 2

Alex
  • 8,908
  • 28
  • 103
  • 157