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

NSRangeException异常求助:索引越界问题及相关代码排查

排查NSRangeException索引越界问题

这个问题我之前帮同事排查过,大概率是iOS基于WebKit的HTML文本解析器在处理RTL(从右到左)文本+特定字体时的内部bug,结合你的代码和异常信息,具体分析和解决方法如下:

问题原因分析

  • iOS的NSHTMLTextDocumentType解析器依赖WebKit内核,当处理RTL排版(比如你设置的direction: RTL)+Mehr Nastaliq Web这类波斯/乌尔都语字体时,对复杂连字、特殊Unicode字符(比如零宽空格、组合字符)的索引计算容易出现偏差,导致内部维护的字符串长度和实际字符数不匹配,触发characterAtIndex:的索引越界。
  • 你使用的NSUnicodeStringEncoding编码方式也可能加剧这个问题,WebKit对UTF-8编码的HTML支持更稳定,Unicode编码可能在解析时产生额外的字符处理逻辑错误。

可行的解决方法

1. 更换HTML字符串编码为UTF-8

这是最容易尝试的修复方式,把NSUnicodeStringEncoding换成NSUTF8StringEncoding,很多时候能直接解决解析时的索引计算问题:

NSString *htmlString = [NSString stringWithFormat:@"<html> <head><style type=\"text/css\">body { font-family: Mehr Nastaliq Web; font-size: 22pt; white-space: pre-wrap; text-align: right; lang: ar; direction: RTL; -webkit-user-select: none; }</style> </head><body leftmargin=\"20\" topmargin=\"0\" rightmargin=\"20\" > %@ </body></html>",str];
// 改用UTF-8编码
NSData *htmlData = [htmlString dataUsingEncoding:NSUTF8StringEncoding];
NSAttributedString *attributedString = [[NSAttributedString alloc] initWithData:htmlData
                                                                       options: @{ NSDocumentTypeDocumentAttribute:NSHTMLTextDocumentType }
                                                            documentAttributes: nil
                                                                         error: nil];
self.txtView.attributedText=attributedString;

2. 预处理字符串,清理特殊字符

如果你的str中包含零宽空格、不可见控制字符或者异常Unicode组合字符,先过滤掉这些字符能减少解析器的出错概率:

// 移除零宽空格、控制字符等可能干扰解析的特殊字符
NSString *cleanedStr = [str stringByReplacingOccurrencesOfString:@"[\u200B-\u200F\uFEFF\u0000-\u001F]" withString:@"" options:NSRegularExpressionSearch range:NSMakeRange(0, str.length)];
// 用清理后的字符串生成HTML
NSString *htmlString = [NSString stringWithFormat:@"<html> <head><style type=\"text/css\">body { font-family: Mehr Nastaliq Web; font-size: 22pt; white-space: pre-wrap; text-align: right; lang: ar; direction: RTL; -webkit-user-select: none; }</style> </head><body leftmargin=\"20\" topmargin=\"0\" rightmargin=\"20\" > %@ </body></html>",cleanedStr];

3. 绕开HTML解析,直接用NSAttributedString设置排版属性

如果HTML解析的bug难以规避,直接用原生的NSAttributedString属性来实现RTL排版和字体设置,完全绕开WebKit解析:

// 创建可变属性字符串
NSMutableAttributedString *mutableAttrStr = [[NSMutableAttributedString alloc] initWithString:str];

// 设置RTL段落样式
NSMutableParagraphStyle *paragraphStyle = [[NSMutableParagraphStyle alloc] init];
paragraphStyle.baseWritingDirection = NSWritingDirectionRightToLeft;
paragraphStyle.alignment = NSTextAlignmentRight;
paragraphStyle.firstLineHeadIndent = 20;
paragraphStyle.tailIndent = -20;
[mutableAttrStr addAttribute:NSParagraphStyleAttributeName value:paragraphStyle range:NSMakeRange(0, mutableAttrStr.length)];

// 设置字体和禁止选中属性
UIFont *nastaliqFont = [UIFont fontWithName:@"Mehr Nastaliq Web" size:22.0];
[mutableAttrStr addAttribute:NSFontAttributeName value:nastaliqFont range:NSMakeRange(0, mutableAttrStr.length)];
[mutableAttrStr addAttribute:NSUserInterfaceItemIdentifierAttributeName value:@"-webkit-user-select: none" range:NSMakeRange(0, mutableAttrStr.length)];

self.txtView.attributedText = mutableAttrStr;

4. 添加异常捕获作为兜底方案

如果以上方法都无法完全避免崩溃,可以添加异常捕获逻辑,当解析失败时回退到普通字符串显示,保证App不崩溃:

NSString *htmlString = [NSString stringWithFormat:@"<html> <head><style type=\"text/css\">body { font-family: Mehr Nastaliq Web; font-size: 22pt; white-space: pre-wrap; text-align: right; lang: ar; direction: RTL; -webkit-user-select: none; }</style> </head><body leftmargin=\"20\" topmargin=\"0\" rightmargin=\"20\" > %@ </body></html>",str];
NSAttributedString *attributedString;

@try {
    NSData *htmlData = [htmlString dataUsingEncoding:NSUTF8StringEncoding];
    attributedString = [[NSAttributedString alloc] initWithData:htmlData
                                                         options: @{ NSDocumentTypeDocumentAttribute:NSHTMLTextDocumentType }
                                              documentAttributes: nil
                                                           error: nil];
} @catch (NSException *exception) {
    NSLog(@"HTML解析触发异常: %@", exception);
    // 回退到普通字符串
    attributedString = [[NSAttributedString alloc] initWithString:str];
}

self.txtView.attributedText = attributedString;

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.28 04:23:25