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

时间:2013-08-19 13:47:59

标签: objective-c nsstring deprecated

我有一个方法,在给定一定长度的字符串(具有相应的正确字体大小)的情况下为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;
}

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

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

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

我有三个问题:

1)因为它被弃用了,这是否意味着我绝对应该替换它,尽管它仍在工作?

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

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

4 个答案:

答案 0 :(得分: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];
  

更新:

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

CGFloat height = ceilf(labelBounds.size.height);

答案 1 :(得分:13)

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

可替换为:

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;

请注意文档提及:

  

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

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

CGFloat height = ceilf(size.height);
CGFloat width  = ceilf(size.width);

答案 2 :(得分: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);
}

答案 3 :(得分:2)

斯威夫特版的挪威亚历山大的答案......

func heightNeededForText(text: NSString, withFont font: UIFont, width: CGFloat, lineBreakMode:NSLineBreakMode) -> CGFloat {
        let paragraphStyle = NSMutableParagraphStyle()
        paragraphStyle.lineBreakMode = lineBreakMode
        let size: CGSize = text.boundingRectWithSize(CGSizeMake(width, CGFloat.max), options: [.UsesLineFragmentOrigin, .UsesFontLeading], attributes: [ NSFontAttributeName: font, NSParagraphStyleAttributeName: paragraphStyle], context: nil).size//text boundingRectWithSize:CGSizeMake(width, CGFLOAT_MA

        return ceil(size.height);
    }

在你想获得高度的代码中,只需调用下面的方法......

let size = self.heightNeededForText(text as NSString, withFont: UIFont.systemFontOfSize(15.0), width: scrollView.frame.size.width - 20, lineBreakMode: NSLineBreakMode.ByWordWrapping) //Can edit the font size and LinebreakMode