Ios NSRangeException by String.subscript.getter
我在Ios NSRangeException by String.subscript.getter,ios,swift,Ios,Swift,我在Extension中编写了这个mid方法 func mid(fromIndex: Int, toIndex: Int) -> String { var _fromIndex = 0 if( fromIndex >= self.count ) { return "" } else if( fromIndex > 0 ){ _fromIndex = fromIndex } var _toInd
Extension
中编写了这个mid
方法
func mid(fromIndex: Int, toIndex: Int) -> String {
var _fromIndex = 0
if( fromIndex >= self.count ) {
return ""
}
else if( fromIndex > 0 ){
_fromIndex = fromIndex
}
var _toIndex = 0
if( toIndex >= self.count ) {
_toIndex = self.count - 1
}
else if( toIndex > 0 ){
_toIndex = toIndex
}
if( _fromIndex > _toIndex ){
return ""
}
return String(self[self.index(self.startIndex, offsetBy: _fromIndex)...self.index(self.startIndex, offsetBy: _toIndex)])
}
并使用此方法检索用户删除的字符串
func textView(_ textView: UITextView, shouldChangeTextIn range: NSRange, replacementText text: String) -> Bool {
defer{
if text.isEmpty {
let deletedText = textView.attributedText.string.mid(fromIndex: range.lowerBound, toIndex: range.upperBound)
}
}
}
但它有时会抛出这个例外
let deletedText = (contents as NSString).substring(with: range)
致命异常:NSRangeException
***-[NSBigMutableString characterAtIndex:]:索引672超出范围;字符串长度672
专用字符串.subscript.getter
在使用string.subscript.getter
之前,我已经检查了字符串的大小
if( toIndex >= self.count ) {
_toIndex = self.count - 1
}
文本操作应该在主线程上。
为什么我仍然得到这个例外?
我是否误解了Swift中的字符串索引
更新1
根据@Wattholm的回答。
我使用这种方法从UITextView
获取带有NSRange
的文本
let contents: String = textView.text
if let _range = Range(range, in: contents) {
let deletedText = String(contents[_range])
}
else {
logHelper.w("Failed to get deletedText from NSRange, try UITextRange.")
if let startPosition = textView.position(from: textView.beginningOfDocument, offset: range.location),
let endPosition = textView.position(from: startPosition, offset: range.length),
let textRange = textView.textRange(from: startPosition, to: endPosition),
let deletedText = textView.text(in: textRange) {
// do something with deletedText
}
else {
logHelper.w("Failed to get deletedText from UITextRange, try NSString.")
let deletedText = (contents as NSString).mid(fromIndex: range.lowerBound, toIndex: range.upperBound)
}
}
但它仍然会落入第二个else
和抛出NSRangeException
。
这意味着长度和索引仍然不匹配
更新2
尝试使用NSString.substring
,但仍不断出现此异常
let deletedText = (contents as NSString).substring(with: range)
也许UITextView中存在错误?我可能错了,但我认为这里的问题与String和NSString之间或Range和NSRange之间的固有差异有关。字符串的计数并不总是与NSString的长度相同 可能有一种更简单的方法,但我尝试的是以与为String创建扩展相同的方式为NSString创建扩展,然后将“contents”(我假设是字符串;这里似乎缺少一些代码,因为“contents”没有在任何地方声明)强制转换为NSString,以便它能够正常工作,由于textview为我们提供了NSRange:
extension NSString {
func mid(fromIndex: Int, toIndex: Int) -> NSString {
var _fromIndex = 0
if( fromIndex >= self.length ) {
return ""
}
else if( fromIndex > 0 ){
_fromIndex = fromIndex
}
var _toIndex = 0
if( toIndex >= self.length ) {
_toIndex = self.length - 1
}
else if( toIndex > 0 ){
_toIndex = toIndex
}
if( _fromIndex > _toIndex ){
return ""
}
return NSString(string: self.substring(with: NSRange(location: _fromIndex, length: _toIndex - _fromIndex + 1)))
}
}
对于文本视图:
func textView(_ textView: UITextView, shouldChangeTextIn range: NSRange, replacementText text: String) -> Bool {
defer{
if text.isEmpty {
let deletedText = (contents as NSString).mid(fromIndex: range.lowerBound, toIndex: range.upperBound - 1)
}
}
}
另一种方法是将NSRange转换为一个范围,这可能是更好的方法,尤其是当您要求字符计数与字符串在Swift中的字符计数完全相同时。textview函数中的范围:NSRange可以转换为如下范围:
设swiftRange=Range(范围,单位:rangeText)
其中rangeText应替换为range所引用的text属性。我可能错了,但我认为这里的问题与String和NSString之间或range和NSRange之间的固有差异有关。字符串的计数并不总是与NSString的长度相同 可能有一种更简单的方法,但我尝试的是以与为String创建扩展相同的方式为NSString创建扩展,然后将“contents”(我假设是字符串;这里似乎缺少一些代码,因为“contents”没有在任何地方声明)强制转换为NSString,以便它能够正常工作,由于textview为我们提供了NSRange:
extension NSString {
func mid(fromIndex: Int, toIndex: Int) -> NSString {
var _fromIndex = 0
if( fromIndex >= self.length ) {
return ""
}
else if( fromIndex > 0 ){
_fromIndex = fromIndex
}
var _toIndex = 0
if( toIndex >= self.length ) {
_toIndex = self.length - 1
}
else if( toIndex > 0 ){
_toIndex = toIndex
}
if( _fromIndex > _toIndex ){
return ""
}
return NSString(string: self.substring(with: NSRange(location: _fromIndex, length: _toIndex - _fromIndex + 1)))
}
}
对于文本视图:
func textView(_ textView: UITextView, shouldChangeTextIn range: NSRange, replacementText text: String) -> Bool {
defer{
if text.isEmpty {
let deletedText = (contents as NSString).mid(fromIndex: range.lowerBound, toIndex: range.upperBound - 1)
}
}
}
另一种方法是将NSRange转换为一个范围,这可能是更好的方法,尤其是当您要求字符计数与字符串在Swift中的字符计数完全相同时。textview函数中的范围:NSRange可以转换为如下范围:
设swiftRange=Range(范围,单位:rangeText)
其中rangeText应替换为该范围所指的text属性。这是一个更快速的版本,它利用了从NSRange
到range
的可靠转换,反之亦然
extension String {
func mid(fromIndex: Int, toIndex: Int) -> String {
guard toIndex >= fromIndex else { return "" }
let nsRange = NSRange(location: fromIndex, length: toIndex + 1 - fromIndex)
guard let range = Range(nsRange, in: self) else { return "" }
return String(self[range])
}
}
实际上,您不需要扩展,因为您已经有了一个NSRange
,只需编写
func textView(_ textView: UITextView, shouldChangeTextIn range: NSRange, replacementText text: String) -> Bool {
defer{
if text.isEmpty {
let textViewString = textView.attributedText.string
guard let swiftRange = Range(range, in: textViewString) else { return }
let deletedText = String(textViewString[swiftRange])
}
}
}
这是一个更快速的版本,它利用了从NSRange
到Range
的可靠转换,反之亦然
extension String {
func mid(fromIndex: Int, toIndex: Int) -> String {
guard toIndex >= fromIndex else { return "" }
let nsRange = NSRange(location: fromIndex, length: toIndex + 1 - fromIndex)
guard let range = Range(nsRange, in: self) else { return "" }
return String(self[range])
}
}
实际上,您不需要扩展,因为您已经有了一个NSRange
,只需编写
func textView(_ textView: UITextView, shouldChangeTextIn range: NSRange, replacementText text: String) -> Bool {
defer{
if text.isEmpty {
let textViewString = textView.attributedText.string
guard let swiftRange = Range(range, in: textViewString) else { return }
let deletedText = String(textViewString[swiftRange])
}
}
}
deletedText=contents.mid()
-你是说textView.text
而不是contents
?还要注意toIndex
是self.count+17
的情况。对不起,我忘了提到内容来自textView.AttributeText.string
。发生错误时,您是否可以在textView中提供字符串文本,以便我可以复制错误?我还想知道,在NSRangeException发生之前,用户是如何触发对ShouldChangeTextIn的调用的?如果您可以将一些数据记录到控制台,例如下限、上限、内容、删除文本,也可能会发生这种情况。deletedText=contents.mid()
-您是指textView.text
而不是contents
?请注意toIndex
是self.count+17
的情况。例如:?@Yonat抱歉,我忘了提到内容来自textView.AttributeText.string
。发生错误时,您是否可以在textView中提供字符串文本,以便我可以复制错误?我还想知道,在NSRangeException发生之前,用户是如何触发对ShouldChangeTextIn的调用的?如果您可以将一些数据记录到控制台,例如下限、上限、内容、删除的文本,也可以这样做。contents
来自textView.attributedText.string
。我已经编辑了代码段。内容
来自textView.attributedText.string
。我已经编辑了代码段。我已经在我的应用程序中使用了Range(Range,in:textViewString)
。您可以在UPDATE1中看到这一行。但它仍然落在第二个else
中。可能范围与内容不匹配?我已经在我的应用程序中使用了range(range,in:textViewString)
。您可以在UPDATE1中看到这一行。但它仍然落在第二个else
中。可能范围与内容不匹配?