简体   繁体   中英

how to replace sizeWithFont after it is deprecated on iOS 7

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

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.

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.

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

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM