Goals
- Accessing the Dictionaries within an array
- Some how get all 1957 Dictionaries decoded without hand coding each ticker name.
With the help of another question which was answered here I have included code below which I am trying to change to accomplish the above goals.
CallApi.swift - this file calls the API and models it to PriceApiModel
import UIKit
class ViewController: UIViewController {
let headers = [
"X-RapidAPI-Key": "Sorry I cannot include this",
"X-RapidAPI-Host": "binance43.p.rapidapi.com"
]
let request = NSMutableURLRequest(url: NSURL(string: "https://binance43.p.rapidapi.com/ticker/price")! as URL,
cachePolicy: .useProtocolCachePolicy,
timeoutInterval: 10.0)
func getData() {
request.httpMethod = "GET"
request.allHTTPHeaderFields = headers
let session = URLSession.shared
let dataTask = session.dataTask(with: request as URLRequest, completionHandler: { (data, response, error) -> Void in
if (error != nil) {
print("error")
} else {
let httpResponse = response as? HTTPURLResponse
do {
//let dictionary = try JSONSerialization.jsonObject(with: data!, options: [])
let model = try JSONDecoder().decode(PriceApiModel.self, from: data!)
//print(String(model.symbol) "name") // please see output below
//print(dictionary)
} catch {
print("NOT WORKING ")
}
}
})
dataTask.resume()
}
}
PriceApiModel.swift - I am trying to find a way for this file to be a model for decoding the data
struct PriceApiModel: Hashable, Codable {
//changed the String type to Decimal
var price: String
// every property you are interested to decode needs a CodingKey.
// You can omit values you are not interested in
enum CodingKeys: CodingKey{
case askPrice
}
// here you decode your data into the struct
init(from decoder: Decoder) throws {
// get the container
let container = try decoder.container(keyedBy: CodingKeys.self)
// decode the askPrice into a String and cast it into a Decimal
let askPrice = String(try container.decode(String.self, forKey: .askPrice))
// check if casting was succesfull else throw
guard let askPrice = askPrice else{
throw CustomError.decodingError
}
// assign it
self.askPrice = askPrice
}
}
CodePudding user response:
So I just tried out what you want to achieve here. First of all, you declared a service class (fetching data) as ViewController, by inheritance a UIViewController
. It seems to me a bit odd just having this in a class because the UIViewController
is not used. Secondly, I would recommend you to watch or read something about Codable
for example Hackingforswift. It helped at least me :)
However, here is a Code that shows you a way how it could work:
OptionalObject
is needed because of the data structure, holding everything within an array.
struct OptionalObject<Base: Decodable>: Decodable {
public let value: Base?
public init(from decoder: Decoder) throws {
do {
let container = try decoder.singleValueContainer()
self.value = try container.decode(Base.self)
} catch {
self.value = nil
}
}
}
struct PriceApiModel: Codable {
let price: String
let symbol: String
}
class Service {
let headers = [
"X-RapidAPI-Key": "",
"X-RapidAPI-Host": "binance43.p.rapidapi.com"
]
let request = NSMutableURLRequest(
url: URL(string: "https://binance43.p.rapidapi.com/ticker/price")!,
cachePolicy: .useProtocolCachePolicy,
timeoutInterval: 5.0
)
init() {
self.getData()
}
func getData() {
request.httpMethod = "GET"
request.allHTTPHeaderFields = headers
let session = URLSession.shared
let dataTask = session.dataTask(with: request as URLRequest, completionHandler: { (data, response, error) -> Void in
if let data = data {
let model = try? JSONDecoder().decode([OptionalObject<PriceApiModel>].self, from: data)
print(model?.compactMap { $0.value?.price })
print(model?.compactMap { $0.value?.symbol })
}
})
dataTask.resume()
}
}
Hope I could help.