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

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.09.24 21:45:10