Swift NSKeyedUnarchiver 在从字符串转换为数据后失败

Swift NSKeyedUnarchiver Failing After Converting from String to Data

我有一个符合 NSCoding 的 class。我想将 class 转换为数据,然后转换为可以存储在后端的字符串。

问题是,一旦它从 String 转换回 Data,它就无法使用 NSKeyedUnarchiver 正确解档,因此转换为字符串一定会破坏数据。

代码如下:

  do {
        let data = try NSKeyedArchiver.archivedData(withRootObject: drawItems, requiringSecureCoding: false)
        let stringData = String(decoding: data, as: UTF8.self)
        
        print("HERE successfully converted to a string: ", stringData)
        
        let stringBackToData: Data? = stringData.data(using: .utf8)
        if let stringBackToData = stringBackToData, let allItems = try NSKeyedUnarchiver.unarchiveTopLevelObjectWithData(stringBackToData) as? [DrawItem] {
            print("HERE items: ", allItems)
        } else {
            print("HERE FAILED to unarchive")
        }
        
    catch {
            print("Failed: ", error)
    }

这个字符串转换有什么问题?

默认outputFormat for NSKeyedArchiver is .binary, which is not convertible to or from UTF-8. In your example, String(decoding: data, as: UTF8.self) "repairs" invalid UTF-8 bytes by replacing them with the UTF-8 replacement character(0xFFFD).

这会破坏存档数据,并阻止其正确解码。

如果您确实无法将二进制数据按原样传输到您的后端,或者无法以这种方式存储,并且必须将数据转换为字符串,您有两个选择:

  1. NSKeyedArchiver.xml 的备用 .outputFormat,它生成 UTF-8 XML 数据。您可以通过创建归档器并对其进行配置来生成此数据:

    let archiver = NSKeyedArchiver(requiringSecureCoding: false)
    archiver.outputFormat = .xml
    archiver.encode(drawItems, forKey: NSKeyedArchiveRootObjectKey)
    
    if let error = archiver.error {
        // Handle the error. This is the same error that would be produced
        // by `NSKeyedArchiver.archivedData(withRootObject:requiringSecureCoding:)`
    } else {
        let data = archiver.encodedData
        // `data` is UTF-8 XML data ready to be transmitted/stored
    }
    
  2. 或者,您可以继续使用现在的便捷方法,但是Base64 encode它:

     let data = try NSKeyedArchiver.archivedData(withRootObject: drawItems, requiringSecureCoding: false)
     let base64EncodedData = data.base64EncodedString()
    

您使用哪种取决于您:就其本身而言,base64 编码的字符串比原始 XML 数据短(因为起始二进制数据明显小于其等效 XML ),但 XML 数据确实比 base64 数据压缩得好得多,而且很可能最终变得更小。您可以测试这两种方法,看看哪种方法更适合您的用例。