Подтвердить что ты не робот

С чем следует заменить устаревший метод sizeWithFont:?

У меня есть метод, который дает мне идеальный размер для 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, и поэтому я считаю, что это нормально спросить его о переполнении стека, а не переходить на официальный форум разработчиков Apple.

У меня есть три вопроса:

1) Поскольку он устарел, значит ли это, что я должен его обязательно заменить, несмотря на то, что он все еще работает?

2) Я пробовал много разных методов boundingRectWithSize: с различными переменными, но он никогда не бывает совершенным, он всегда кажется немного открытым (как много вопросов о стековом потоке) - есть ли идеальная замена этим не устаревшим методом что делает то же самое, что и мой предыдущий метод с минимальными проблемами?

3) зачем удалять этот метод? Это связано с перекрытием этого другого метода?

4b9b3361

Ответ 1

После часа пробной ошибки мне удалось заставить его работать:

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

Обновление:

Как упоминает г-н Т в ответ ниже: В iOS 7 и более поздних версиях этот метод возвращает дробные размеры (в компоненте размера возвращаемого CGRect); для использования возвращаемого размера в представлении размера вы должны использовать его значение до ближайшего более высокого целого с помощью функции ceil. ceilf рекомендуется использовать.

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

Ответ 2

Я считаю, что функция была устарела, потому что эта серия функций NSString + UIKit была основана на библиотеке UIStringDrawing, которая не была потокобезопасной. Если вы попытались запустить их не в основном потоке (как и любая другая функция UIKit), вы получите непредсказуемое поведение. В частности, если вы запускаете функцию на нескольких потоках одновременно, это, вероятно, приведет к краху вашего приложения. Вот почему в iOS 6 они внедрили метод boundingRectWithSize:... для NSAttributedStrings. Это было построено поверх библиотек NSStringDrawing и является потокобезопасным.

Если вы посмотрите на новую функцию NSString boundingRectWithSize:..., она запрашивает массив атрибутов таким же образом, как и NSAttributeString. Если бы мне пришлось догадаться, эта новая функция NSString в iOS 7 является просто оболочкой для функции NSAttributeString от iOS 6.

В этой заметке, если вы поддерживали только 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);

Ответ 3

Для проблемы с выпуском строки:

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

Ответ 4

Быстрая версия Александра из Норвегии отвечает...

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