Как сделать NSAttributedString совместимым кодируемым? - PullRequest
0 голосов
/ 10 января 2019

В чем проблема?

В настоящее время я создаю расширение приложения для моего основного приложения, которое взаимодействует через JSON. Темы и данные находятся в JSON и анализируются с помощью кодируемого протокола от Apple. Проблема, с которой я сейчас сталкиваюсь, - это совместимость NSAttributedString. Я знаю, что он не встроен, но я знаю, что он может быть преобразован в данные и обратно в .

Что у меня до сих пор?

Приведите NSAttributedString к данным, чтобы поделиться им через JSON.

if let attributedText = something.attributedText {
    do {
        let htmlData = try attributedText.data(from: NSRange(location: 0, length: attributedText.length), documentAttributes: [NSDocumentTypeDocumentAttribute: NSHTMLTextDocumentType])
        let htmlString = String(data: htmlData, encoding: .utf8) ?? "" 
    } catch {
        print(error)
    }
}

Привести HTML-строку JSON обратно к NSAttributedString:

do {
    return try NSAttributedString(data: self, options: [.documentType: NSAttributedString.DocumentType.html, .characterEncoding: String.Encoding.utf8.rawValue], documentAttributes: nil)
} catch {
    print("error:", error)
    return  nil
}

Мой вопрос?

Как создать структуру, имеющую свойство nsAttributedTitle, имеющее тип NSAttributedString, и сделать ее совместимой с кодируемым декодером?

Пример структуры (не задумываясь о кодируемой совместимости):

struct attributedTitle: Codable {
    var title: NSAttributedString

    enum CodingKeys: String, CodingKey {
        case title
    }

    public func encode(to encoder: Encoder) throws {}
    public init(from decoder: Decoder) throws {}
}

1 Ответ

0 голосов
/ 10 января 2019

NSAttributedString соответствует NSCoding, поэтому вы можете использовать KeyArchiver для получения Data объекта.

Чтобы соответствовать JSON и PropertyList, необходимо преобразовать данные в строку в кодировке base64.

Это возможное решение

class AttributedString : Codable {

    let attributedString : NSAttributedString

    init(nsAttributedString : NSAttributedString) {
        self.attributedString = nsAttributedString
    }

    public required init(from decoder: Decoder) throws {
        let singleContainer = try decoder.singleValueContainer()
        let base64String = try singleContainer.decode(String.self)
        guard let data = Data(base64Encoded: base64String) else { throw DecodingError.dataCorruptedError(in: singleContainer, debugDescription: "String is not a base64 encoded string") }
        guard let attributedString = try NSKeyedUnarchiver.unarchivedObject(ofClasses: [NSAttributedString.self], from: data) as? NSAttributedString else { throw DecodingError.dataCorruptedError(in: singleContainer, debugDescription: "Data is not NSAttributedString") }
        self.attributedString = attributedString
    }

    func encode(to encoder: Encoder) throws {
        let data = try NSKeyedArchiver.archivedData(withRootObject: attributedString, requiringSecureCoding: false)
        var singleContainer = encoder.singleValueContainer()
        try singleContainer.encode(data.base64EncodedString())
    }
}
...