Swift: NSAttributedString & emojis - PullRequest
       74

Swift: NSAttributedString & emojis

0 голосов
/ 06 июня 2019

Я использую 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")
    }
}

И когда я пробую это с текстом типа «Образец текста ❤️», вот что получится:

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()
}

Обратите внимание, что во время редактирования моего текстового представления у меня есть некоторые распечатки "Range of the bounds".

Есть ли способ конвертировать NSRange до действительного Swift Range?

1 Ответ

1 голос
/ 06 июня 2019

Самое важное, что следует помнить при работе с NSAttributedString, NSRange и String, это то, что NSAttributedStringNSString) и NSRange основаны на кодированных длинах UTF-16.Но String и count основаны на фактическом количестве символов.Они не смешиваются.

Если вы когда-нибудь попытаетесь создать NSRange с someSwiftString.count, вы получите неправильный диапазон.Всегда используйте someSwiftString.utf16.count.

В вашем конкретном случае вы применяете атрибуты к половине для символа due из-за неправильной длины в NSRange и каскадных ошибок, которые вы видите.

И в коде, который вы разместили, вам нужно изменить:

guard (range.location + range.length - 1) < string.count else {

на:

guard (range.location + range.length - 1) < string.utf16.count else {

по тем же причинам, что описаны выше.

...