我应该用什么来替换弃用的sizeWithFont:方法?

Ram*_*ino 26 objective-c deprecated nsstring

给定一个字符串长度(具有相应的正确字体大小),我有一个方法可以为UITextView提供完美的大小:

- (NSInteger) heightOfLabel:(NSString*) string {
    CGSize maximumLabelSize = CGSizeMake([[UIScreen mainScreen] bounds].size.width - 40, FLT_MAX);
    CGSize expectedLabelSize = [[NSString stringTrimmedForLeadingAndTrailingWhiteSpacesFromString:string]
             sizeWithFont:[UIFont systemFontOfSize:15]
             constrainedToSize:maximumLabelSize 
             lineBreakMode:NSLineBreakByWordWrapping];

    return expectedLabelSize.height + 5;
}
Run Code Online (Sandbox Code Playgroud)

事实上,即使在iOS7中,它仍然让我完美契合.虽然现在它提出了一个警告方法,说我不应该使用'sizeWithFont:contrainedToSize:lineBreakMode'.

它现在说我应该使用-boundingRectWithSize:options:attributes:context:

这个方法对iOS7来说并不陌生,因此我认为可以在堆栈溢出时询问它,而不是去官方的苹果开发者论坛.

我有三个问题:

1)因为它被弃用了,这是否意味着我应该更换它,尽管它仍然有效?

2)我已经尝试了许多不同的boundingRectWithSize:方法,但是它们从来都不是完美的,它似乎总是略有不足(正如许多stackoverflow问题所指出的那样) - 是否有一个完美的替代方法,这种方法完全取而代之与我以前的方法一样,麻烦最小?

3)为什么要删除这种方法?是因为与其他方法的重叠吗?

Ram*_*ino 57

经过一个小时的试用错误,我设法让它工作:

CGSize maximumLabelSize = CGSizeMake(tableView.width, MAXFLOAT);

NSStringDrawingOptions options = NSStringDrawingTruncatesLastVisibleLine |
                                 NSStringDrawingUsesLineFragmentOrigin;

NSDictionary *attr = @{NSFontAttributeName: [UIFont systemFontOfSize:15]};
CGRect labelBounds = [string boundingRectWithSize:maximumLabelSize 
                                          options:options
                                       attributes:attr
                                          context:nil];
Run Code Online (Sandbox Code Playgroud)

更新:

正如T先生在下面的回答中提到的:在iOS 7及更高版本中,此方法返回小数大小(在返回的CGRect的大小组件中); 要使用返回的大小来调整视图大小,必须使用ceil函数将其值提升到最接近的更高整数. ceilf建议使用功能.

CGFloat height = ceilf(labelBounds.size.height);
Run Code Online (Sandbox Code Playgroud)


Mr.*_*. T 13

我相信该函数已被弃用,因为该系列NSString + UIKit函数基于UIStringDrawing库,该库不是线程安全的.如果您尝试不在主线程上运行它们(就像任何其他UIKit功能一样),您将获得不可预测的行为.特别是,如果您同时在多个线程上运行该函数,它可能会使您的应用程序崩溃.这就是为什么在iOS 6中,他们boundingRectWithSize:...为NSAttributedStrings 引入了一种方法.它建立在NSStringDrawing库之上,并且是线程安全的.

如果查看新的NSString boundingRectWithSize:...函数,它会以与NSAttributeString相同的方式请求属性数组.如果我不得不猜测,iOS 7中的这个新的NSString函数只是iOS 6中NSAttributeString函数的包装器.

在这方面,如果您只支持iOS 6和iOS 7,那么我肯定会将所有NSString更改sizeWithFont:...为NSAttributeString boundingRectWithSize.如果您碰巧有一个奇怪的多线程角落案例,它会为您省去很多麻烦!以下是我转换NSString的方法sizeWithFont:constrainedToSize::

过去是什么:

NSString *text = ...;
CGFloat width = ...;
UIFont *font = ...;
CGSize size = [text sizeWithFont:font 
               constrainedToSize:CGSizeMake(width, CGFLOAT_MAX)];
Run Code Online (Sandbox Code Playgroud)

可以替换为:

NSString *text = ...;
CGFloat width = ...;
UIFont *font = ...;
NSAttributedString *attributedText =
    [[NSAttributedString alloc]
        initWithString:text
        attributes:@
        {
            NSFontAttributeName: font
        }];
CGRect rect = [attributedText boundingRectWithSize:CGSizeMake(width, CGFLOAT_MAX)
                                           options:NSStringDrawingUsesLineFragmentOrigin
                                           context:nil];
CGSize size = rect.size;
Run Code Online (Sandbox Code Playgroud)

请注意文档提到:

在iOS 7及更高版本中,此方法返回小数大小(在返回的CGRect的大小组件中); 要使用返回的大小来调整视图大小,必须使用ceil函数将其值提升到最接近的更高整数.

因此,要拉出用于调整视图大小的计算高度或宽度,我会使用:

CGFloat height = ceilf(size.height);
CGFloat width  = ceilf(size.width);
Run Code Online (Sandbox Code Playgroud)

  • 没有解决linebreakmode问题 (4认同)

Ale*_*way 5

对于换行问题:

- (CGFloat)heightNeededForText:(NSString *)text withFont:(UIFont *)font width:(CGFloat)width lineBreakMode:(NSLineBreakMode)lineBreakMode {
    NSMutableParagraphStyle * paragraphStyle = [[NSMutableParagraphStyle alloc] init];
        paragraphStyle.lineBreakMode = lineBreakMode;
    CGSize size = [text boundingRectWithSize:CGSizeMake(width, CGFLOAT_MAX)
                                     options:(NSStringDrawingUsesLineFragmentOrigin | NSStringDrawingUsesFontLeading)
                                  attributes:@{ NSFontAttributeName: font, NSParagraphStyleAttributeName: paragraphStyle }
                                     context:nil].size;

    return ceilf(size.height);
}
Run Code Online (Sandbox Code Playgroud)