Swift UITextView取子串报String index is out of bounds崩溃如何解决
崩溃原因
- 直接调用
index(_:offsetBy:)时未做边界校验:在UITextView末尾输入字符时,replacementTextRange.charIndex + replacementTextRange.length等于甚至超过当前文本的总长度,偏移量超出字符串合法范围直接触发越界崩溃。 - 额外隐患:UITextView原生回调的范围是基于UTF-16计数的
NSRange,如果直接把NSRange的location当做Swift String的偏移量使用,遇到emoji、中文等多字节字符时会出现计算偏差,也可能触发越界问题。
修复方案
方案1:添加边界校验,使用安全索引API
使用Swift提供的index(_:offsetBy:limitedBy:)方法创建索引,提前拦截越界场景:
let text = textString.text let startOffset = replacementTextRange.charIndex let endOffset = startOffset + replacementTextRange.length // 先校验总偏移量不超过文本长度 guard endOffset <= text.count else { // 越界时可根据业务需要兜底,比如取到文本末尾 let currentTextForReplacement = String(text.suffix(from: text.index(text.startIndex, offsetBy: min(startOffset, text.count)))) return } // 安全创建起止索引 guard let substringStart = text.index(text.startIndex, offsetBy: startOffset, limitedBy: text.endIndex), let subStringEnd = text.index(text.startIndex, offsetBy: endOffset, limitedBy: text.endIndex) else { let currentTextForReplacement = "" return } let currentTextForReplacementRange = substringStart..<subStringEnd let currentTextForReplacement = String(text[currentTextForReplacementRange])
方案2:直接转换NSRange为Swift Range(更推荐)
如果你的replacementRange是从UITextViewDelegate回调中拿到的原生NSRange,可以直接用系统提供的转换方法,完全避免手动计算偏移量出错:
let text = textString.text // 直接把NSRange转换为Swift String的Range guard let swiftRange = Range(replacementTextRange, in: text) else { // 范围不合法时兜底 let currentTextForReplacement = "" return } let currentTextForReplacement = String(text[swiftRange])
该方案同时解决了多字节字符计数偏差和越界两个问题,适配性更强
内容的提问来源于stack exchange,提问作者userNew
相关产品推荐
相关产品推荐

