使用PropertyList编解码时为何出现“Expected to decode Data but found an array instead”错误?
问题分析与解决方案
这个错误的核心原因是你编码的是可选类型的Data(Data?),但解码时却尝试解析为非可选的Data,而PropertyListEncoder对可选Data的编码行为,导致最终存储的是数组结构,和你期望的Data类型不匹配。
具体细节
你在encode(to:)方法中直接传入了UIImagePNGRepresentation(image)的返回值——这是一个Data?类型。PropertyListEncoder在处理可选Data时,会将其编码为属性列表中的数组格式(底层是把NSOptional包装的NSData序列化为字节数组)。而你解码时调用container.decode(Data.self, forKey: .image),期望得到一个Data类型,但实际读取到的是数组,因此触发类型不匹配错误。
修复方案
你需要确保编码的是非可选的Data,先对UIImagePNGRepresentation的结果进行解包验证,再执行编码:
修改你的encode(to:)方法:
func encode(to encoder: Encoder) throws { var container = encoder.container(keyedBy: CodingKeys.self) try container.encode(rect, forKey: .rect) // 先验证并解包PNG数据,避免编码可选类型 guard let pngData = UIImagePNGRepresentation(image) else { throw EncodingError.invalidValue( image, EncodingError.Context( codingPath: [CodingKeys.image], debugDescription: "无法将UIImage转换为PNG格式数据" ) ) } try container.encode(pngData, forKey: .image) }
这样修改后,你编码的是确定存在的Data类型,PropertyListEncoder会将其正确序列化为属性列表中的NSData对应格式,解码时就能正常解析为Data,进而转换成UIImage。
另外,建议你在解码时也去掉强制解包!,改用安全的可选绑定,避免因数据损坏导致崩溃:
init(from decoder: Decoder) throws { let container = try decoder.container(keyedBy: CodingKeys.self) rect = try container.decode(CGRect.self, forKey: .rect) let imageData = try container.decode(Data.self, forKey: .image) guard let decodedImage = UIImage(data: imageData) else { throw DecodingError.dataCorrupted( DecodingError.Context( codingPath: [CodingKeys.image], debugDescription: "无法将解码后的数据转换为UIImage" ) ) } image = decodedImage }
这样你的编解码流程会更健壮,同时彻底解决类型不匹配的问题。
内容的提问来源于stack exchange,提问作者Sweeper
相关产品推荐
相关产品推荐

