【问题标题】:'sizeWithFont:constrainedToSize:lineBreakMode:'is deprecated:'sizeWithFont:constrainedToSize:lineBreakMode:'已弃用:
【发布时间】:2013-09-20 17:10:34
【问题描述】:

在 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;
    }

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

【问题讨论】:

    标签: ios xcode uikit nstextview


    【解决方案1】:

    我不会仅仅掩盖已弃用的功能警告。他们不赞成使用它是有原因的。我相信该函数已被弃用,因为该系列 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:(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);
    

    【讨论】:

    • 是的!我也认为掩盖问题不是解决方案。如果可能,让我尝试实施您的建议并发布修改后的代码。
    • 使用CGRectIntegral(rect) 来限制大小而不是单独限制高度和宽度。
    • 一定要记住实现任何一个舍入函数,因为在这样做之前我的标签会被略微截断!
    • 新的boundingRectWitSize 在使用NSStringDrawingUsesLineFragmentOrigin 时始终使用换行规则作为NSLineBreakByClipping。因此,当我们使用其他中断规则时,这会返回不正确的大小。例如:NSLineBreakByCharWrapping
    【解决方案2】:

    如果您希望它与 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 案例的一个示例,也许您需要根据您的需要进行一些修改。 ;)

    【讨论】:

    • 那么,iOS7 使用 CharWrapping,iOS6 使用 WordWrapping? ;)
    【解决方案3】:

    对于 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;
    

    【讨论】:

      【解决方案4】:

      你可以使用:

      UIFont *font = [UIFont boldSystemFontOfSize:16];
      
      CGRect new = [string boundingRectWithSize:CGSizeMake(200, 300)
          options:NSStringDrawingUsesFontLeading 
          attributes:@{NSFontAttributeName: font} 
          context:nil];
      
      CGSize stringSize= new.size;
      

      【讨论】:

        【解决方案5】:

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

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

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

        你可以find the Apple docs on this new method here.

        【讨论】:

        • 是的,只有当我们为 iOS 7 执行此操作并且编译器本身已经提出了您的建议时,才会出现问题。我需要有关如何使用 boundingRectWithSize:options:attributes:context 的帮助!感谢您的建议。
        【解决方案6】:

        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));
        

        【讨论】:

        • 如果你有双换行符(例如“\n\n”),那么你会遇到麻烦,因为boundingRectWithSize 没有正确调整空字符串的大小。我添加了if ([actString isEqual: @""]) {height += fontSize) else{ &lt;your current loop code&gt;}。请注意,这也需要您传递字体大小。
        • 我无法编辑我之前的评论,但我应该提到我将 fontSize 乘以 1.125 以获得空白字符串。我观察到boundingRectWithSize 这样做是为了计算每条线的高度。
        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2013-09-25
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2014-02-12
        • 1970-01-01
        相关资源
        最近更新 更多