Swift 4.0 iOS11.2.x下Codable结构体跨设备解码崩溃求助
首先,咱们先拆解一下你遇到的这个崩溃问题——*NSInvalidArgumentException*通常意味着解码时出现了类型不匹配、数据损坏或者编码/解码方式不统一的情况,结合你的场景,我给你列几个排查和解决的方向:
1. 确认编码和解码方式完全一致
你提到保存的文件不是JSON格式,那大概率是用了NSKeyedArchiver(因为Codable支持归档)。如果是这样的话,解码时必须用对应的NSKeyedUnarchiver,而且要确保两台设备上的products结构体完全一致:
- 结构体的属性名、类型、顺序(虽然Codable不依赖顺序,但归档可能有影响)必须完全相同
- 如果结构体里有嵌套类型,嵌套的类型也要同样遵循
Codable(或者NSCoding,如果用的是旧的归档方式)
举个例子,如果你保存时用的是:
let data = try NSKeyedArchiver.archivedData(withRootObject: productsArray, requiringSecureCoding: false) try data.write(to: fileURL)
那解码时必须对应:
guard let data = try? Data(contentsOf: receivedFileURL) else { return } guard let decodedProducts = try? NSKeyedUnarchiver.unarchiveTopLevelObjectWithData(data) as? [Products] else { // 解码失败的处理逻辑 return }
2. 检查AirDrop接收的文件是否完整
AirDrop传输偶尔会出现文件截断的情况,你可以在解码前先验证文件的大小和原设备上的是否一致,或者打印读取到的Data字节数,看看是否合理。另外,在AppDelegate中处理AirDrop文件时,要确保文件已经完全写入本地再解码——系统在application(_:open:options:)方法中会保证文件可用,但如果是其他接收逻辑,可能需要等待写入完成。
3. 排查类型转换错误(崩溃高发点)
崩溃的核心原因很可能是你尝试将解码后的对象转换成错误的类型。比如,你保存的是[Products]数组,但解码时却尝试转换成单个Products对象,或者反过来。建议你替换掉try?,改用do-catch捕获详细错误:
do { let data = try Data(contentsOf: receivedFileURL) // 如果用的是归档方式解码 guard let decodedProducts = try NSKeyedUnarchiver.unarchiveTopLevelObjectWithData(data) as? [Products] else { throw NSError(domain: "DecodeError", code: 0, userInfo: [NSLocalizedDescriptionKey: "无法将解码对象转换为[Products]类型"]) } // 处理解码后的产品数据 } catch { print("解码失败:\(error.localizedDescription)") print("详细错误信息:\(error)") }
这样打印的错误信息会帮你精准定位问题,比只看崩溃日志更有用。
4. 检查结构体的Codable实现
如果你的products结构体自定义了init(from decoder: Decoder)或者encode(to encoder: Encoder)方法,要仔细排查这些实现是否有逻辑错误——比如某个属性没有正确编码/解码,或者可选值处理不当。如果没有自定义需求,尽量使用系统自动合成的Codable实现,避免手动编码带来的疏漏。
内容的提问来源于stack exchange,提问作者user3069232

