如何使NSAttributedString可编码兼容?

Kev*_*gts 4 swift codable

问题是什么?

目前,我正在通过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)
    }
}
Run Code Online (Sandbox Code Playgroud)

将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
}
Run Code Online (Sandbox Code Playgroud)

我的问题?

如何制作一个具有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 {}
}
Run Code Online (Sandbox Code Playgroud)

vad*_*ian 6

NSAttributedString符合,NSCoding因此您可以NSKeyedArchiver用来获取Data对象。

这是一个可能的解决方案

class AttributedString : Codable {

    let attributedString : NSAttributedString

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

    public required init(from decoder: Decoder) throws {
        let singleContainer = try decoder.singleValueContainer()
        guard let attributedString = try NSKeyedUnarchiver.unarchiveTopLevelObjectWithData(singleContainer.decode(Data.self)) as? NSAttributedString else {
            throw DecodingError.dataCorruptedError(in: singleContainer, debugDescription: "Data is corrupted")
        }
        self.attributedString = attributedString
    }

    public func encode(to encoder: Encoder) throws {
        var singleContainer = encoder.singleValueContainer()
        try singleContainer.encode(NSKeyedArchiver.archivedData(withRootObject: attributedString, requiringSecureCoding: false))
    }
}
Run Code Online (Sandbox Code Playgroud)