You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

iOS 11下调用NSString的boundingRectWithSize方法崩溃问题求助

解决iOS 11下特殊字符串导致boundingRectWithSize崩溃及多行UILabel渲染崩溃的问题

这个iOS11的文本渲染坑我之前帮同事排查过,刚好能给你几个靠谱的解决方案。先说说问题根源,再看具体办法:

问题根源

这是iOS 11系统文本渲染引擎的一个已知bug,当字符串中包含某些特殊Unicode字符(比如你示例里的混合日文、emoji、特殊符号组合)时,系统在执行文本换行计算(NSParagraphArbitrator相关逻辑)时,会在-[NSString rangeOfCharacterFromSet:options:range:]方法中抛出异常,进而导致boundingRectWithSize调用崩溃,同时行数设为0的多行UILabel渲染时也会触发相同问题。

可行解决方案

方案1:过滤/替换问题字符

如果业务允许,可以提前过滤掉那些可能触发崩溃的特殊Unicode字符。你可以自定义需要过滤的字符集合,示例代码如下:

NSString *originalStr = @" しょーたฅ(๑•̀ω•́๑)ฅニャンニャンガオー★";
// 定义需要过滤的字符集合,可根据实际出现问题的字符调整
NSCharacterSet *problemChars = [NSCharacterSet characterSetWithCharactersInString:@"ฅ(๑•̀ω•́๑)ฅニャンニャンガオー★"];
// 清理字符串
NSString *cleanedStr = [[originalStr componentsSeparatedByCharactersInSet:problemChars] componentsJoinedByString:@""];

// 使用清理后的字符串计算尺寸
CGSize strSize = [cleanedStr boundingRectWithSize:CGSizeMake(281.33333, 100) 
                                          options:NSStringDrawingUsesLineFragmentOrigin | NSStringDrawingUsesFontLeading | NSStringDrawingUsesDeviceMetrics 
                                       attributes:@{NSFontAttributeName:[UIFont systemFontOfSize:16]} 
                                          context:nil].size;

⚠️ 注意:这个方案需要根据你的业务场景调整过滤规则,如果必须保留这些特殊字符,建议用下面的方案。

方案2:用CoreText手动计算文本尺寸

绕开系统的boundingRectWithSize方法,直接使用底层的CoreText来计算文本尺寸,完全避免触发上层的系统bug。示例代码:

NSString *str = @" しょーたฅ(๑•̀ω•́๑)ฅニャンニャンガオー★";
UIFont *font = [UIFont systemFontOfSize:16];
CGFloat maxWidth = 281.33333;

// 构造CoreText需要的字体和富文本
CTFontRef ctFont = CTFontCreateWithName((__bridge CFStringRef)font.fontName, font.pointSize, NULL);
NSMutableAttributedString *attributedStr = [[NSMutableAttributedString alloc] initWithString:str];
[attributedStr addAttribute:(id)kCTFontAttributeName value:(__bridge id)ctFont range:NSMakeRange(0, str.length)];

// 计算文本尺寸
CTFramesetterRef framesetter = CTFramesetterCreateWithAttributedString((__bridge CFAttributedStringRef)attributedStr);
CGSize suggestedSize = CTFramesetterSuggestFrameSizeWithConstraints(framesetter, CFRangeMake(0, 0), NULL, CGSizeMake(maxWidth, CGFLOAT_MAX), NULL);
CGSize strSize = CGSizeMake(ceil(suggestedSize.width), ceil(suggestedSize.height));

// 记得释放CoreText对象,避免内存泄漏
CFRelease(ctFont);
CFRelease(framesetter);

这个方案兼容性更好,而且不会受系统上层bug影响。

方案3:针对多行UILabel的临时修复

如果是行数设为0的UILabel渲染崩溃,可以用一个小技巧绕过:先临时把行数设为1,强制Label完成一次布局,再改回多行模式:

UILabel *multiLineLabel = [[UILabel alloc] initWithFrame:CGRectMake(0, 0, 281.33333, 100)];
multiLineLabel.font = [UIFont systemFontOfSize:16];
multiLineLabel.text = @" しょーたฅ(๑•̀ω•́๑)ฅニャンニャンガオー★";

// 临时设置行数为1,强制布局
multiLineLabel.numberOfLines = 1;
[multiLineLabel layoutIfNeeded];

// 改回多行模式,再次布局
multiLineLabel.numberOfLines = 0;
[multiLineLabel layoutIfNeeded];

这个办法能快速解决Label渲染崩溃的问题,适合不想改动文本计算逻辑的场景。

额外建议

如果你的App支持的最低系统版本可以提升到iOS12及以上,那最好不过——苹果在iOS12中已经修复了这个文本渲染的bug,不需要做任何额外处理。

内容的提问来源于stack exchange,提问作者Yanneng Zhang

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.15 04:06:36