Swift 4结合Realm使用Codable解码JSON遇Decodable合规错误求助
解决Realm + Codable的解码错误问题
嘿,我看你在把Codable和Realm结合的时候碰到解码报错了,问题主要出在模型结构和JSON层级不匹配,还有Realm的List类型需要特殊处理解码逻辑~咱们一步步来解决:
首先先明确你的JSON结构层级,方便对应模型:
{ "success": true, "message": "got the locations!", "data": { "LocationList": [ { "LocID": 1, "LocName": "Downtown" }, { "LocID": 2, "LocName": "Uptown" }, { "LocID": 3, "LocName": "Midtown" } ] } }
你当前模型的核心问题
- 层级错位:根节点的
success应该在最外层模型里,而你把data定义成了List<LocationData>,但JSON里的data是单个对象,不是数组;真正的数组是data里的LocationList。 - Realm
List不支持默认Codable:原生Codable没有对RealmList的解码支持,必须手动实现解码逻辑。
修正后的完整模型代码
import RealmSwift // 对应JSON根节点的模型 class LocationResponse: Object, Decodable { @objc dynamic var success: Bool = false @objc dynamic var message: String = "" @objc dynamic var data: LocationData? // JSON里的data是单个对象,用可选Object类型 // 映射JSON字段和模型属性 enum CodingKeys: String, CodingKey { case success, message, data } // 自定义解码方法,同时满足Realm Object的初始化要求 required init(from decoder: Decoder) throws { let container = try decoder.container(keyedBy: CodingKeys.self) success = try container.decode(Bool.self, forKey: .success) message = try container.decode(String.self, forKey: .message) data = try container.decodeIfPresent(LocationData.self, forKey: .data) // 必须调用Realm Object的默认初始化方法 super.init() } // Realm Object强制要求的空初始化方法 required init() { super.init() } // Realm Object强制要求的Schema初始化方法 required init(value: Any, schema: ObjectSchema) { super.init(value: value, schema: schema) } } // 对应JSON里的data对象 class LocationData: Object, Decodable { let locationList = List<LocationItem>() // 对应JSON里的LocationList数组 enum CodingKeys: String, CodingKey { case locationList = "LocationList" // 映射JSON的大写字段到Swift小驼峰命名 } required init(from decoder: Decoder) throws { let container = try decoder.container(keyedBy: CodingKeys.self) // 先解码成Swift原生数组,再转成Realm List let items = try container.decode([LocationItem].self, forKey: .locationList) locationList.append(objectsIn: items) super.init() } required init() { super.init() } required init(value: Any, schema: ObjectSchema) { super.init(value: value, schema: schema) } } // 对应单个地点的模型 class LocationItem: Object, Decodable { @objc dynamic var locID: Int = 0 // 用Swift规范的小驼峰命名 @objc dynamic var locName: String = "" enum CodingKeys: String, CodingKey { case locID = "LocID" case locName = "LocName" } // 属性都有默认值,无需自定义解码方法,Codable会自动处理 required init() { super.init() } required init(value: Any, schema: ObjectSchema) { super.init(value: value, schema: schema) } }
关键要点说明
- 层级对齐:
LocationResponse对应整个JSON根节点,data是单个LocationData对象,LocationData里的locationList才是存储地点的数组。 - CodingKeys映射:既符合Swift的命名规范,又能准确对应JSON的字段名,还能避免和Realm内部属性冲突。
- List解码技巧:先把JSON数组解码成Swift原生的
[LocationItem],再通过append(objectsIn:)把元素添加到Realm的List中。 - Realm初始化要求:所有继承自
Object的类必须实现三个初始化方法,否则会报错。
测试解码的示例代码
// 假设你有JSON字符串转成的Data对象 if let jsonData = yourJsonString.data(using: .utf8) { do { let response = try JSONDecoder().decode(LocationResponse.self, from: jsonData) // 解码成功后,将地点数据存入Realm let realm = try Realm() try realm.write { realm.add(response.data?.locationList ?? List(), update: .modified) } } catch { print("解码错误:\(error)") } }
内容的提问来源于stack exchange,提问作者Misha
相关产品推荐
相关产品推荐

