When I make a model for my JSON file, I get these two errors.
1) I got the conform error in AreaData struct
2) " AnyObject
cannot be used as a type conforming to protocol Decodable
because Decodable
has static requirements" error in initialiser.
I have tried several ways but I cannot find the correct solution. How can I make a proper model for this nested/complex JSON?
Here is my JSON file. This data is nested
[
{
"ID": "01",
"Name": "Area 01",
"parentId": null,
"sublevel": [
{
"ID": "01-01",
"Name": "Building 01",
"On": "",
"Off": "",
"parentId": "01",
"sublevel": [
{
"ID": "01-01-01",
"Name": "Flat 01",
"On": "",
"Off": "",
"parentId": "01-01",
"sublevel": []
}
]
},
{
"ID": "01-02",
"Name": "Building 02",
"On": "01",
"Off": "03",
"parentId": "01",
"sublevel": [
{
"ID": "01-02-01",
"Name": "Flat 01",
"On": "",
"Off": "",
"parentId": "01-02",
"sublevel": []
},
{
"ID": "01-02-02",
"Name": "Flat 02",
"On": "01",
"Off": "02",
"parentId": "01-02",
"sublevel": []
},
{
"ID": "01-02-03",
"Name": "Flat 03",
"On": "02",
"Off": "12",
"parentId": "01-02",
"sublevel": [
{
"ID": "01-02-03-01",
"Name": "Room 01",
"On": "",
"Off": "",
"parentId": "01-02-03",
"sublevel": []
},
{
"ID": "01-02-03-02",
"Name": "Room 02",
"On": "",
"Off": "",
"parentId": "01-02-03",
"sublevel": []
},
{
"ID": "01-02-03-03",
"Name": "Room 03",
"On": "02",
"Off": "03",
"parentId": "01-02-03",
"sublevel": []
},
{
"ID": "01-02-03-04",
"Name": "Room 04",
"On": "",
"Off": "",
"parentId": "01-02-03",
"sublevel": []
},
{
"ID": "01-02-03-05",
"Name": "Room 05",
"On": "01",
"Off": "",
"parentId": "01-02-03",
"sublevel": []
}
]
},
{
"ID": "01-02-04",
"Name": "Flat 04",
"On": "12",
"Off": "03",
"parentId": "01-02",
"sublevel": []
},
{
"ID": "01-02-05",
"Name": "Flat 05",
"On": "02",
"Off": "",
"parentId": "01-02",
"sublevel": []
}
]
},
{
"ID": "01-03",
"Name": "Building 03",
"On": "02",
"Off": "01",
"parentId": "01",
"sublevel": []
},
{
"ID": "01-04",
"Name": "Building 04",
"On": "",
"Off": "",
"parentId": "01",
"sublevel": []
}
]
}
]
And this is my model class
import Foundation
struct AreaData : Codable {
let iD : String?
let name : String?
let parentId : AnyObject?
let sublevel : [Sublevel]?
enum CodingKeys: String, CodingKey {
case iD = "ID"
case name = "Name"
case parentId = "parentId"
case sublevel = "sublevel"
}
init(from decoder: Decoder) throws {
let values = try decoder.container(keyedBy: CodingKeys.self)
iD = try values.decodeIfPresent(String.self, forKey: .iD)
name = try values.decodeIfPresent(String.self, forKey: .name)
parentId = try values.decodeIfPresent(AnyObject.self, forKey: .parentId)
sublevel = try values.decodeIfPresent([Sublevel].self, forKey: .sublevel)
}
}
struct Sublevel : Codable {
let on : String?
let iD : String?
let name : String?
let off : String?
let parentId : String?
let sublevel : [Sublevel]?
enum CodingKeys: String, CodingKey {
case on = "On"
case iD = "ID"
case name = "Name"
case off = "Off"
case parentId = "parentId"
case sublevel = "sublevel"
}
init(from decoder: Decoder) throws {
let values = try decoder.container(keyedBy: CodingKeys.self)
on = try values.decodeIfPresent(String.self, forKey: .on)
iD = try values.decodeIfPresent(String.self, forKey: .iD)
name = try values.decodeIfPresent(String.self, forKey: .name)
off = try values.decodeIfPresent(String.self, forKey: .off)
parentId = try values.decodeIfPresent(String.self, forKey: .parentId)
sublevel = try values.decodeIfPresent([Sublevel].self, forKey: .sublevel)
}
}
try this,
struct AreaDataModel: Codable {
let id, name: String
let parentID: String? // AnyObject can't conform to Encodable protocol .
let sublevel: [Sublevel]
enum CodingKeys: String, CodingKey {
case id = "ID"
case name = "Name"
case parentID = "parentId"
case sublevel
}
}
// MARK: - Sublevel
struct Sublevel: Codable {
let id, name, on, off: String
let parentID: String
let sublevel: [Sublevel]
enum CodingKeys: String, CodingKey {
case id = "ID"
case name = "Name"
case on = "On"
case off = "Off"
case parentID = "parentId"
case sublevel
}
}
typealias AreaData = [AreaDataModel]
I recommend this tool simple and fast .
The problem is due to AnyObject
. Codabe
doesn't support anything like Any
or AnyObject
. You need to specify the type explicitly.
In the JSON response you added, the parentId
is either null
or String
. So, you can use String?
as its type, ie
struct AreaData : Codable {
let parentId : String? //here.....
//rest of the code....
}
Also, there is no need to specify the rawValue
of the case
explitly in enum CodingKeys
if the property and the key has an exact match. So the CodingKeys
in struct AreaData
must be,
enum CodingKeys: String, CodingKey {
case iD = "ID"
case name = "Name"
case parentId, sublevel
}
Moreover, init(from decoder: Decoder)
is not required. This is because you're not doing any specific parsing inside it. Direct parsing will be handled by the Codable
itself.
So, struct AreaData
should look like,
struct AreaData : Codable {
let iD : String?
let name : String?
let parentId : String?
let sublevel : [Sublevel]?
enum CodingKeys: String, CodingKey {
case iD = "ID"
case name = "Name"
case parentId, sublevel
}
}
Make similar changes to struct Sublevel
as well.
Also, use Codable
only if you want to both encode and decode the data. In case you want a single functionality ie either encode or decode , use Encodable
or Decodable
instead.
Recommendation:
Since the AreaData
and Sublevel
contain almost same kind of data, you can use a single struct
to decode
that JSON , ie
struct AreaData: Decodable {
let iD : String?
let name : String?
let parentId : String?
let sublevel : [AreaData]?
let on : String?
let off : String?
enum CodingKeys: String, CodingKey {
case iD = "ID"
case name = "Name"
case on = "On"
case off = "Off"
case parentId, sublevel
}
}
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.