Swift 将NSAttribute字符串与可编码字符串一致会引发错误

Swift 将NSAttribute字符串与可编码字符串一致会引发错误,swift,codable,Swift,Codable,我需要将NSAttributedString数据写入并读取到一个json文件中,在此之前,我可以使用它对数据进行编码,但在解码时会抛出一个错误 class AttributedString : Codable { let attributedString : NSAttributedString init(attributedString : NSAttributedString) { self.attributedString = attributedStri

我需要将
NSAttributedString
数据写入并读取到一个json文件中,在此之前,我可以使用它对数据进行编码,但在解码时会抛出一个错误

class AttributedString : Codable {
    let attributedString : NSAttributedString

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

    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())
    }
}
以及:

错误域=NSCOCAERRORDOMAIN Code=4864“项'NS.objects'的值” 属于意外的类“NSShadow”。允许的类为{( NSGlyphInfo, UIColor, 国家统计局字典, UIFont, NSURL, 非语法风格, NSString, NSAttribute字符串, 恩萨雷, NSNumber)}.”UserInfo={NSDebugDescription=键“NS.objects”的值属于意外的类“NSShadow”。允许的类为 '{( NSGlyphInfo, UIColor, 国家统计局字典, UIFont, NSURL, 非语法风格, NSString, NSAttribute字符串, 恩萨雷, NSNumber)}.}


PS:我需要保留属性

您可以尝试
unarchiveTopLevelObjectWithData
取消归档您的AttributedString对象数据:

NSKeyedUnarchiver.unarchiveTopLevelObjectWithData(data)
作为结构实现的
attributeString
应该如下所示:

struct AttributedString {
    let attributedString: NSAttributedString
    init(attributedString: NSAttributedString) { self.attributedString = attributedString }
    init(string str: String, attributes attrs: [NSAttributedString.Key: Any]? = nil) { attributedString = .init(string: str, attributes: attrs) }
}

存档/编码

extension NSAttributedString {
    func data() throws -> Data { try NSKeyedArchiver.archivedData(withRootObject: self, requiringSecureCoding: false) }
}
extension Data {
    func topLevelObject() throws -> Any? { try NSKeyedUnarchiver.unarchiveTopLevelObjectWithData(self) }
    func unarchive<T>() throws -> T? { try topLevelObject() as? T }
    func attributedString() throws -> NSAttributedString? { try unarchive() }
}


取消归档/解码

extension NSAttributedString {
    func data() throws -> Data { try NSKeyedArchiver.archivedData(withRootObject: self, requiringSecureCoding: false) }
}
extension Data {
    func topLevelObject() throws -> Any? { try NSKeyedUnarchiver.unarchiveTopLevelObjectWithData(self) }
    func unarchive<T>() throws -> T? { try topLevelObject() as? T }
    func attributedString() throws -> NSAttributedString? { try unarchive() }
}

尝试
NSKeyedUnarchiver.unarchiveTopLevelObjectWithData(数据)为?NSAttributeString
@LeoDabus噢,谢谢,它修复了错误。如果你把它作为一个答案张贴,我可以标记它。你介意解释一下区别吗?我从来没有用过其他方法。“这是我需要时通常使用的答案。”LeoDabus,介意把它作为答案贴出来吗?
extension AttributedString: Decodable {
    public init(from decoder: Decoder) throws {
        let container = try decoder.singleValueContainer()
        guard let attributedString = try container.decode(Data.self).attributedString() else {
            throw DecodingError.dataCorruptedError(in: container, debugDescription: "Corrupted Data")
        }
        self.attributedString = attributedString
    }
}