29

在 Xcode 5 上将项目从 iOS5.0 转换为 iOS7 / iOS6。下面的代码给出了编译时警告:

'sizeWithFont:constrainedToSize:lineBreakMode:'已弃用:首先在 ios 7.0 中弃用 - 使用 - boundingRectWithSize:options:attribiutes:context

- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath
{
    if (indexPath.section == 0)
    {
        self.lblHidden.frame = CGRectMake(58, 228, 945, 9999);
        self.lblHidden.text = detailShareObj.pDesc;
        CGSize size = [detailShareObj.pDesc sizeWithFont:self.lblHidden.font constrainedToSize:self.lblHidden.frame.size lineBreakMode:NSLineBreakByWordWrapping];
        return 228.0+size.height+20;

    }
    else if (indexPath.section == 1)
    {
        NSString *tempPointStr = (self.shortDescArray)[indexPath.row];

        self.lblHidden.frame = CGRectMake(58, 0, 945, 9999);
        self.lblHidden.text = tempPointStr;
        CGSize size = [tempPointStr sizeWithFont:self.lblHidden.font
                               constrainedToSize:self.lblHidden.frame.size
                                   lineBreakMode:NSLineBreakByWordWrapping];

            return 50.0f;
    }

我在其他地方尝试了一些建议,但如果有人可以通过提供代码中所需的更正来提供帮助,将不胜感激。

4

6 回答 6

64

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

如果您查看新的 NSStringboundingRectWithSize:...函数,它会以与 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:(CGSize){width, CGFLOAT_MAX}];

可以替换为:

NSString *text = ...;
CGFloat width = ...;
UIFont *font = ...;
NSAttributedString *attributedText =
    [[NSAttributedString alloc]
        initWithString:text
        attributes:@
        {
            NSFontAttributeName: font
        }];
CGRect rect = [attributedText boundingRectWithSize:(CGSize){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);
于 2013-09-23T03:38:52.163 回答
44

如果您希望它与 iOS7 及其以下版本兼容,请尝试这个(使用 ARC):

CGSize size;

if ([tempPointStr respondsToSelector:
     @selector(boundingRectWithSize:options:attributes:context:)])
{
  NSMutableParagraphStyle * paragraphStyle = [[NSMutableParagraphStyle alloc] init];
  paragraphStyle.lineBreakMode = NSLineBreakByWordWrapping;
  paragraphStyle.alignment = NSTextAlignmentLeft;

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

  size = [tempPointStr boundingRectWithSize:self.lblHidden.frame.size
                                    options:NSStringDrawingUsesFontLeading
                                           |NSStringDrawingUsesLineFragmentOrigin
                                 attributes:attributes
                                    context:nil].size;
} else {
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Wdeprecated-declarations"
  size = [tempPointStr sizeWithFont:self.lblHidden.font
                  constrainedToSize:self.lblHidden.frame.size
                      lineBreakMode:NSLineBreakByWordWrapping];
#pragma clang diagnostic pop
}

注意:这只是您的else-if案例的一个示例,也许您需要根据您的需要进行一些修改。;)

于 2013-09-20T17:27:27.253 回答
10

对于 iOS7,替换:

CGSize size = [tempPointStr sizeWithFont:self.lblHidden.font
                       constrainedToSize:self.lblHidden.frame.size
                           lineBreakMode:NSLineBreakByWordWrapping];

和:

NSMutableParagraphStyle *paragraphStyle = [[NSMutableParagraphStyle alloc]init];
paragraphStyle.lineBreakMode = NSLineBreakByWordWrapping; //set the line break mode
NSDictionary *attrDict = [NSDictionary dictionaryWithObjectsAndKeys:self.lblHidden.font, NSFontAttributeName, paragraphStyle, NSParagraphStyleAttributeName, nil];
CGSize size = [tempPointStr boundingRectWithSize:self.lblHidden.frame.size
                                         options:NSStringDrawingTruncatesLastVisibleLine|NSStringDrawingUsesLineFragmentOrigin
                                      attributes:attrDict context:nil].size;
于 2014-06-30T12:53:37.323 回答
2

您可以使用:

UIFont *font = [UIFont boldSystemFontOfSize:16];

CGRect new = [string boundingRectWithSize:CGSizeMake(200, 300)
    options:NSStringDrawingUsesFontLeading 
    attributes:@{NSFontAttributeName: font} 
    context:nil];

CGSize stringSize= new.size;
于 2014-07-17T12:48:53.383 回答
1

如果您的目标是 iOS 6.0+,您仍然可以使用sizeWithFont:constrainedToSize:lineBreakMode:. 只要确保您的项目iOS Deployment Target设置为 6.0,编译器就不会给您这些警告。

(您可以通过单击“信息”部分中的蓝色项目选项卡(通常位于左侧顶部的项目导航器窗格)来找到它)。

如果您只针对 iOS 7.0+,您应该使用新方法boundingRectWithSize:options:attributes:context

您可以在此处找到有关此新方法的 Apple 文档。

于 2013-09-20T17:18:19.403 回答
1

boundingRectWithSize:options:attributes:context 存在问题,如果字符串包含“\n”(换行符),它不会正确计算高度。因此,此代码针对给定宽度(inWidth)分别计算每条线的大小:

NSArray *brokenByLines=[string componentsSeparatedByString:@"\n"];
CGFloat height=0.0;
CGFloat maxWidth=0.0;
for (NSString* actString in brokenByLines) {
    CGRect tSize=[actString boundingRectWithSize:CGSizeMake(inWidth, 600) options:(NSStringDrawingUsesLineFragmentOrigin | NSLineBreakByWordWrapping) attributes:@{NSFontAttributeName: inFont} context:nil];
    if (maxWidth<tSize.size.width) {
        maxWidth=tSize.size.width;
    }
    height+=tSize.size.height;
}
CGSize size= CGSizeMake(ceil(maxWidth), ceil(height));
于 2014-09-04T15:34:25.110 回答