I have geoJSON file:
{
"type": "Feature",
"geometry": {
"type": "MultiPolygon",
"coordinates": [
[
[
[
40.303141,
55.9765684
],
[
40.3033449,
55.9765114
],
[
40.3034017,
55.976575
],
[
40.3031979,
55.9766321
],
[
40.303141,
55.9765684
]
]
]
]
},
"properties": {
"@id": 4305947573,
"building": "yes"
}
}
I'm interested in properties:
"properties":{"@id":4305947573,"building":"yes"}
I want parse "properties", and make structure:
struct Feature: Decodable {
let type: String
let properties: Dictionary<String, String> }
It's work good, but then i add parameter in geoJSON: "@id":4305947573
4305947573 - this is Int variable, and parser don't parse geoJSON.
I think i need modify my struct Feature. I want to parser understand and String, and Int in properties.
Help me please. Thank you
CodePudding user response:
You can use a custom CodingKey
with a custom object.
enum CodingKeys: String, CodingKey{
case id = "@id"
case building
}
The object will look something like
struct Feature: Codable{
var type: String
var geometry: Geometry
var properties: Property
struct Geometry: Codable{
var type: String
var coordinates: [[[[Double]]]]
}
struct Property: Codable{
var id: Int
var building: String
enum CodingKeys: String, CodingKey{
case id = "@id"
case building
}
}
}
Then you can decode with a simple decoder or any other parser.
func decode(string: String) throws -> Feature?{
let decoder = JSONDecoder()
return try decoder.decode(Feature.self, from: string.data(using: .utf8)!)
}
CodePudding user response:
There are a number of GeoJSON swift libraries (search github) that you could use instead of re-inventing the wheel.
If you really want to code it yourself, try this approach,
where the dynamic keys and values of properties
are decoded
into a dictionary of var data: [String: Any]
, as shown.
Use the struct models like this:
let result = try JSONDecoder().decode(Feature.self, from: data)
Models
struct Feature: Decodable {
let type: String
var properties: Properties
// ...
}
struct Properties: Decodable {
var data: [String: Any] = [:]
init(from decoder: Decoder) throws {
let container = try decoder.container(keyedBy: DynamicKey.self)
container.allKeys.forEach { key in
if let theString = try? container.decode(String.self, forKey: key) {
self.data[key.stringValue] = theString
}
if let theInt = try? container.decode(Int.self, forKey: key) {
self.data[key.stringValue] = theInt
}
}
}
}
struct DynamicKey: CodingKey {
var intValue: Int?
init?(intValue: Int) {
self.intValue = intValue
self.stringValue = ""
}
var stringValue: String
init?(stringValue: String) {
self.stringValue = stringValue
self.intValue = nil
}
}