I’m trying to retrieve an integer value from a JSON file in swift. I’m doing this as follows: self.trip.dist = String(decodedJson.Trip[self.tripIndex].LegList.Leg[i].dist)
but I’m getting this error error
.
Here is a link to the JSON file that I’m accessing. I’m trying to access the dist
value.
These are my structures:
struct JSONStructure: Decodable {
var Trip: [TripStructure]
}
struct TripStructure: Decodable {
var LegList: LegListStructure
}
struct LegListStructure: Decodable {
var Leg: [LegStructure]
}
struct LegStructure: Decodable {
var Origin: StationStructure
var Destination: StationStructure
var Product: ProductStructure
var name: String
var type: String
var dist: Int
}
struct StationStructure: Decodable {
var time: String
var name: String
var date: String
}
struct ProductStructure: Decodable {
var catIn: String
}
// Just to condense my varibales
struct LocationInfo {
var iD = String()
var input = String()
var lat = String()
var lon = String()
var name = String()
var time = String()
var date = String()
var vehicleType = String()
var transportType = String()
var dist = String()
var legName = String()
}
Here is the function I’m using to call the function:
@Published var trip: LocationInfo = LocationInfo()
@Published var dest: LocationInfo = LocationInfo()
@Published var origin: LocationInfo = LocationInfo()
@Published var arrivalTime = String()
@Published var travelDate = String()
@Published var searchForArrival = String()
@Published var tripIndex = Int()
@Published var Trips: [Dictionary<String, String>] = []
public func FetchTrip() {
Trips.removeAll()
let tripKey = "40892db48b394d3a86b2439f9f3800fd"
let tripUrl = URL(string: "http://api.sl.se/api2/TravelplannerV3_1/trip.json?key=(tripKey)&originExtId=(self.origin.iD)&destExtId=(self.dest.iD)&Date=(self.travelDate)&Time=(self.arrivalTime)&searchForArrival=(self.searchForArrival)")
URLSession.shared.dataTask(with: tripUrl!) {data, response, error in
if let data = data {
do {
let decodedJson = try JSONDecoder().decode(JSONStructure.self, from: data)
self.tripIndex = decodedJson.Trip.count - 1
for i in 0..<decodedJson.Trip[self.tripIndex].LegList.Leg.count {
self.trip.transportType = decodedJson.Trip[self.tripIndex].LegList.Leg[i].type
if self.trip.transportType == "WALK" {
self.origin.name = decodedJson.Trip[self.tripIndex].LegList.Leg[i].Origin.name
self.origin.time = String(decodedJson.Trip[self.tripIndex].LegList.Leg[i].Origin.time.prefix(5))
self.origin.date = decodedJson.Trip[self.tripIndex].LegList.Leg[i].Origin.date
self.dest.name = decodedJson.Trip[self.tripIndex].LegList.Leg[i].Destination.name
self.dest.time = String(decodedJson.Trip[self.tripIndex].LegList.Leg[i].Destination.time.prefix(5))
self.dest.date = decodedJson.Trip[self.tripIndex].LegList.Leg[i].Destination.date
self.trip.vehicleType = decodedJson.Trip[self.tripIndex].LegList.Leg[i].Product.catIn
self.trip.dist = String(decodedJson.Trip[self.tripIndex].LegList.Leg[i].dist) // This is where the problem lies
self.Trips.append(["Origin": self.origin.name, "Destination": self.dest.name, "OriginTime": self.origin.time, "DestTime": self.dest.time, "OriginDate": self.origin.date, "DestDate": self.dest.date, "TransportType": self.trip.transportType, "VehicleType": self.trip.vehicleType, "Distance": self.trip.dist])
}
else {
self.origin.name = decodedJson.Trip[self.tripIndex].LegList.Leg[i].Origin.name
self.origin.time = String(decodedJson.Trip[self.tripIndex].LegList.Leg[i].Origin.time.prefix(5))
self.origin.date = decodedJson.Trip[self.tripIndex].LegList.Leg[i].Origin.date
self.dest.name = decodedJson.Trip[self.tripIndex].LegList.Leg[i].Destination.name
self.dest.time = String(decodedJson.Trip[self.tripIndex].LegList.Leg[i].Destination.time.prefix(5))
self.dest.date = decodedJson.Trip[self.tripIndex].LegList.Leg[i].Destination.date
self.trip.vehicleType = decodedJson.Trip[self.tripIndex].LegList.Leg[i].Product.catIn
self.trip.legName = decodedJson.Trip[self.tripIndex].LegList.Leg[i].name
self.Trips.append(["Origin": self.origin.name, "Destination": self.dest.name, "OriginTime": self.origin.time, "DestTime": self.dest.time, "OriginDate": self.origin.date, "DestDate": self.dest.date, "TransportType": self.trip.transportType, "VehicleType": self.trip.vehicleType, "LegName": self.trip.legName])
}
}
} catch {
print(error)
}
}
}.resume()
}
I am getting this error in the console:
keyNotFound(CodingKeys(stringValue: "dist", intValue: nil), Swift.DecodingError.Context(codingPath: [CodingKeys(stringValue: "Trip", intValue: nil), _JSONKey(stringValue: "Index 0", intValue: 0), CodingKeys(stringValue: "LegList", intValue: nil), CodingKeys(stringValue: "Leg", intValue: nil), _JSONKey(stringValue: "Index 0", intValue: 0)], debugDescription: "No value associated with key CodingKeys(stringValue: "dist", intValue: nil) ("dist").", underlyingError: nil))
2
Answers
This site is great: https://app.quicktype.io You just paste in your json and it will write the Codable for you. QED.
You need to use an Optional Int to extract the
dist
values because not all legs have one.Here’s the minimum necessary to access the
dist
values:I’m glad you found a solution. There are other issues with your code that I feel the need to address.
The following code has the same effect but is, IMO, much cleaner:
For most of the variables, you are assigning to the same var each time through the loop. This is just wasteful. Assign the values from the last element of the loop and be done with it.
Most of the work being done in the
if...else...
blocks are identical. Separate out the identical parts and only put the parts that care about theLeg.type
in the if/else block. Do you actually use all the class properties in other methods of the class or were you just using them to make local variables in a weird way? (I’m assuming the former in the above code just in case.) If you don’t need all the other properties in other methods, and the only point is to populate thetrips
array, you could unload most of the code (except theself.trips =...
line of course.