Cannot assign value, SwiftUI fetch API - ios

I wanted to grab data from exchangeratesapi.io, but I have been struggling with modeling my data.
it says "Cannot assign value of type 'rates' to type rates.Type"
I have no idea what I did nor have any visualization , if there's any reference please do comment below.
Here's my class
class MoneyView:ObservableObject {
#Published var currency = rates.self//[rates]()
init() {
fetchData()
}
func fetchData() {
guard let url = URL(string: "http://api.exchangeratesapi.io/v1/latest?access_key=24a5ab7688a7044f60bfeb491eb37550") else {
return
}
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 result = try decoder.decode(rates.self, from: safeData)
DispatchQueue.main.async {
self.currency = result // here's the error
}
} catch {
print(error)
}
}
}
}
task.resume()
}
}
Here's the rates type :
struct rates: Decodable{
// USD CAD IDR GBP CHF SGD INR MYR JPY KRW
var USD:Int
var CAD:Int
var IDR:Int
var GBP:Int
var CHF:Int
var SGD:Int
var INR:Int
var MYR:Int
var JPY:Int
var KWR:Int
}
in case you guys wonder how the API looks like
{
"success":true,
"timestamp":1620597364,
"base":"EUR",
"date":"2021-05-09",
"rates":{
"AED":4.469059,
"AFN":93.55172,
"ALL":122.991702,
"AMD":629.683505,
"ANG":2.167635,
"AOA":795.883245,
}
}

Change
#Published var currency:Rate?
struct Root: Decodable{
var rates:Rate
}
struct Rate: Decodable{
var USD:Int
var CAD:Int
var IDR:Int
var GBP:Int
var CHF:Int
var SGD:Int
var INR:Int
var MYR:Int
var JPY:Int
var KWR:Int
}
let result = try decoder.decode(Root.self, from: safeData)
currency = result.rates
Change class start letter to capital Rates

Related

How to display only 12 hours of hourly temp from OpenWeatherMap?

I’m having a brain block right now and I can’t figure out how to display only 12 hours of hourly temperature rather than the 48 hours with the OpenWeatherMap API OneCall. I've tried messing around with the for-in loop but not having any luck.
Here is my ViewModel
class WeatherModel: ObservableObject {
//Declare published property wrapper, that when the the property value changes, we want to notifty anyone who is observing it
#Published var weatherData: Weather?
#AppStorage("cityName") var cityName = ""
init(){
getWeatherData(cityName)
}
//Init method gets run when a new instance of WeatherModel is created
//MARK: - OpenWeatherMap API methods
func getWeatherData(_ cityName: String){
CLGeocoder().geocodeAddressString(cityName){(placemarks, error ) in
if let error = error {
print(error)
}
if let lat = placemarks?.first?.location?.coordinate.latitude,
let lon = placemarks?.first?.location?.coordinate.longitude {
//first is the first element of the collection
let weatherUrlString = "https://api.openweathermap.org/data/2.5/onecall?lat=\(lat)&lon=\(lon)&exclude=minutely,daily,alerts&units=imperial&appid=\(Constants.apiKey)"
let weatherUrl = URL(string: weatherUrlString)
guard weatherUrl != nil else {
return
}
let request = URLRequest(url: weatherUrl!)
//Create a URL session
let session = URLSession.shared
let dataTask = session.dataTask(with: request) { data, response, error in
guard error == nil else {
return
}
do{
let decoder = JSONDecoder()
var result = try decoder.decode(Weather.self, from: data!)
//parsing the weather data into the constant, result
//Add UUId's to the hourly weather objects. Use the variable Result since that is parsing the weather
for i in 0..<result.hourly.count {
result.hourly[i].id = UUID()
}
DispatchQueue.main.async {
self.weatherData = result
}
}catch {
print(error)
}
}
dataTask.resume()
}
}
}//func getWeatherData
}
My Model
struct Weather: Decodable {
var current: Current
var hourly: [Current]
//Hourly is an arrary of weather responses (i.e. Current). It parses the data because the arrary is similar to Current properties
}
struct Current: Decodable, Identifiable {
var id: UUID?
var dt: Double
var temp: Double
var feels_like: Double
var weather: [WeatherInfo]
}
struct WeatherInfo: Decodable {
var description: String
}
Right now this is just a rough view and will update the look of it but for now I’m putting it as a list. I only want 12 hours of the hourly temperature rather than the 48 hours
View
List(model.weatherData?.hourly ?? [] ) {
hour in
Text("\(Constants.dtConversion(hour.dt)), \(Constants.tempToString(hour.temp))")

How to read Firestore data from a Map field type?

My Firestore data is set up like this:
This is how I'm reading the data:
for doc in snapshot!.documents {
let recipeFromFirestore = Recipe(
glutenFree: doc["glutenFree"] as! Bool,
dairyFree: doc["dairyFree"] as! Bool,
cheap: doc["cheap"] as! Bool)
recipes.append(recipeFromFirestore)
}
These are my Recipe and ExtendedIngredients structs:
struct Recipe: Codable {
var glutenFree: Bool?
var dairyFree: Bool?
var cheap: Bool?
var extendedIngredients: [ExtendedIngredients]? = nil
}
struct ExtendedIngredients: Codable {
var aisle: String?
var image: String?
var name: String?
var amount: Double?
var unit: String?
}
How can I go about reading the array of Map type data in my extendedIngredients field in Firestore? I'm not sure how to include that in my let recipeFromFirestore code.
Any help or guidance is much appreciated!
I was able to get all of my data, including the Map type by using the Codable API.
docRef.getDocument { document, error in
if let error = error as NSError? {
self.errorMessage = "Error getting document: \(error.localizedDescription)"
}
else {
if let document = document {
do {
self.recipe = try document.data(as: Recipe.self)
let recipeFromFirestore = Recipe(
glutenFree: self.recipe!.glutenFree,
dairyFree: self.recipe!.dairyFree,
cheap: self.recipe!.cheap,
extendedIngredients: self.recipe!.extendedIngredients)
self.recipes.append(recipeFromFirestore)
}
catch {
print("Line 136: \(error)")
}
}
}
}
I did not need to do any explicit mapping with this approach.

SWIFT "Expected to decode Dictionary<String, Any> but found an array instead.", underlyingError: nil))

This is my first-time question.
I thought I did everything correctly. Have I built my model wrong? I'm not sure how to fix this error.
This is my code, after the correct model I want to pass the data to the table:
func createJSON() {
if let url = URL(string: "https://newsapi.org/v2/everything?q=apple&from=2020-11-15&to=2020-11-15&sortBy=popularity&apiKey=c5722efe6e65432fb5c116d3e1403dca") {
let session = URLSession(configuration: .default)
let task = session.dataTask(with: url) { (data, response, error) in
guard let data = data, error == nil else { return }
var result: NewsResult?
do {
result = try JSONDecoder().decode(NewsResult.self, from: data)
} catch {
print("error masage: \(error)")
}
guard let finalResult = result else { return }
print(finalResult.status)
print(finalResult.totalResults)
// print(finalResult.articles)
// let newNews = finalResult.artiscles
// self.newsApple.append(contentsOf: newNews)
DispatchQueue.main.async {
self.tableView.reloadData()
}
}
task.resume()
}
}
// MARK: - Model Data Source
struct NewsResult:Codable {
let status: String
let totalResults: Int // totalResults
let articles: [articles]
}
struct articles:Codable {
let author: String // articles[0].author
let title: String
let description: String
let url:String
let urlToImage:String
let publishedAt: String
let content: String
}
You have written the model code that was not mapping correctly with JSON resultant. Try replacing your model structure with the following code:
struct NewsResult: Codable {
var status: String?
var totalResults: Int?
var articles: [Article]?
}
struct Article: Codable {
var source: Source?
var author: String?
var title: String?
var articleDescription: String?
var url: String?
var urlToImage: String?
var publishedAt: String?
var content: String?
}
struct Source: Codable {
var id : String?
var name: String?
}

Swift Does not see data

I am trying to parse the data and display on the screen but i am getting " Value of type 'EmployeeData' has no member 'employee_name' "
What i am missing ?
I created my struct, parsed data and tried to divide into two parts. first part will be related with listing, second part is all data.
struct EmployeeData: Codable {
var data: Employee
var status: String
}
struct Employee: Codable {
var employee_name: String
var employee_salary: String
var employee_age: String
}
class WebServices {
func getData(completion: #escaping (EmployeeData?) -> ()){
guard let url = URL(string:"http://dummy.restapiexample.com/api/v1/employees")
else { fatalError("There is error!") }
URLSession.shared.dataTask(with: url) { (data, response,error) in
guard let data = data, error == nil else {
DispatchQueue.main.async{
completion(nil)
}
return
}
let empleyees = try? JSONDecoder().decode(EmployeeData.self, from: data)
DispatchQueue.main.async {
completion(empleyees)
}
}.resume()
}
}
class MVDesingnListView: ObservableObject {
}
struct MVDesignCellView {
let employeeDatas: EmployeeData
init(employeeDatas: EmployeeData) {
self.employeeDatas = employeeDatas
}
var employee_name: String {
self.employeeDatas.employee_name
}
}
The compiler is all right. Your struct EmployeeData has no member employee_name.
You need to go to the employee first, to get her name:
var employee_name: String {
self.employeeDatas.data.employee_name
}
should do the job.

how to parse this json in swift?

I have a request
Alamofire.request(.GET,HttpHelper.baseURL+HttpHelper.tripsURL,encoding:.JSON).responseJSON {
response in
var json = JSON(data: response.data!)
print(json)
print(json["res"])
}
followed by the result
{
"res" : "[{\"name\":\"testName\",\"lastName\":\"testLastName\"},{\"name\":\"testName\",\"lastName\":\"testLastName\"}]",
"status" : "success",
"out" : "{\"name\":\"testName\",\"lastName\":\"testLastName\"}"
}
[{"name":"testName","lastName":"testLastName"},{"name":"testName","lastName":"testLastName"}]
how i can set data from res to struct or class User
struct User {
var name : String?
var lastName : String?
}
please help to solve this problem) thank you very much !!)
You can do something like that
var result: [User]()
for user in json["res"] {
let userTmp = User(name: user["name"], lastName: user["lastName"])
result.append(userTmp)
}
Regards
Basically, it would be:
class User {
var name : String?
var lastName : String?
}
var theUsers = [User]()
Alamofire.request(.GET,HttpHelper.baseURL+HttpHelper.tripsURL,encoding:.JSON)
.responseJSON { response in
var json = JSON(data: response.data!)
print(json)
theUsers = json["res"].map {
return User (name: $0["name"], lastName: $0.["lastName"])
}
})
However, along the way, you might need some typecasting. For example, maybe replace json["res"] with (json["res"] as Array<Dictionary<String,String>>) in order to keep the type checker and type inferencer happy.
I'm using native Codable protocol to do that:
class MyClass: Codable {
var int: Int?
var string: String?
var bool: Bool?
var double: Double?
}
let myClass = MyClass()
myClass.int = 1
myClass.string = "Rodrigo"
myClass.bool = true
myClass.double = 2.2
if let json = JsonUtil<MyClass>.toJson(myClass) {
print(json) // {"bool":true,"string":"Rodrigo","double":2.2,"int":1}
if let myClass = JsonUtil<MyClass>.from(json: json) {
print(myClass.int ?? 0) // 1
print(myClass.string ?? "nil") // Rodrigo
print(myClass.bool ?? false) // true
print(myClass.double ?? 0) // 2.2
}
}
And I created a JsonUtil to help me:
public struct JsonUtil<T: Codable> {
public static func from(json: String) -> T? {
if let jsonData = json.data(using: .utf8) {
let jsonDecoder = JSONDecoder()
do {
return try jsonDecoder.decode(T.self, from: jsonData)
} catch {
print(error)
}
}
return nil
}
public static func toJson(_ obj: T) -> String? {
let jsonEncoder = JSONEncoder()
do {
let jsonData = try jsonEncoder.encode(obj)
return String(data: jsonData, encoding: String.Encoding.utf8)
} catch {
print(error)
return nil
}
}
}
And if you have some issue with Any type in yours objects. Please look my other answer:
https://stackoverflow.com/a/51728972/3368791
Good luck :)

Resources