Swift:NSAttributedString 和表情符号

The*_*ow_ 2 nsattributedstring ios emoji nsrange swift

我使用UITextView启用了文本属性编辑的 ,当文本中有表情符号时,我在获取属性时遇到问题。

这是我使用的代码:

var textAttributes = [(attributes: [NSAttributedString.Key: Any], range: NSRange)]()
let range = NSRange(location: 0, length: textView.attributedText.length)
textView.attributedText.enumerateAttributes(in: range) { dict, range, _ in
    textAttributes.append((attributes: dict, range: range))
}

for attribute in textAttributes {
    if let swiftRange = Range(attribute.range, in: textView.text) {
        print("NSRange \(attribute.range): \(textView.text![swiftRange])")
    } else {
        print("NSRange \(attribute.range): cannot convert to Swift range")
    }
}
Run Code Online (Sandbox Code Playgroud)

当我尝试使用“示例文本 ??”之类的文本时,输出如下:

NSRange {0, 12}:示例文本

NSRange {12, 1}:无法转换为 Swift 范围

NSRange {13, 1}:无法转换为 Swift 范围

如您所见,我无法获取带有表情符号的文本。

文本属性由我NSTextStorage在文本视图上应用的自定义设置。这是setAttributes方法:

override func setAttributes(_ attrs: [NSAttributedString.Key: Any]?, range: NSRange) {
    guard (range.location + range.length - 1) < string.count  else {
        print("Range out of bounds")
        return
    }

    beginEditing()
    storage.setAttributes(attrs, range: range)
    edited(.editedAttributes, range: range, changeInLength: 0)
    endEditing()
}
Run Code Online (Sandbox Code Playgroud)

请注意,在编辑我的文本视图期间,我有一些“超出范围”的打印。

有没有办法将 转换NSRange为有效的 Swift Range

rma*_*ddy 10

使用NSAttributedString,NSRange和时要记住的最重要的事情StringNSAttributedString(和NSString) andNSRange基于 UTF-16 编码长度。但是Stringcount是基于实际的字符数。他们不混合。

如果您尝试创建NSRangewith someSwiftString.count,您将得到错误的范围。始终使用someSwiftString.utf16.count.

在您的特定情况下,您将属性应用于 ?? 由于长度错误而导致的字符,NSRange并且会导致您看到的错误。

在您发布的代码中,您需要更改:

guard (range.location + range.length - 1) < string.count else {
Run Code Online (Sandbox Code Playgroud)

到:

guard (range.location + range.length - 1) < string.utf16.count else {
Run Code Online (Sandbox Code Playgroud)

出于上述相同的原因。