2017-12-26 45 views
1

API에서 데이터를 가져 와서 라벨을 업데이트하여 앱의 Bitcoin 가격 및 백분율 변화를 인쇄하려고하지만 JSON을 올바르게 디코딩하는 방법을 알 수 없습니다.API에서 JSON 데이터를 디코딩 할 수 없습니다.

BitcoinInfo.swift :

import Foundation 
import UIKit 

struct Bitcoin: Codable { 
    let percentChange1h: String 
    let priceEUR: String 
    private enum CodingKeys: String, CodingKey { 
     case percentChange1h = "percent_change_1h", priceEUR = "price_eur" 
    } 
} 

extension Bitcoin { 
    var priceEURdecimal: Decimal { 
     return Decimal(string: priceEUR) ?? 0 
    } 
    var priceEURcurrency: String { 
     Formatter.currency.locale = Locale(identifier: "fr_FR") 
     return Formatter.currency.string(for: priceEURdecimal) ?? "" 
    } 
} 

ViewController.swift :

import Foundation 
import UIKit 

class ViewController: UIViewController { 

    let bitcoinInfoController = BitcoinInfoController() 

    @IBOutlet weak var bitcoinPriceLabel: UILabel! 
    @IBOutlet weak var bitcoinPercentageChangeLabel: UILabel! 

    override func viewDidLoad() { 
     super.viewDidLoad() 

     bitcoinPriceLabel.text = "" 
     bitcoinPercentageChangeLabel.text = "" 

     fetchBitcoinInfo { bitcoin, error in 
      guard let bitcoin = bitcoin else { 
       print(error!); 
       return 
      } 
      self.updateUI(with: bitcoin) 
     } 
    } 

    override func didReceiveMemoryWarning() { 
     super.didReceiveMemoryWarning() 

    } 

    func updateUI(with bitcoinInfo: Bitcoin) { 
     DispatchQueue.main.async { 
      self.bitcoinPriceLabel.text = bitcoinInfo.priceEURcurrency 
      self.bitcoinPercentageChangeLabel.text = String(format: "%.2f%%", Double(bitcoinInfo.percentChange1h) ?? 0) 
     } 
    } 

    func fetchBitcoinInfo(completion: @escaping (Bitcoin?, Error?) -> Void) { 
     let baseURL = URL(string: "https://api.coinmarketcap.com/v1/ticker/bitcoin/?convert=EUR")! 

     let url = baseURL 

     let task = URLSession.shared.dataTask(with: url) { (data, response, error) in 
      guard let data = data else { return } 
      do { 
       if let bitcoinEUR = try JSONDecoder().decode([Bitcoin].self, from: data).first { 
        print(bitcoinEUR) 
        print(bitcoinEUR.priceEUR) 
        print(bitcoinEUR.priceEURdecimal) 
        print(bitcoinEUR.priceEURcurrency) 
        print(bitcoinEUR.percentChange1h) 
        completion(bitcoinEUR, nil) 
       } 
      } catch { 
       print(error) 
      } 
     } 
     task.resume() 
    } 

} 

콘솔은 ". 데이터 중 하나가 반환되지 않았거나 데이터가 제대로 디코딩되지 않았다"인쇄 중입니다

편집 : 이것은 최신 코드 버전입니다. EDIT2 : 이제 코드가 100 % 기능적입니다! :)

+0

'try? '로 디코딩 오류를 버리지 마세요. 오류를 잡아서 출력하십시오. 문제가 무엇인지 정확하게 알려줄 것입니다. – Hamish

+0

감사합니다. Hamish, 당신은 저에게 말해야 할 첫 번째 인물이 아닙니다. 나는 Apple의 과정을 통해 Swift를 배우고 있으며, 그들은 시험으로 가르치고 있나? 처음에는 나를 위해 바뀌는 나쁜 습관 – Wizzardzz

+0

@ Wizzardzz는 달러 통화 기호를 사용하여 유로 가격을 표시하고 있음에 유의하십시오. –

답변

1

주요 문제는 가격과 백분율이 두 배가 아닌 문자열입니다. 를 디코딩 할 때 [Bitcoin].self 유형을 사용할 필요가 있으므로 BTW는 배열을 반환

이 당신의 codable 구조체가 같이하는 방법입니다 :

struct Bitcoin: Codable { 
    let id: String 
    let name: String 
    let symbol: String 
    let rank: String 
    let priceUSD: String 
    let priceBTC: String 
    let volume24hUSD: String 
    let marketCapUSD: String 
    let availableSupply: String 
    let totalSupply: String 
    let maxSupply: String 
    let percentChange1h: String 
    let percentChange24h: String 
    let percentChange7d: String 
    let lastUpdated: String 
    let priceEUR: String 
    let volume24hEUR: String 
    let marketCapEUR: String 
    private enum CodingKeys: String, CodingKey { 
     case id, name, symbol, rank, 
     priceUSD = "price_usd", 
     priceBTC = "price_btc", 
     volume24hUSD = "24h_volume_usd", 
     marketCapUSD = "market_cap_usd", 
     availableSupply = "available_supply", 
     totalSupply = "total_supply", 
     maxSupply = "max_supply", 
     percentChange1h = "percent_change_1h", 
     percentChange24h = "percent_change_24h", 
     percentChange7d = "percent_change_7d", 
     lastUpdated = "last_updated", 
     priceEUR = "price_eur", 
     volume24hEUR = "24h_volume_eur", 
     marketCapEUR = "market_cap_eur" 
    } 
} 

그리고 이것은 당신이 JSON 배열을 디코딩하는 방법입니다 API에서 돌아와 첫 번째 요소를 얻을 : 만 관심이 있다면

do { 
    if let bitcoinEUR = try JSONDecoder().decode([Bitcoin].self, from: data).first { 
     print(bitcoinEUR) 
     print(bitcoinEUR.priceEUR) 
     print(bitcoinEUR.percentChange1h) 
    } 
} catch { 
    print(error) 
} 

을 에드는 두 속성이처럼 비트 코인 구조를 설정할 수 있습니다

struct Bitcoin: Codable { 
    let percentChange1h: String 
    let priceEUR: String 
    private enum CodingKeys: String, CodingKey { 
     case percentChange1h = "percent_change_1h", priceEUR = "price_eur" 
    } 
} 

편집/업데이트를 :

참고 : 당신은 달러 통화 기호를 사용하여 유로 가격을 표시하고 있습니다. 유로 값을 2 소수 자릿수로 포맷해야하는 경우 먼저 API에서 반환 한 문자열로 새 부동 소수점 객체를 초기화해야합니다.

그래서 당신은 진수하는 유로 가격 문자열을 변환하는 데,이 계산 된 속성 하나를 비트 코인의 API를 확장 할 수 있으며, 다른 통화로 진수 값을 포맷 :

extension Bitcoin { 
    var priceEURdecimal: Decimal { 
     return Decimal(string: priceEUR) ?? 0 
    } 
    var priceEURcurrency: String { 
     Formatter.currency.locale = Locale(identifier: "fr_FR") 
     return Formatter.currency.string(for: priceEURdecimal) ?? "" 
    } 
} 

당신은 사람들을 추가하는 것이 필요합니다

extension NumberFormatter { 
    convenience init(numberStyle: Style) { 
     self.init() 
     self.numberStyle = numberStyle 
    } 
} 
extension Formatter { 
    static let currency = NumberFormatter(numberStyle: .currency) 
} 

사용법 :

프로젝트에서 새로운 스위프트 파일 확장자는 통화를 포맷 도움
do { 
    if let bitcoinEUR = try JSONDecoder().decode([Bitcoin].self, from: data).first { 
     print(bitcoinEUR.priceEURdecimal) // "13823.952495\n" 
     print(bitcoinEUR.priceEURcurrency) // "13 823,95 €\ 
    } 
} catch { 
    print(error) 
} 
+0

감사합니다. Léo! 부동 소수점이란 무엇입니까? 데이터로 라벨을 업데이트하는 방법을 아직 모르겠습니다. – Wizzardzz

+0

부동 소수점은 Double 또는 Float가 될 수 있습니다.Decimal 형식을 사용할 수도 있습니다. 통화를 형식화하려는 로케일은 무엇입니까? 유로 통화에는 로케일 (프랑스, 독일 등 ...)에 따라 여러 가지 방법이 있습니다. –

+0

프랑스어 로켈을 사용했지만 필요에 따라 변경할 수 있습니다. –