I am querying a WebService and I get the following response:
{
"pageSize": 50,
"pageNum": 1,
"totalCount": 1146,
"totalPages": 23,
"items": [
{
"type": "Feature",
"properties": {...},
"geometry": {
"type": "GeometryCollection",
"geometries": [
{
"type": "Point",
"coordinates": [
0.15,
35.22
]
}
]
}
}
]
}
The 'items' are GeoJSON objects.
In Swift, I can parse GeoJSON objects with: MKGeoJSONDecoder().decode(data)
, but how can I parse the whole response (that starts with pageSize, etc and then contains an array of GeoJSON items in the items
member)?
If I define the root object like so
struct WebServiceResponse: Codable {
let pageSize: Int
let pageNum: Int
let totalCount: Int
let totalPages: Int
let items: [MKGeoJSONObject]
}
I get Type 'WebServiceResponse' does not conform to protocol 'Decodable'
, which seems logical cos MKGeoJSONObject is defined as
public protocol MKGeoJSONObject : NSObjectProtocol {
}
So no mention of it being Decodable.
I could manually remove the first bit (and the curly bracket at the end of the response) so that I only have this bit left:
[
{
"type": "Feature",
"properties": {...},
"geometry": {
"type": "GeometryCollection",
"geometries": [
{
"type": "Point",
"coordinates": [
0.15,
35.22
]
}
]
}
}
]
and parse that with the MKGeoJSONDecoder ... but that sounds like a hack to me.
MKGeoJSONDecoder
is, as you have experienced, does not work well with Codable
, in the same way that JSONSerialization
doesn't work well with Codable
.
You basically need to write your own Codable
types that represent the GeoJSON models. There are people who have already done this. You can use a package like CodableGeoJSON.
struct WebServiceResponse: Codable {
let pageSize: Int
let pageNum: Int
let totalCount: Int
let totalPages: Int
let items: [GeoJSON]
}
GeoJSON
is an enum with associated values, each case representing each kind of GeoJSON data.
If you know what specific type of GeoJSON you will get, you can use the more specialised types,
// if you know it will be an array of features
let items: [GeoJSON.Feature]
// if you know it will be an array of features represented by points:
let items: [GeoJSONFeature<PointGeometry, LocationProperties>]
// 'LocationProperties' above represents the data in the 'properties' key
// and so on...