JSON Object to string Swift UI - json

import SwiftUI
extension String{
func load() ->UIImage {
do{
//string to URL
guard let url = URL(string: self) else{
//empty image if wrong url
return UIImage()
}
//url to data
let data : Data = try Data(contentsOf: url)
//create uuimage obj from data
return UIImage(data: data) ?? UIImage()
}catch{
}
return UIImage()
}
}
struct ContentView: View {
#State private var quoteData : QuoteData?
var body: some View {
ZStack{
VStack{
Text(quoteData?.lat ?? "Latitude")
Text(quoteData?.long ?? "Longitude")
//------------------------HELP HERE
Image(uiImage: "https://maps.googleapis.com/maps/api/staticmap?center=LATITUDE,LONGITUDE&zoom=16&size=400x400&key=AIzaSyClGOTMpV2kKF27bxAo6nm3pIq7zmW69Fw".load())
struct QuoteData: Decodable{
//var id: Int
var long: String
var lat: String
var apiURL: String
}
I want to insert the long and lat variables of QuoteData inside the url string that is used in IMAGE(uimage
I cant find an answer , been looking for hours with no luck
this is just a fragment of the code it will be nice if someone can help me .

try something like this, using \(lat),\(lon) "...to insert the long and lat variables of QuoteData inside the url string...":
struct ContentView: View {
#State private var quoteData: QuoteData? = QuoteData(long: "139.7514", lat: "35.685", apiURL: "") // for testing, Tokyo
var body: some View {
VStack{
Text(quoteData?.lat ?? "Latitude")
Text(quoteData?.long ?? "Longitude")
if let lat = quoteData?.lat, let lon = quoteData?.long {
Image(uiImage: "https://maps.googleapis.com/maps/api/staticmap?center=\(lat),\(lon)&zoom=16&size=400x400&key=AIzaSyClGOTMpV2kKF27bxAo6nm3pIq7zmW69Fw".load())
}
}
}
}
PS: this has nothing to do with JSON object to String

Related

Can't seem to decode JSON

I know this type of question seems to be answered a lot but I really can't seem to make this work. I'm trying to decode some JSON data into my data structs. I think the problem is there. I may have my data model wrong, but can't quite work it out. The data is not an array, there is an array within it. Its trying to decode a dictionary into array but when I try to initialise my results variable as something other than array it won't build. I'll submit my code and the JSON data in the hopes someone can shed light!
The error I'm getting is:
JSON decode failed: Swift.DecodingError.typeMismatch(Swift.Array, Swift.DecodingError.Context(codingPath: [], debugDescription: "Expected to decode Array but found a dictionary instead.", underlyingError: nil))
thank you so much
import SwiftUI
struct DataFormatted: Codable, Hashable {
var deliveryPoints: [DeliveryPoints]
var deliveryPointCount: Int
var postalCounty: String
var traditionalCounty: String
var town: String
var postCode: String
}
struct DeliveryPoints: Codable, Hashable {
var organisationName: String
var departmentName: String
var line1: String
var line2: String
var udprn: String
var dps: String
}
struct ContentView: View {
// I reckon the error is here:
#State private var results = [DataFormatted]()
var body: some View {
VStack{
List{
ForEach(results, id: \.self) { result in
Text(result.postalCounty)
}
}
}
.task {
await loadData()
}
}
func loadData() async {
guard let url = URL(string: "https://pcls1.craftyclicks.co.uk/json/rapidaddress?key=APIKEY&postcode=aa11aa&response=data_formatted") else {
print("Invalid URL")
return
}
var request = URLRequest(url: url)
request.setValue("application/json", forHTTPHeaderField: "Content-Type")
request.httpMethod = "GET"
do {
let (data, _) = try await URLSession.shared.data(for: request)
let decoder = JSONDecoder()
decoder.keyDecodingStrategy = .convertFromSnakeCase
let decodedResponse = try decoder.decode([DataFormatted].self, from: data)
results = decodedResponse
} catch let jsonError as NSError {
print("JSON decode failed: \(jsonError)")
}
}
}
JSON Data:
{
"delivery_points":[
{
"organisation_name":"THE BAKERY",
"department_name":"",
"line_1":"1 HIGH STREET",
"line_2":"CRAFTY VALLEY",
"udprn":"12345678",
"dps":"1A"
},
{
"organisation_name":"FILMS R US",
"department_name":"",
"line_1":"3 HIGH STREET",
"line_2":"CRAFTY VALLEY",
"udprn":"12345679",
"dps":"1B"
}
],
"delivery_point_count":2,
"postal_county":"POSTAL COUNTY",
"traditional_county":"TRADITIONAL COUNTY",
"town":"BIG CITY",
"postcode":"AA1 1AA"
}
try something like this:
struct DataFormatted: Codable {
var deliveryPoints: [DeliveryPoint]
var deliveryPointCount: Int
var postalCounty: String
var traditionalCounty: String
var town: String
var postcode: String // <-- postcode
}
struct DeliveryPoint: Codable {
var organisationName: String
var departmentName: String
var line1: String?
var line2: String?
var line3: String?
var udprn: String
var dps: String
}
and use it like this:
let apiResponse = try decoder.decode(DataFormatted.self, from: data)
EDIT-1: here is the code I used for testing:
// -- here, default values for convenience
struct DataFormatted: Codable {
var deliveryPoints: [DeliveryPoint] = []
var deliveryPointCount: Int = 0
var postalCounty: String = ""
var traditionalCounty: String = ""
var town: String = ""
var postcode: String = "" // <-- postcode
}
struct DeliveryPoint: Hashable, Codable { // <-- here
var organisationName: String
var departmentName: String
var line1: String?
var line2: String?
var line3: String?
var udprn: String
var dps: String
}
struct ContentView: View {
#State private var results = DataFormatted()
var body: some View {
VStack{
Text(results.postalCounty)
Text(results.town)
List {
ForEach(results.deliveryPoints, id: \.self) { point in
Text(point.organisationName)
}
}
}
.task {
await loadData()
}
}
func loadData() async {
let apikey = "your-key" // <-- here
guard let url = URL(string: "https://pcls1.craftyclicks.co.uk/json/rapidaddress?key=\(apikey)&postcode=aa11aa&response=data_formatted") else {
print("Invalid URL")
return
}
do {
let (data, _) = try await URLSession.shared.data(from: url)
let decoder = JSONDecoder()
decoder.keyDecodingStrategy = .convertFromSnakeCase
results = try decoder.decode(DataFormatted.self, from: data) // <-- here
} catch {
print("JSON decode failed: \(error)")
}
}
}

How to read and display a dictionary from JSON?

I am working on an app that fetches the data from JSON and displays it.
However, I am stuck with an error saying Instance method 'appendInterpolation(_:formatter:)' requires that '[String : Int]' inherit from 'NSObject'
Here is my data structure:
struct Data: Codable {
var message: String
var data: Objects
}
struct Objects: Codable {
var date: String
var day: Int
var resource: String
var stats, increase: [String: Int]
}
Function to fetch the data:
func getData() {
let urlString = "https://russianwarship.rip/api/v1/statistics/latest"
let url = URL(string: urlString)
URLSession.shared.dataTask(with: url!) { data, _, error in
if let data = data {
do {
let decoder = JSONDecoder()
let decodedData = try decoder.decode(Data.self, from: data)
self.data = decodedData
} catch {
print("Hey there's an error: \(error.localizedDescription)")
}
}
}.resume()
}
And a ContentView with the #State property to pass the placeholder data:
struct ContentView: View {
#State var data = Data(message: "", data: Objects(date: "123", day: 123, resource: "", stats: ["123" : 1], increase: ["123" : 1]))
var body: some View {
VStack {
Button("refresh") { getData() }
Text("\(data.data.date)")
Text("\(data.data.day)")
Text(data.message)
Text("\(data.data.stats)") //error is here
Here is an example of JSON response
I wonder if the problem is in data structure, because both
Text("\(data.data.date)")
Text("\(data.data.day)")
are working just fine. If there are any workarounds with this issue – please, I would highly appreciate your help!:)
stats is [String: Int], and so when you want to use it, you need to supply the key to get the value Int, the result is an optional that you must unwrap or supply a default value in Text
So use this:
Text("\(data.data.stats["123"] ?? 0)")
And as mentioned in the comments, do not use Data for your struct name.
EDIT-1: there are two ways you can make the struct fields camelCase; one is using the CodingKeys as shown in ItemModel, or at the decoding stage, as shown in the getData() function. Note, I've also updated your models to make them easier to use.
struct DataModel: Codable {
var message: String
var data: ObjectModel
}
struct ObjectModel: Codable {
var date: String
var day: Int
var resource: String
var stats: ItemModel
var increase: ItemModel
}
struct ItemModel: Codable {
var personnelUnits: Int
var tanks: Int
var armouredFightingVehicles: Int
// ...
// manual CodingKeys
// enum CodingKeys: String, CodingKey {
// case tanks
// case personnelUnits = "personnel_units"
// case armouredFightingVehicles = "armoured_fighting_vehicles"
// }
}
struct ContentView: View {
#State var dataModel = DataModel(message: "", data: ObjectModel(date: "123", day: 123, resource: "", stats: ItemModel(personnelUnits: 123, tanks: 456, armouredFightingVehicles: 789), increase: ItemModel(personnelUnits: 3, tanks: 4, armouredFightingVehicles: 5)))
var body: some View {
VStack {
Button("get data from Server") { getData() }
Text("\(dataModel.data.date)")
Text("\(dataModel.data.day)")
Text(dataModel.message)
Text("\(dataModel.data.stats.armouredFightingVehicles)") // <-- here
}
}
func getData() {
let urlString = "https://russianwarship.rip/api/v1/statistics/latest"
if let url = URL(string: urlString) {
URLSession.shared.dataTask(with: url) { data, _, error in
if let data = data {
do {
let decoder = JSONDecoder()
decoder.keyDecodingStrategy = .convertFromSnakeCase // <-- here
dataModel = try decoder.decode(DataModel.self, from: data)
} catch {
print("--> error: \(error)")
}
}
}.resume()
}
}
}

How do I parse this JSON API data in SwiftUI?

A beginner here.
I'm having some trouble trying to parse this json url in SwiftUI
Here is what I've tried:
import SwiftUI
struct PriceData2: Decodable {
var id: Int
var last: Double
var lowestAsk: Double
var highestBid: Double
var percentChange: Double
var baseVolume: Double
var quoteVolume: Double
var isFrozen: Int
var high24hr: Double
var low24hr: Double
var change: Double
var prevClose: Double
var prevOpen: Double
}
struct ContentView: View {
#State var priceData2: PriceData2?
var body: some View {
if #available(iOS 15.0, *) {
VStack(){
Text("\(priceData2?.id ?? 0)")
}.onAppear (perform: loadData2)
} else {
// Fallback on earlier versions
}
}
public func loadData2() {
guard let url = URL(string: "https://api.bitkub.com/api/market/ticker?sym=THB_BTC") else {
return
}
URLSession.shared.dataTask(with: url) { data, response, error in
guard let data = data else {return}
if let decodedData = try? JSONDecoder().decode(PriceData2.self, from: data){
DispatchQueue.main.async {
self.priceData2 = decodedData
}
}
}.resume()
}
}
struct ContentView_Previews: PreviewProvider {
static var previews: some View {
ContentView()
}
}
I think it has something to do with the THB_BTC property of the dictionary that I haven't dealt with but I'm not totally sure of.
Any help with this is much appreciated.
Thanks
What is missing when decoding is a top level type to hold the price data and there are two ways to solve this, either by using a top level struct or by using a dictionary.
Since the top level key, THB_BTC, seems to be the "symbol" argument from the query and thus might change a top level dictionary is the best alternative here
do {
let result = try JSONDecoder().decode([String: PriceData].self, from: data)
if let priceData = result.values.first { //or = result["THB_BTC"]
print(priceData)
}
} catch {
print(error)
}
Just for completeness, here is the variant with the top level struct
struct Result: Decodable {
enum CodingKeys: String, CodingKey {
case data = "THB_BTC"
}
let data: PriceData
}
let result = try JSONDecoder().decode(Result.self, from: data)
print(result.data)

How do you display JSON Data in swiftUI

I have problem with showing JSON Data in SwiftUI, I get the data from Genius API I currently search for song and can confirm that I get the data extracted correctly; example I can print out the title of the result:
This is how I fetch the data
class NetworkManager: ObservableObject {
var objectWillChange = PassthroughSubject<NetworkManager, Never>()
var fetchedSongsResults = [hits]() {
willSet {
objectWillChange.send(self)
}
}
init() {
fetchSongs()
}
func fetchSongs() {
guard let url = URL(string: "https://api.genius.com/search?q=Sia") else { return }
var urlRequest = URLRequest(url: url)
urlRequest.setValue("Bearer TOKEN", forHTTPHeaderField: "Authorization")
URLSession.shared.dataTask(with: urlRequest) {data, response, error in
guard let data = data else { return }
//print(String(decoding: data, as: UTF8.self))
let songs = try! JSONDecoder().decode(feed.self, from: data)
DispatchQueue.main.async {
self.fetchedSongsResults = songs.response.hits
}
}.resume()
}
}
So when I get the data I save to the variable fetchedSongsResults and this seems correctly but for what ever reason when I try to print the count for example it says that i empty and also I can't loop through the fetchedSongsResults using a list or ForEach this is how, (which I believe s because I have not made the model identifiable) I tried to print the count of fetchedSongsResults,
This initialized outside the body (just so you know)
#State var networkManager = NetworkManager()
This is inside the body
Text("\(networkManager.fetchedSongsResults.count)")
If your are wondering how my structure looks like when I decode the JSON Data then here it is
struct feed: Codable {
var meta: meta
var response: response
}
struct meta: Codable {
var status: Int
}
struct response: Codable {
var hits: [hits]
}
struct hits: Codable {
var index: String
var type: String
var result: song
}
struct song: Codable, Identifiable {
var id: Int
var header_image_thumbnail_url: String
var url: String
var title: String
var lyrics_state: String
var primary_artist: artist
}
struct artist: Codable {
var name: String
}
Try: #ObservedObject var networkManager = NetworkManager().

How do I fix error: "Expected to decode Dictionary<String, Any> but found an array instead" in this code?

import UIKit
class ViewController: UIViewController {
override func viewDidLoad() {
super.viewDidLoad()
//API Key: 5ca10b2d20a545099a108a3aeceb329c
//url: https://newsapi.org/v2/top-headlines?country=us&apiKey=5ca10b2d20a545099a108a3aeceb329c
// model
struct Source: Decodable {
var id: String
var name: String
}
struct Articles: Decodable {
var source: Source
var author: String
var title: String
var description: String
var url: String
var urlToImage: String
var publishedAt: String
var content: String
}
struct JSONDescription: Decodable {
var status: String
var totalResults: Int
var articles: Articles
}
guard let url = URL(string: "https://newsapi.org/v2/top-headlines?country=us&apiKey=5ca10b2d20a545099a108a3aeceb329c") else { return }
URLSession.shared.dataTask(with: url) { data, response, error in
guard let data = data else { return }
//let dataAsString = String(data: data, encoding: .utf8)
// print(dataAsString)
do {
let jsonDescription = try JSONDecoder().decode(JSONDescription.self, from: data)
print(jsonDescription.totalResults)
}
catch let jsonError {
print("Json Error:", jsonError)
}
}.resume()
}
}
What I expected to see was the JSON data returned here: https://newsapi.org/v2/top-headlines?country=us&apiKey=5ca10b2d20a545099a108a3aeceb329c
You can put it into this formatter to make is readable: https://jsonformatter.curiousconcept.com
I thought I did everything correctly. Have I built my model wrong? I'm not sure how to fix this error.
So, with the help of the error returned, and looking at the data, it seems that "articles" is an array.
Here's what I'd try:
Rename your Articles struct to Article
Change JSONDescription's articles property from Articles to [Article]
I didn't notice any other errors in the data mapping, but hopefully this gets you closer.