当前,我正在通过JSON进行通信的主应用程序上构建应用程序扩展。主题和数据位于JSON中,并通过Apple的可编码协议进行解析。我现在遇到的问题是使NSAttributedString可编码兼容。我知道它不是内置的,但我知道它可以转换为数据并返回到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 {}
}
答案 0 :(得分:4)
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())
}
}