UITextView添加段落属性触发NSMutableRLEArray越界错误
错误原因及修复方案
核心问题点
NSMakeRange参数使用错误:NSMakeRange的入参规则是NSMakeRange(起始位置, 区间长度),你代码中直接把结束下标作为第二个参数传入,生成的区间长度等于结束下标值,最终区间上限为startIndex + endIndex,必然超出文本总长度,直接触发越界崩溃。- 字符计数体系不匹配:Swift原生
String的count是基于Unicode字符的计数,而UITextView的selectedRange、textStorage均使用NSString的UTF-16计数规则,当文本包含emoji、多字节字符时,直接通过String.enumerated()获取的下标转换为NSRange会出现位置错位,也会触发越界。 - 边界场景未处理:当光标位于文本最开头时,
textView.selectedRange.location为0,你传入的position为-1,段落查找逻辑直接失效,会生成非法范围。
修复后代码
// 统一转换为NSString处理,保证计数体系匹配 func findParagraphBy(position: Int) -> NSRange? { guard position >= 0, !textView.text.isEmpty else { return nil } let text = textView.text as NSString var startIndex = 0 var endIndex = text.length - 1 // 往前找最近的换行符 if position > 0 { let preRange = NSMakeRange(0, position) startIndex = text.range(of: "\n", options: .backwards, range: preRange).upperBound } // 往后找最近的换行符 let postRange = NSMakeRange(position, text.length - position) let postNewLineRange = text.range(of: "\n", range: postRange) if postNewLineRange.location != NSNotFound { endIndex = postNewLineRange.lowerBound } // 正确计算长度:结束下标 - 起始下标 let length = endIndex - startIndex guard length >= 0 else { return nil } return NSMakeRange(startIndex, length) } func applyAttr(){ guard textView.selectedRange.location > 0 else { return } guard let range = findParagraphBy(position: textView.selectedRange.location - 1) else { return } self.textView.textStorage.addAttributes(self.currentAttribute.getAttr(), range: range) }
内容的提问来源于stack exchange,提问作者NewUser
相关产品推荐
相关产品推荐

