0

当我尝试将属性应用于子字符串时,有时会在以下代码中崩溃:

// Dummy strings
let originalString = "Some example string"
let searchSubString = "exam"

// Get range of sub-string for which new attributes are to be set.
let rangeOfSubString: NSRange = (originalString.lowercaseString as NSString).rangeOfString(searchSubString.lowercaseString)

// Apply new attributes to the sub-string in original string and show it in UILabel.
let attributedOriginalString = NSMutableAttributedString(string: originalString, attributes: [NSForegroundColorAttributeName : UIColor.blueColor()])
attributedOriginalString.addAttribute(NSFontAttributeName, value: UIFont.systemFontOfSize(14.0), range: rangeOfSubString)
attributedOriginalString.addAttribute(NSForegroundColorAttributeName, value: UIColor.redColor(), range: rangeOfSubString)
self.textLabel.attributedText = attributedOriginalString

以下是堆栈跟踪:

Thread : Fatal Exception: NSRangeException
0 CoreFoundation 0x26cbefef __exceptionPreprocess
1 libobjc.A.dylib 0x35362c8b objc_exception_throw
2 CoreFoundation 0x26cbef35 -[NSException initWithCoder:]
3 Foundation 0x2793ac3b -[NSRLEArray objectAtIndex:effectiveRange:]
4 Foundation 0x27954b2d -[NSConcreteMutableAttributedString addAttribute:value:range:]

虽然我无法重现它,但我通过 crashlytics 得到了这个崩溃日志。

崩溃日志似乎说rangeOfSubString超出了 的范围originalString,但我认为它永远不会发生。

谁能指出我坠机的原因是什么?

4

1 回答 1

0

如果其他人遇到此类问题,请发布我的答案:

代替

let rangeOfSubString: NSRange = (originalString.lowercaseString as NSString).rangeOfString(searchSubString.lowercaseString)

let rangeOfSubString: NSRange = (originalString as NSString).rangeOfString(searchSubString, options: .CaseInsensitiveSearch)

计算子字符串范围的第一种方法是错误的原因:

  • 它正在计算子字符串范围 WRT 小写版本并将该范围的属性应用于原始字符串(非小写)。但是如果是特殊字符,使用上述方法计算的范围可能会超出原始字符串范围,因为小写字符可能比大写字符需要更多的长度,反之亦然。

    即大写土耳其字符“İ”的长度为 1,而其小写版本“i̇”的长度为 2。

  • 例如。如果我们在 "Hİ"(length = 2) 中搜索 "İ",第一种方法会给你一个 range(1, 2) 因为小写的 "İ" 需要长度 = 2,但如果你应用 range(1, 2 ) 到“Hİ”,它将超出其范围(0, 2),或者如果原始字符串中有更多字符,如“Hİabc”,它将对应于“İa”,这又是错误的。

  • 所以计算范围 WRT 原始字符串,因为稍后我需要将该范围应用于原始字符串本身。

另请参阅苹果的文档:

小写字符串:

不保证大小写转换是对称的或生成与原始字符串长度相同的字符串。

lcString = [myString 小写字符串];

可能不等于以下语句:

lcString = [[myString 大写字符串] 小写字符串];

例如,德语中“ß”的大写形式是“SS”,因此将“Straße”转换为大写,然后是小写,会产生以下字符串序列:

“大街”</p>

“STRASSE”</p>

“大街”</p>

https://developer.apple.com/library/mac/documentation/Cocoa/Reference/Foundation/Classes/NSString_Class/#//apple_ref/occ/instp/NSString/lowercaseString

于 2016-02-03T16:11:07.577 回答