Home > database >  getting nil when i try to make decode
getting nil when i try to make decode

Time:10-05

when i try to make decoder.decode i get result nil (i check the data and there is data, data != nil) but the decode not working I think most likely it is related to the structs, I would love to refine what I am doing wrong. i added the code below Thanks for the help

struct codable :

struct CoinsList: Codable {
    
    let data:[Coin]?
       
}

struct Coin:Codable {
    
   
    let id:Int?
    let name:String?
    let symbol:String?
    let max_supply:Int64?
    let circulating_supply:Int64?
    let total_supply: Int64?
    let cmc_rank:Int?
    let quote:QuoteData?
       
}

struct QuoteData:Codable {
    
    let USD:CoinPrice?
    
}

struct CoinPrice:Codable {
    
    let price:Double?
    let volume_24h:Double?
    let market_cap:Double?
    
}

json:

{
  status: {
     timestamp: "2022-10-04T12:34:53.878Z",
     error_code: 0,
     error_message: null,
     elapsed: 20,
     credit_count: 1,
     notice: null,
     total_count: 9462
  },
 data: [
   {
    id: 1,
    name: "Bitcoin",
    symbol: "BTC",
    slug: "bitcoin",
    num_market_pairs: 9760,
    date_added: "2013-04-28T00:00:00.000Z",
tags: [
    "mineable",
     "pow",
     "sha-256",
     "store-of-value",
     "state-channel",
     "coinbase-ventures-portfolio",
     "three-arrows-capital-portfolio",
     "polychain-capital-portfolio",
     "binance-labs-portfolio",
     "blockchain-capital-portfolio",
     "boostvc-portfolio",
     "cms-holdings-portfolio",
     "dcg-portfolio",
     "dragonfly-capital-portfolio",
     "electric-capital-portfolio",
     "fabric-ventures-portfolio",
     "framework-ventures-portfolio",
     "galaxy-digital-portfolio",
     "huobi-capital-portfolio",
     "alameda-research-portfolio",
     "a16z-portfolio",
     "1confirmation-portfolio",
     "winklevoss-capital-portfolio",
     "usv-portfolio",
     "placeholder-ventures-portfolio",
     "pantera-capital-portfolio",
     "multicoin-capital-portfolio",
      "paradigm-portfolio"
],
    max_supply: 21000000,
    circulating_supply: 19168887,
    total_supply: 19168887,
    platform: null,
    cmc_rank: 1,
    self_reported_circulating_supply: null,
    self_reported_market_cap: null,
    tvl_ratio: null,
    last_updated: "2022-10-04T12:32:00.000Z",
quote: {
  USD:  {
    price: 19944.28244328565,
    volume_24h: 33376911598.804485,
    volume_change_24h: 35.5843,
    percent_change_1h: 0.10558095,
    percent_change_24h: 3.77987746,
    percent_change_7d: -1.62664338,
    percent_change_30d: 0.4638364,
    percent_change_60d: -14.4615399,
    percent_change_90d: -0.70303523,
    market_cap: 382309696451.4265,
    market_cap_dominance: 39.9685,
    fully_diluted_market_cap: 418829931309,
tvl: null,
last_updated: "2022-10-04T12:32:00.000Z"
}
}
},

}

reuqset api :

class CoinRestApi {
    
    private let urlCoinList = "https://pro-api.coinmarketcap.com/v1/cryptocurrency/listings/latest"
    private var coinDataSource:((CoinsList?)->Void)?
    private var coins: CoinsList?
    func getCoinsLists(coinDetaClousre: @escaping (_ coinDataSource:CoinsList?)->Void) {
        
        self.coinDataSource = coinDetaClousre
        
        let url = URL(string: self.urlCoinList)
        
        guard url != nil else {
            return
        }
        let session = URLSession.shared
        let dataTask = session.dataTask(with: url!, completionHandler: ParseCoin)
        dataTask.resume()
        
        
    }
    
    private func ParseCoin(data:Data? , urlResponse:URLResponse? , error:Error?) {
        
        
        if error == nil && data != nil {
            // parse JSON
            let decoder = JSONDecoder()
            
            do {
                self.coins = try decoder.decode(CoinsList.self, from: data!)
                
            }
            catch  {
                
                print("Parseing Failed")
            }
        }
        if let coinDataSource {
            coinDataSource(coins)
        }
        
        
    }
    
    
 

CodePudding user response:

I tried your code, and it worked just fine. The JSON data you shared has a wrong format and as @workingdog said you get API key missing when trying to call the URL. So I created a data.json file with the structure fixed and tested the decode method locally and it worked ok. I suggest you use the code below to check the error you are getting, but the problem is not in the Codable structs.

let decoder = JSONDecoder()
do {
   self.coins = try decoder.decode(CoinsList.self, from: data!)
}
catch(let error){
    print("Parsing Failed \(error)")
 }

CodePudding user response:

The errors you get is probably due to your data model structs not matching the json data from the server. Try this example code. Since I do not have an api key, I've used the "test" key with the "sandbox" api, which should be the same as the "pro-api".

class CoinRestApi: ObservableObject {
    @Published var coinsList: [Coin] = []
    
    func fetchData(token: String) {
        // var urlComponents = URLComponents(string: "https://pro-api.coinmarketcap.com/v1/cryptocurrency/listings/latest")
        
        // for testing, sandbox-api
        var urlComponents = URLComponents(string: "https://sandbox-api.coinmarketcap.com/v1/cryptocurrency/listings/latest")
        guard let url = urlComponents?.url else {
            print("Invalid url")
            return
        }
        
        var request = URLRequest(url: url)
        request.httpMethod = "GET"
        request.setValue("\(token)", forHTTPHeaderField: "X-CMC_PRO_API_KEY")
        
        URLSession.shared.dataTask(with: request) { data, response, error in
            guard let data = data else { return }
            DispatchQueue.main.async {
                do {
                    let results = try JSONDecoder().decode(CryptoResponse.self, from: data)
                    self.coinsList = results.data
                } catch {
                    print(error) // <-- here important
                }
            }
        }.resume()
    }
    
}

struct ContentView: View {
    @StateObject var model = CoinRestApi()
    
    var body: some View {
        VStack {
            List(model.coinsList) { coin in
                VStack {
                    Text(coin.symbol)
                    Text("\(coin.quote["USD"]?.price ?? 0.0)")
                }
            }
        }
        .onAppear {
            model.fetchData(token: "b54bcf4d-1bca-4e8e-9a24-22ff2c3d462c")
        }
    }
}

// MARK: - CryptoResponse
struct CryptoResponse: Codable {
    let status: Status
    let data: [Coin]
}

// MARK: - Coin
struct Coin: Identifiable, Codable {
    let id: Int
    let name, symbol, slug: String
    let cmcRank, numMarketPairs, circulatingSupply, totalSupply: Int
    let maxSupply: Int
    let lastUpdated, dateAdded: String
    let tags: [String]
    let platform, selfReportedCirculatingSupply, selfReportedMarketCap: String?
    let quote: [String: Quote]

    enum CodingKeys: String, CodingKey {
        case id, name, symbol, slug
        case cmcRank = "cmc_rank"
        case numMarketPairs = "num_market_pairs"
        case circulatingSupply = "circulating_supply"
        case totalSupply = "total_supply"
        case maxSupply = "max_supply"
        case lastUpdated = "last_updated"
        case dateAdded = "date_added"
        case tags, platform
        case selfReportedCirculatingSupply = "self_reported_circulating_supply"
        case selfReportedMarketCap = "self_reported_market_cap"
        case quote
    }
}

// MARK: - Quote
struct Quote: Codable {
    let price: Double
    let volume24H: Int
    let volumeChange24H, percentChange1H, percentChange24H, percentChange7D: Double?
    let marketCap: Double
    let marketCapDominance: Int
    let fullyDilutedMarketCap: Double
    let lastUpdated: String

    enum CodingKeys: String, CodingKey {
        case price
        case volume24H = "volume_24h"
        case volumeChange24H = "volume_change_24h"
        case percentChange1H = "percent_change_1h"
        case percentChange24H = "percent_change_24h"
        case percentChange7D = "percent_change_7d"
        case marketCap = "market_cap"
        case marketCapDominance = "market_cap_dominance"
        case fullyDilutedMarketCap = "fully_diluted_market_cap"
        case lastUpdated = "last_updated"
    }
}

// MARK: - Status
struct Status: Codable {
    let timestamp: String
    let errorCode: Int
    let errorMessage: String?
    let elapsed, creditCount: Int
    let notice: String?

    enum CodingKeys: String, CodingKey {
        case timestamp
        case errorCode = "error_code"
        case errorMessage = "error_message"
        case elapsed
        case creditCount = "credit_count"
        case notice
    }
}
  • Related