I'm trying to get a response from this link : https://zsr.octane.gg/players/5f5ae840c6cbf591c568a477 but it won't work and I can't figure why.
There is my ContentView.swift :
struct ContentView: View {
#State private var players = [Player]()
var body: some View {
List(players, id: \._id) { item in
VStack(alignment: .leading) {
Text(item.name)
.font(.headline)
Text(item.country)
}
}.task {
await loadData()
}
}
func loadData() async {
guard let url = URL(string: "https://zsr.octane.gg/players/5f5ae840c6cbf591c568a477") else {
print("URL invalide")
return
}
do {
let (data, _) = try await URLSession.shared.data(from: url)
if let decodedResponse = try? JSONDecoder().decode(Response.self, from: data) {
players = decodedResponse.players
}
} catch {
print("Invalid data")
}
}
}
My Response struct :
struct Response: Codable {
var players: [Player]
}
Player struct :
struct Player: Codable {
var _id: String
var slug: String
var tag: String
var name: String
var country: String
var team: Team
var accounts: [Account]
var revelant: Bool
}
Team struct :
struct Team: Codable {
var _id: String
var slug: String
var name: String
var region: String
var image: String
var relevant: Bool
}
Account struct :
struct Account: Codable {
var platform: String
var id: String
}
Edit: the error that I have from the do catch is :
Invalid data with error: keyNotFound(CodingKeys(stringValue: "revelant", intValue: nil), Swift.DecodingError.Context(codingPath: [], debugDescription: "No value associated with key CodingKeys(stringValue: "revelant", intValue: nil) ("revelant").", underlyingError: nil))
I followed a tutorial which works well but when I replace the link and use my own structs nothing happens when I launch the app.
Thanks for your help.
Your response is a dictionary not an array to to log error use try instead of try? and log the error inside the catch part , this snippet is after the edit and it shows currently info of 1 player
One player
func loadData() async {
guard let url = URL(string: "https://zsr.octane.gg/players/5f5ae840c6cbf591c568a477") else {
print("URL invalide")
return
}
do {
let (data, _) = try await URLSession.shared.data(from: url)
let decodedResponse = try JSONDecoder().decode(Player.self, from: data)
players = [decodedResponse]
} catch {
print("Invalid data with error: ",error)
}
}
All players
May be you mean to drop 5f5ae840c6cbf591c568a477 from guard let url = URL(string: "https://zsr.octane.gg/players/5f5ae840c6cbf591c568a477") else { to get all players , check here complete working demo
import SwiftUI
struct ContentView: View {
#State private var players = [Player]()
var body: some View {
List(players, id: \._id) { item in
VStack(alignment: .leading) {
Text(item.name ?? "")
.font(.headline)
Text(item.country ?? "")
}
}.task {
await loadData()
}
}
func loadData() async {
guard let url = URL(string: "https://zsr.octane.gg/players") else {
print("URL invalide")
return
}
do {
let (data, _) = try await URLSession.shared.data(from: url)
let decodedResponse = try JSONDecoder().decode(Response.self, from: data)
players = decodedResponse.players
} catch {
print("Invalid data",error)
}
}
}
struct Response: Codable {
var players: [Player]
}
struct Player: Codable {
var _id: String
var slug: String
var tag: String
var name: String?
var country: String?
var accounts: [Account]?
}
struct Team: Codable {
var _id: String
var slug: String
var name: String
var region: String
var image: String
var relevant: Bool
}
struct Account: Codable {
var platform: String
var id: String
}
struct ContentView_Previews: PreviewProvider {
static var previews: some View {
ContentView()
}
}
Note: a variable that may exist in a model or not should be marked as optional
Related
I am trying to display data from an api. When I try to do it on the app it works but once I move the code to the widget it doesn't work the onAppear or Button. I need help on how to refresh the json when the decoder loads it. I think my decoder needs works I am not sure what the issue is.
struct panchangWidgetEntryView : View {
#State private var panchangData: PanchangData?
var entry: Provider.Entry
var body: some View {
HStack {
Text(panchangData?.tithi ?? "")
.font(.subheadline)
.padding()
Text(panchangData?.paksha ?? "")
.font(.subheadline)
.padding()
}
}
func loadData(){
guard let url = URL(string: "API URL") else {
return
}
URLSession.shared.dataTask(with: url){ data, response, error in
guard let data = data else { return }
if let decodedData = try? JSONDecoder().decode(PanchangData.self, from: data){
DispatchQueue.main.async {
self.panchangData = decodedData
}
}
}.resume()
}
}
struct PanchangData: Decodable{
var slon: Double
var mlon: Double
var tithinum: Int
var tithi: String
var paksha: String
var tithiTill: String
var nakshatra: String
var nakshatraTill: String
var yoga: String
var yogTill: String
var karana: String
var karanTill: String
var rashi: String
var requestsremaining: Int
var requeststotal: Int
var plan: String
var status: String
var reqdate: String
var reqtime: String
}
I'm trying to create a list view with some data I am pulling from an API. I'm struggling to understand how to take the data from the API response and putting it into the state for my app to use. Below is the content view in my application that is pulling the data.
import SwiftUI
import Alamofire
struct ContentView: View {
#State var results = [Bottle]()
var body: some View {
List(results, id: \.id) { item in
VStack(alignment: .leading) {
Text(item.name)
}
}.onAppear(perform: loadData)
}
func loadData() {
let request = AF.request("https://bevy-staging.herokuapp.com")
request.responseJSON { (data) in
print(data)
}
}
}
I've tried adding this to the result block
AF.request("https://bevy-staging.herokuapp.com/").responseJSON { response in
guard let data = response.data else { return }
if let response = try? JSONDecoder().decode([Bottle].self, from: data) {
DispatchQueue.main.async {
self.results = response
}
return
}
}
However nothing populates in my view and I get the following error.
nw_protocol_get_quic_image_block_invoke dlopen libquic failed
Why am I receiving this error and how can I get my data to display in the list vew?
Here is the model I am working with.
struct Bottle: Decodable {
var id: String
var name: String
var price: String
var sku: String
var size: String
var origination: String
var varietal: String
var brand_bottle: String
}
You need to add "?" to model data that can have null data, for all model rows which can obtain "null" need to use "?" or JSONDecoder wouldn't decode data to your model. Inside the model your rows "origination, varietal, brand_bottle" have "String" data type but from the server, you obtain "null", thus JSONDecoder can't recognize data.
You can check responses use services like "http://jsonviewer.stack.hu/" or any other.
Need to modify model data like below:
struct Bottle: Decodable {
var id: String
var name: String
var price: String
var sku: String
var size: String
var origination: String?
var varietal: String?
var brand_bottle: String?
}
I did recreate your project and all work well code below:
import SwiftUI
import Alamofire
struct ContentView: View {
#State var results = [Bottle]()
var body: some View {
List(results, id: \.id) { item in
VStack(alignment: .leading) {
Text(item.name)
}
}.onAppear(perform: loadData)
}
func loadData() {
AF.request("https://bevy-staging.herokuapp.com/").responseJSON { response in
guard let data = response.data else { return }
if let response = try? JSONDecoder().decode([Bottle].self, from: data) {
DispatchQueue.main.async {
self.results = response
}
return
}
}
}
}
struct ContentView_Previews: PreviewProvider {
static var previews: some View {
ContentView()
}
}
struct Bottle: Decodable {
var id: String
var name: String
var price: String
var sku: String
var size: String
var origination: String?
var varietal: String?
var brand_bottle: String?
}
Currently not getting data from API to display.
Current code:
import SwiftUI
struct Response: Decodable {
var content: [Result]
}
struct Result : Decodable {
var code: String
var fire: String
var name: String
var police: String
var medical: String
}
struct ContentView: View {
#State private var content = [Result]()
var body: some View {
List(content, id: \.code) { item in
VStack(alignment: .leading) {
Text(item.name)
.font(.headline)
Text(item.medical)
}
}
.onAppear(perform: loadData)
}
func loadData() {
let url = URL(string: "https://emergency-phone-numbers.herokuapp.com/country/gb")!
URLSession.shared.dataTask(with: url) { data, response, error in
if let error = error { print(error); return }
do {
let decodedResponse = try JSONDecoder().decode(Response.self, from: data!)
// we have good data – go back to the main thread
DispatchQueue.main.async {
// update our UI
self.content = decodedResponse.content
}
} catch {
print(error)
}
}.resume()
}
}
struct ContentView_Previews: PreviewProvider {
static var previews: some View {
ContentView()
}
}
Current error:
2021-01-21 19:21:07.094582+0000 iTunes API[39924:1098972] [] nw_protocol_get_quic_image_block_invoke dlopen libquic failed
keyNotFound(CodingKeys(stringValue: "content", intValue: nil), Swift.DecodingError.Context(codingPath: [], debugDescription: "No value associated with key CodingKeys(stringValue: "content", intValue: nil) ("content").", underlyingError: nil))
Please advise. Thanks in advance.
Please note that the content from https://emergency-phone-numbers.herokuapp.com/country/gb is:
{"code":"GB","fire":"999","police":"999","name":"United Kingdom","medical":"999"}
The problem is that there's no content on the response that you're getting, so the JSONDecoder is failing to parse the response. It seems the response you get contains content that fits on Result, so if you change your code to parse that, it works fine:
import SwiftUI
struct Response: Decodable {
var content: [Result]
}
struct Result : Decodable {
var code: String
var fire: String
var name: String
var police: String
var medical: String
}
struct ContentView: View {
#State private var content = [Result]()
var body: some View {
List(content, id: \.code) { item in
VStack(alignment: .leading) {
Text(item.name)
.font(.headline)
Text(item.medical)
}
}
.onAppear(perform: loadData)
}
func loadData() {
let url = URL(string: "https://emergency-phone-numbers.herokuapp.com/country/gb")!
URLSession.shared.dataTask(with: url) { data, response, error in
if let error = error { print(error); return }
do {
let decodedResponse = try JSONDecoder().decode(Result.self, from: data!)
// we have good data – go back to the main thread
DispatchQueue.main.async {
// update our UI
self.content = [decodedResponse]
}
} catch {
print(error)
}
}.resume()
}
}
I guess, in the end, you probably wanted a collection of Results to fit on the content, so you might need to change something on that API of yours to return that collection, then your code would work fine.
NOTE: Forgive my cluelessness, i am still new in regards to this. The full code is posted at the bottom.
ISSUE: It seems that when i have a short nest, i am able to call it for my #Published property however when i try an api request with a longer nest, like this. and type Decodable structs that follows the structure of the GET request
struct TripScheduleTest: Codable {
let TripList: InitialNest
}
struct InitialNest: Codable {
var Trip: [TravelDetail]
}
struct TravelDetail: Codable {
var Leg: [TripTest]
}
struct TripTest: Codable, Hashable {
var name: String
var type: String
}
I am not able to call it for the #Published var dataSet1 = [TripTest]()
self.dataSet1 = tripJSON.TripList.Trip.Leg
I get an error message, that says "Value of type '[TravelDetail]' has no member 'Leg'
I am not sure why, however it works when i use [TravelDetail]() instead of [TripTest]() in the #Published var and stop at Trip before Leg for the dataSet1, then it seems to at least build successfully. But now i am not able to get the name and type information from the request
Full code
import SwiftUI
struct TripScheduleTest: Codable {
let TripList: InitialNest
}
struct InitialNest: Codable {
var Trip: [TravelDetail]
}
struct TravelDetail: Codable {
var Leg: [TripTest]
}
struct TripTest: Codable, Hashable {
var name: String
var type: String
}
class TripViewModel: ObservableObject {
#Published var dataSet1 = [TripTest]()
init() {
let urlString = "http://xmlopen.rejseplanen.dk/bin/rest.exe/trip?originId=8600790&destId=6553&format=json"
guard let url = URL(string: urlString) else { return }
URLSession.shared.dataTask(with: url) { (data, resp, err) in
guard let data = data else { return }
do {
let tripJSON = try
JSONDecoder().decode(TripScheduleTest.self, from: data)
print(data)
DispatchQueue.main.async {
self.dataSet1 = tripJSON.TripList.Trip.Leg
}
} catch {
print("JSON Decode error: ", error)
}
}.resume()
}
}
struct TripView: View {
#ObservedObject var vm = TripViewModel()
var body: some View {
List(vm.dataSet1, id: \.self) { day in
Text("Test")
.font(.system(size: 12, weight: .bold))
Text(" \(day.name)")
.font(.system(size: 12))
}
}
}
Trip is an array (note the [])
You need to get one item of the array by index for example
tripJSON.TripList.Trip.first?.Leg
To assign the value to a non-optional array write
self.dataSet1 = tripJSON.TripList.Trip.first?.Leg ?? []
first of all I made this NetworkManager class to made networking with json api. like this below.
import Foundation
import SwiftUI
import Combine
class NetworkManager: ObservableObject {
#Published var posts = [Post]()
func fetchData() {
var urlComponents = URLComponents()
urlComponents.scheme = "http"
urlComponents.host = "183.111.148.229"
urlComponents.path = "/mob_json/mob_json.aspx"
urlComponents.queryItems = [
URLQueryItem(name: "nm_sp", value: "UP_MOB_CHECK_LOGIN"),
URLQueryItem(name: "param", value: "1000|1000|1")
]
if let url = urlComponents.url {
print(url)
let session = URLSession(configuration: .default)
let task = session.dataTask(with: url) { (data, response, error) in
if error == nil {
let decoder = JSONDecoder()
if let safeData = data {
do {
let results = try decoder.decode(Results.self, from: safeData)
DispatchQueue.main.async {
self.posts = results.Table
}
} catch {
print(error)
}
}
}
}
task.resume()
}
}
}
And this is my data Model which is structure for my json data. I also made this by refer code on the internet.
import Foundation
struct Results: Decodable {
let Table: [Post]
}
struct Post: Decodable, Identifiable {
var id: String {
return CD_FIRM
}
let CD_FIRM: String
let NM_FIRM: String
let CD_USER: String
let NM_USER: String
}
On the view, This is work fine I can see my result. But this is not what I want.
I want to see each single text value.
import SwiftUI
struct SwiftUIView: View {
#ObservedObject var networkManager = NetworkManager()
var body: some View {
NavigationView {
List(networkManager.posts) { post in
Text(post.NM_FIRM)
}
}.onAppear {
self.networkManager.fetchData()
}
}
}
struct SwiftUIView_Previews: PreviewProvider {
static var previews: some View {
SwiftUIView()
}
}
** I want to extract single text value from results like this**
with JUST single text.
I can extract all datas from json, but I don't know how to extract each values from result.
I tried like this below
import SwiftUI
struct SwiftUIView: View {
#ObservedObject var networkManager = NetworkManager()
var body: some View {
VStack {
Text(networkManager.posts.NM_FIRM)
}.onAppear {
self.networkManager.fetchData()
}
}
}
struct SwiftUIView_Previews: PreviewProvider {
static var previews: some View {
SwiftUIView()
}
}
But this one didn't work. where do I have to fix this? Please help me.
Add more thing
import Foundation
struct Results: Decodable {
let Table: [Post]
}
struct Post: Decodable, Identifiable {
var id: String {
return name
}
let name: String
let cellPhone: String
}
// I want to get value like this but this didn't work
var data1 = name
var data2 = cellPhone