Learn Courses My Dashboard

How should I solve this error?

Hey all! I was trying to make a crypto tracking app, but ran into an error. The error states:

Cannot convert value of type 'Coins' to expected argument type 'Coin'

My ContentView.swift file:

import SwiftUI
import Combine

struct CoinView: View {
    var body: some View {
        Text(/*@START_MENU_TOKEN@*/"Hello, World!"/*@END_MENU_TOKEN@*/)
    }
}

struct CoinView_Previews: PreviewProvider {
    static var previews: some View {
        CoinView()
    }
}

struct Coin {
    let name: String
    let price: String
}


struct CoinViewModel {
    private let coin: Coin
    var name: String {
        return coin.name
    }
    var formattedPrice: String {
        return coin.price
    }
    init(_ coin: Coin) {
        self.coin = coin
    }
}

class CoinClassViewModel: ObservableObject {
    private let cryptoService = CryptoService()
    @Published var coinViewModels = [CoinViewModel]()
    var cancellable: AnyCancellable?
    
    func fetchCoins() {
        cancellable = cryptoService.fetchCoins().sink(receiveCompletion: { _ in
            
        }, receiveValue: { cryptoContainer in
            self.coinViewModels = cryptoContainer.data.coins.map { CoinViewModel($0) } //ERROR
        })
    }
}

My CryptoService.swift file:

import Foundation
import Combine

final class CryptoService {
    var components: URLComponents {
        var components = URLComponents()
        components.scheme = "https"
        components.host = "api.coinranking.com"
        components.path = "/v1/public/coins"
        components.queryItems = [URLQueryItem(name: "base", value: "USD"), URLQueryItem(name: "timePeriod", value: "24h")]
        return components
    }
    
    func fetchCoins() -> AnyPublisher<CryptoDataContainer, Error> {
        return URLSession.shared.dataTaskPublisher(for: components.url!)
            .map {
                $0.data
            }
            .decode(type: CryptoDataContainer.self, decoder: JSONDecoder())
            .eraseToAnyPublisher()
    }
}

struct CryptoDataContainer: Decodable {
    let status: String
    let data: CryptoData
}

struct CryptoData: Decodable {
    let coins: [Coins]
}

struct Coins: Decodable {
    let name: String
    let price: String
}

Can anyone help me? I’ve marked the line with the error. It’s at the bottom of the ContentView.swift file. Thanks :slight_smile:

Your CoinViewModel has this initializer:

    init(_ coin: Coin) {
        self.coin = coin
    }

But in this line:

self.coinViewModels = cryptoContainer.data.coins.map { CoinViewModel($0) }

you are passing it a Coins structure because that’s what you defined CryptoData as having:

struct CryptoData: Decodable {
    let coins: [Coins]
}

Why do you have these two structs that are identical, just one conforms to Decodable and one doesn’t?

struct Coin {
    let name: String
    let price: String
}

struct Coins: Decodable {
    let name: String
    let price: String
}

You should just conform Coin to Decodable and use it instead of creating a new type. Then your CryptoData would be this:

struct CryptoData: Decodable {
    let coins: [Coin]
}

and your problem would go away.

@roosterboy
Thank you! It works like a charm now!