失业中 swiftUI json数据解析 和模型数据,网络请求

281 阅读2分钟

app.quicktype.io/

image.png

image.png

image.png

image.png

image.png

image.png

image.png

model数据

// 一定要一一对应上

struct CoinModel:Identifiable,Codable{

    let id, symbol, name: String

    let image: String

    let currentPrice :Double

    let marketCap, marketCapRank, fullyDilutedValuation: Double?

    let totalVolume, high24H, low24H: Double?

    let priceChange24H, priceChangePercentage24H: Double?

    let marketCapChange24H: Double?

    let marketCapChangePercentage24H: Double?

    let circulatingSupply, totalSupply, maxSupply, ath: Double?

    let athChangePercentage: Double?

    let athDate: String?

    let atl, atlChangePercentage: Double?

    let atlDate: String?

    let lastUpdated: String?

    let sparklineIn7D: SparklineIn7D?

    let priceChangePercentage24HInCurrency: Double?

    let currentHoldinds:Double?

    

    // 查看是否有下划线

    enum CodingKeys:String,CodingKey{

        case id,symbol,name,image

        case currentPrice = "current_price"

        case marketCap = "market_cap"

        case marketCapRank = "market_cap_rank"

        case fullyDilutedValuation = "fully_diluted_valuation"

        case totalVolume = "total_volume"

        case high24H = "high_24h"

        case low24H = "low_24h"

        case priceChange24H = "price_change_24h"

        case priceChangePercentage24H = "price_change_percentage_24h"

        case marketCapChange24H = "market_cap_change_24h"

        case marketCapChangePercentage24H = "market_cap_change_percentage_24h"

        case circulatingSupply = "circulating_supply"

        case totalSupply = "total_supply"

        case maxSupply = "max_supply"

        case ath

        case athChangePercentage = "ath_change_percentage"

        case athDate = "ath_date"

        case atl

        case atlChangePercentage = "atl_change_percentage"

        case atlDate = "atl_date"

        case lastUpdated = "last_updated"

        case sparklineIn7D = "sparkline_in_7d"

        case priceChangePercentage24HInCurrency = "price_change_percentage_24h_in_currency"

        case currentHoldinds

    }

    

    // 更新模型

    func updateHolding(amount:Double) -> CoinModel{

        return CoinModel(id: id, symbol: symbol, name: name, image: image, currentPrice: currentPrice, marketCap: marketCap, marketCapRank: marketCapRank, fullyDilutedValuation: fullyDilutedValuation, totalVolume: totalVolume, high24H: high24H, low24H: low24H, priceChange24H: priceChange24H, priceChangePercentage24H: priceChangePercentage24H, marketCapChange24H: marketCapChange24H, marketCapChangePercentage24H: marketCapChangePercentage24H, circulatingSupply: circulatingSupply, totalSupply: totalSupply, maxSupply: maxSupply, ath: ath, athChangePercentage: athChangePercentage, athDate: athDate, atl: atl, atlChangePercentage: atlChangePercentage, atlDate: atlDate, lastUpdated: lastUpdated, sparklineIn7D: sparklineIn7D, priceChangePercentage24HInCurrency: priceChangePercentage24HInCurrency, currentHoldinds: amount)

    }

    var*currentHoldingsValue:Double{

        return (currentHoldinds ?? 0) * currentPrice

    }

    

    var rank:Int{

        return Int(marketCapRank ?? 0)

    }

}


// MARK: - SparklineIn7D

struct SparklineIn7D:Codable// 迷你图

    let price: [Double]?

}

网络请求封装

import Foundation

import Combine

  


// 网络请求封装

class NetworkingManager{

    

    enum NetworkingError:LocalizedError{

        case badURLResponse(url:URL)

        case unknown

        

        var errorDescription: String?{

            switch self{

            case .badURLResponse(url:**let** url):return "[hot] bad response from URL \(url)"

            case .unknown:return "Unknown error occured"

            }

        }

    }

    

    static func download(url:URL) -> AnyPublisher<Data,Error>{

        return URLSession.shared.dataTaskPublisher(for: url)

            .subscribe(on: DispatchQueue.global(qos: .default))

            .tryMap({try handleURLResponse(output: $0,url: url)})

            .receive(on: DispatchQueue.main)

            .eraseToAnyPublisher()

        

    }

    

    static func handleURLResponse(output:URLSession.DataTaskPublisher.Output,url:URL) throws -> Data{

       // throw NetworkingError.badURLResponse(url: url)

        guard let response = output.response as? HTTPURLResponse,

              response.statusCode >= 200 && response.statusCode < 300 else{

            throw NetworkingError.badURLResponse(url: url)

        }

        return output.data

    }

    

    static func handleCompletion(completion:Subscribers.Completion<Error>){

        switch completion{

        case .finished:

            break

        case .failure(**let** error):

            print(error.localizedDescription)

        }

    }

}

请求

import Foundation

import Combine

  


class CoinDataSerice{

    // 订阅 和发布者

    @Published var allCoins:[CoinModel] = []

    var cancellables = Set<AnyCancellable>()

    

    var coinSubscription:AnyCancellable?

    

    init(){

        getCoins()

    }

    

    private func getCoins(){

        guard let url = URL(string: "https://api.coingecko.com/api/v3/coins/markets?vs_currency=usd&order=market_cap_desc&per_page=250&page=1&sparkline=true&price_change_percentage=24h&locale=en") else{**return**}

        

        coinSubscription = NetworkingManager.download(url: url)

            .decode(type: [CoinModel].self, decoder: JSONDecoder())

            .sink(receiveCompletion: NetworkingManager.handleCompletion, receiveValue: {[weak self] (returnedCoins) in

                self?.allCoins = returnedCoins

                self?.coinSubscription?.cancel()

            })

  


    }

}

数据与模型数据交互

import Foundation

import Combine

  


class HomeViewModel:ObservableObject{

    @Published var allCoins:[CoinModel] = []

    @Published var portfoliCoins:[CoinModel] = []

    

    private let dataService = CoinDataSerice()

    

    private var cancellables = Set<AnyCancellable>()

    

    init(){

        // 这里不懂

//        DispatchQueue.main.asyncAfter(deadline: .now() + 2.0){

//            self.allCoins.append(DevelooperPreview.instance.coin)

//            self.portfoliCoins.append(DevelooperPreview.instance.coin)

//

//        }

        addSubscribers()

    }

    

    func addSubscribers(){

        dataService.$allCoins

            .sink { [**weak** **self**] (returnedCoins) **in**

                self?.allCoins = returnedCoins

                self?.portfoliCoins = returnedCoins

            }.store(in: &cancellables)

  


    }

}

页面显示

image.png