0

I got an old project, and the code is using sizeWithFont. I got an warning from xcode saying it is first deprecated in iOS 7, and asked me to replace it with

(CGRect)boundingRectWithSize:(CGSize)size options:(NSStringDrawingOptions)options attributes:(NSDictionary *)attributes context:(NSStringDrawingContext *)context

I got two questions:

I. if I intend not to change it, what whould happen? Will it crash my app, or just bypass the deprecated API?

II. I wanted to use the suggested API, but I am confused it is asking for a CGSize paramter and returning a CGRect, while my old project just needs to return a CGSize. If I already got the CGSize, why I need the rect again? Please correct me and give code using the new API. Thanks a lot!

EDIT:

I have checked the answer in Replacement for deprecated sizeWithFont: in iOS 7?

I will do a self-answer to compare two solutions.

Another quesiton I have is:

I notice there is a [self setNumberOfLines:1];, should I keep it or I can delete it? It does not impact anything in my code for now, but I don't know other situations, aka 'multiple line' situlation.

Old legacy code:

@implementation UILabel (dynamicSize)
-(CGFloat)expectedWidth{
    [self setNumberOfLines:1];

    CGSize maximumLabelSize = CGSizeMake(9999,self.frame.size.height);

    CGSize expectedLabelSize = [[self text] sizeWithFont:[self font]
                                       constrainedToSize:maximumLabelSize
                                           lineBreakMode:[self lineBreakMode]];
    return expectedLabelSize.width;
}
@end
Community
  • 1
  • 1
Wingzero
  • 9,644
  • 10
  • 39
  • 80
  • For your first question, no you app will not crash until Apple removes the old code. Something that is not lightly to happen any time soon. For the use of the `sizeWithFont:constrainedToSize:` see the duplicated question. – rckoenes Apr 13 '15 at 09:40
  • @rckoenes I have updated my question with something I dig out. I want to post it as an answer but you close it. Is there anything we can do to highlight what I found? – Wingzero Apr 13 '15 at 10:05
  • @wingzeor I've reopened your question. – rckoenes Apr 13 '15 at 10:11
  • @rckoenes thanks, updated. BTW, I notice there is `[self setNumberOfLines:1];` should I keep it I can delete it? – Wingzero Apr 13 '15 at 10:16
  • It should be the max number of line you want to display. Zet to `0` to have no restriction. – rckoenes Apr 13 '15 at 10:24

3 Answers3

0

I will do a self-answer to compare two solutions from Replacement for deprecated sizeWithFont: in iOS 7?

BTW I am not sure if I need to setNumberOfLines, so I will set it to no limit

[self setNumberOfLines:0];

One solution is

CGSize size = [[self text] sizeWithAttributes:@{NSFontAttributeName: [self font]}];

// Values are fractional -- you should take the ceilf to get equivalent values
CGSize adjustedSize = CGSizeMake(ceilf(size.width), ceilf(size.height));

Another one:

NSAttributedString *attributedText = [[NSAttributedString alloc] initWithString:[self text]
                                                                     attributes:@{NSFontAttributeName: [self font]}];
CGRect rect = [attributedText boundingRectWithSize:(CGSize){CGFLOAT_MAX, CGFLOAT_MAX} // be careful here
                                           options:NSStringDrawingUsesLineFragmentOrigin
                                           context:nil];
CGSize size = rect.size;
CGSize adjustedSize = CGSizeMake(ceilf(size.width), ceilf(size.height));

Both solution gives the same result as the deprecated API. To summerize, I use sizeWithAttributes because it is simpler.

However one thing to mention that:

the answer in Replacement for deprecated sizeWithFont: in iOS 7? uses kinds of (CGSize){width, CGFLOAT_MAX}]; as the size parameter,

but I tested if I use it like (CGSize){self.bounds.size.width, CGFLOAT_MAX}]; The result is not correct, the calculated width is less than the other solution.

If I use (CGSize){CGFLOAT_MAX, CGFLOAT_MAX}, I will get the same result as the other answer. Test your code before you decide choosing a solution.

Community
  • 1
  • 1
Wingzero
  • 9,644
  • 10
  • 39
  • 80
0

You can provide the CGFLOAT_MAX in width if your label need to change width as per text size while put CGFLOAT_MAX in height if you want hight as per text in label. The other param will be static.

NSAttributedString *attributedText = [[NSAttributedString alloc] initWithString:[self text]

//If Height is dynamic and width is fix, Eg.150 width fix, and height dynamic
CGRect rect = [attributedText boundingRectWithSize:(CGSize){150, CGFLOAT_MAX}
                                       options:NSStringDrawingUsesLineFragmentOrigin
                                       context:nil];

              // OR

//If width is dynamic and Height is  fix, Eg.150 Height fix, and width dynamic
CGRect rect = [attributedText boundingRectWithSize:(CGSize){CGFLOAT_MAX,150}
                                       options:NSStringDrawingUsesLineFragmentOrigin
                                       context:nil];

You will get dynamic width, height as per your label size required.

Viral Savaj
  • 3,379
  • 1
  • 26
  • 39
  • I appreciate your answer, but compared to mine, you lack some precision and explaination at how to pick the size. I have self answered it already, so I hope you could go through the answer. – Wingzero Apr 13 '15 at 10:54
0

There are miss concepts about the two methods, if you are tring to get the size of a text container such as UITexView or UILabel, this methods only give you the space occupied by the text, and not by the view, with multiple rows this can lead to clipped text, for instante UITextView contains some padding, those methods doesn't take into account that.
Instead calling -sizeToFit on the text view after adding the text gives you the real size.
About your questions:

  1. Deprecated means that could broke in future releases of iOSes, usually is not a big deal to keep them for a while, but I strongly suggest to change them, to update your code, pay attention that if you are deploying an iOS target that doens't include the new API your app will crash in that specific iOS version
  2. Just use the .size inside the CGRect struct.
  3. This is the maximum number of lines possible, if it doens't fit UILabel will cut the text with rule selected in the -linebreakMode, use 0 to have no restriction
Andrea
  • 26,120
  • 10
  • 85
  • 131
  • I appreciate your answer, but I have posted all solutions and compares already. Towards your answer #2, a `self.bounds.size` is not enough. It should be a {CGFLOAT_MAX, CGFLOAT_MAX} if you are using `boundingRectWithSize`. I chose `sizeWithAttributes` at last – Wingzero Apr 14 '15 at 02:14