Reputation: 59
I am trying to build a public transport app in SwiftUI. I have received an API where I can search for an origin and destination station in Stockholm, Sweden, and the date and time I want to travel and then get a travel route.
This is a part of the JSON file I am working with (the full one is in the comments below):
{
"Trip": [
{
"ServiceDays": [
{
"planningPeriodBegin": "2021-01-05",
"planningPeriodEnd": "2021-05-20",
"sDaysR": "m\u00e5n - fre",
"sDaysI": "utom 13., 14. maj",
"sDaysB": "33E7CF9F3E7CF9F3E7CF9C1E7CF9F3E70F"
}
],
"LegList": {
"Leg": [
{
"Origin": {
"name": "Skansen",
"type": "ST",
"id": "A=1@O=Skansen@X=18101848@Y=59323673@U=74@L=400110217@",
"extId": "400110217",
"lon": 18.101848,
"lat": 59.323673,
"prognosisType": "PROGNOSED",
"time": "15:58:00",
"date": "2021-04-06",
"rtTime": "15:59:00",
"rtDate": "2021-04-06",
"hasMainMast": true,
"mainMastId": "A=1@O=Skansen (Stockholm)@X=18100895@Y=59323960@U=74@L=300101405@",
"mainMastExtId": "300101405",
"additional": false
},
"Destination": {
"name": "Manilla",
"type": "ST",
"id": "A=1@O=Manilla@X=18133759@Y=59323250@U=74@L=400110141@",
"extId": "400110141",
"lon": 18.133759,
"lat": 59.32325,
"prognosisType": "PROGNOSED",
"time": "16:05:00",
"date": "2021-04-06",
"rtTime": "16:06:00",
"rtDate": "2021-04-06",
"hasMainMast": true,
"mainMastId": "A=1@O=Manilla (Stockholm)@X=18134407@Y=59324185@U=74@L=300101426@",
"mainMastExtId": "300101426",
"additional": false
},
This is not even a quarter of the full JSON file but I figured it would be too much adding it all in here, please comment if you would like to view the whole JSON file
for now, I don't focus on changing the date or time, I just need a way to access the following data:
- planningPeriodBegin
- planningPeriodEnd
- The "Origin" "name" (Skansen)
- The "Destination" "name" (Manilla)
I have copied a tutorial on YouTube that partly covers how to access the JSON file - but not completely. Here is the link to the video: https://www.youtube.com/watch?v=-gNOVDNWmIg&list=LL&index=1&t=966s
...And this is the code he wrote in the video:
import SwiftUI
struct RouteList: View {
@State var gifUrl = String()
@State var searchString = String()
var body: some View {
Text("\(gifUrl)")
.onTapGesture {
let url = URL(string: gifUrl)
guard let GIPHYUrl = url, UIApplication.shared.canOpenURL(GIPHYUrl) else {return}
UIApplication.shared.open(GIPHYUrl)
}
TextField("Search GIFs", text: $searchString)
.multilineTextAlignment(.center)
Button("Fetch Gif"){fetchAPI()}
}
func fetchAPI() {
let apiKey = "xkkakigCSAnCN4Opymed36OoyByZEbBO"
let url = URL(string: "https://api.giphy.com/v1/gifs/search?api_key=\(apiKey)&q=\(self.searchString)&limit=25&offset=0&rating=g&lang=en")
URLSession.shared.dataTask(with: url!) { data, response, error in
if let data = data {
if let decodedGiphy = try? JSONDecoder().decode(GIPHYStructure.self, from: data){
self.gifUrl = decodedGiphy.data[0].url
}
}
}.resume()
}
}
struct GIPHYStructure: Decodable {
let data: [dataStructure]
}
struct dataStructure: Decodable {
let url: String
}
Thank you for taking the time to read the whole post and it would help greatly if you could manage to figure out how to do it. I have a URL to the JSON file but that key is private.
Upvotes: 0
Views: 1022
Reputation: 432
Your ...Structure structs need to model the structure of the JSON file you're decoding. So you'd use something like this (untested, since you didn't share the URL):
struct APIStructure: Decodable {
var Trip: [TripStructure]
}
struct TripStructure: Decodable {
var ServiceDays: [ServiceDayStructure]
var LegList: LegListStructure
}
struct ServiceDayStructure: Decodable {
var planningPeriodBegin: Date
var planningPeriodEnd: Date
}
struct LegListStructure: Decodable {
var Leg: [LegStructure]
}
struct LegStructure: Decodable {
var Origin: StationStructure
var Destination: StationStructure
}
struct StationStructure: Decodable {
var name: String
}
Then you could fetch and decode the JSON roughly like this:
func fetchAPI() {
let url = URL(string: "https://api.giphy.com/v1/gifs/search?api_key=\(apiKey)&q=\(self.searchString)&limit=25&offset=0&rating=g&lang=en")
URLSession.shared.dataTask(with: url!) { data, response, error in
if let data = data {
let decoder = JSONDecoder()
let formatter = DateFormatter()
formatter.dateFormat = "yyyy-MM-dd"
decoder.dateDecodingStrategy = .formatted(formatter)
if let decodedJSON = try? decoder.decode(APIStructure.self, from: data){
// Examples how to access the decoded values:
let firstTripFirstPlanningPeriodBegin: Date = decodedJSON.Trip[0].ServiceDays[0].planningPeriodBegin
let firstTripFirstLegOrigin: String = decodedJSON.Trip[0].LegList.Leg[0].Origin.name
}
}
}.resume()
}
This all explained in much more detail in this article: https://learnappmaking.com/codable-json-swift-how-to/
Upvotes: 1
Reputation: 2299
In order to have a better answer, I suggest you improve your question. Also, try to not expose here in the StackOverflow, parameters that could compromise the privacy of your app and your clients like the api key in your question.
Anyway, I got some problems in your code that could be the issue, actually, I'm not sure what's your question but let's see:
Your fetch method seems the problem, if you check the URLSession
documentation you will notice the completion block is async and doesn't run in the main thread. So you have to wrap your assign into a dispatch queue main block in order to update UI elements just after the request and JSON parsing completes
DispatchQueue.main.async {
self.gifUrl = json.data[0].url
}
Always follow the official documentation to support you development.
Upvotes: 0