解码API数据

时间:2018-02-05 09:22:50

标签: ios swift api

我正在尝试从API获取数据,但我无法正确使用,我不知道这里的问题:

struct BTCData : Codable {
    let close : Double
    let high : Double
    let low : Double

    private enum CodingKeys : Int, CodingKey {
        case close = 3
        case high = 4
        case low = 5
    }
}

func fetchBitcoinData(completion: @escaping (BTCData?, Error?) -> Void) {
    let url = URL(string: "https://api.bitfinex.com/v2/candles/trade:30m:tBTCUSD/hist")!

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

我希望能够在每个close中访问dict并按此迭代:

var items : BTCData!

for idx in 0..<15 {
    let diff = items[idx + 1].close - items[idx].close
    upwardMovements.append(max(diff, 0))
    downwardMovements.append(max(-diff, 0))
}

我得到nil。我不明白如何解码这种API,我需要迭代不在另一个dict内的东西。

编辑:以上问题已解决,我现在正在努力在另一个功能中使用[BTCData]。

我想在这里使用它:

func fetchBitcoinData(completion: @escaping ([BTCData]?, Error?) -> Void) {

    let url = URL(string: "https://api.bitfinex.com/v2/candles/trade:30m:tBTCUSD/hist")!

    let task = URLSession.shared.dataTask(with: url) { (data, response, error) in
        guard let data = data else {
            completion(nil, error ?? FetchError.unknownNetworkError)
            return
        }
        do {
            let bitcoin = try JSONDecoder().decode([BTCData].self, from: data); completion(bitcoin, nil)
            //let close52 = bitcoin[51].close
            //print(bitcoin)
            //print(close52)
        } catch let parseError {
            completion(nil, parseError)
        }
    }
    task.resume()
}
class FindArray {

    var items = [BTCData]()

    func findArray() {
        let close2 = items[1].close
        print(close2)
    }
}

fetchBitcoinData() { items, error in
    guard let items = items,
        error == nil else {
            print(error ?? "Unknown error")
            return
    }
    let call = FindArray()
    call.items = items
    call.findArray()
}

编辑2:用[BTCData]()解决了问题。 var items : [BTCData] = []也适用

2 个答案:

答案 0 :(得分:2)

您需要使用JSONSerialization并转换为[[NSNumber]]才能获得所需的结果

<强>更新

检查https://docs.bitfinex.com/v2/reference#rest-public-candles我认为这就是您要搜索的内容

尝试使用此

func fetchBitcoinData(completion: @escaping ([BTCData]?, Error?) -> Void) {
    let url = URL(string: "https://api.bitfinex.com/v2/candles/trade:30m:tBTCUSD/hist")!

    let task = URLSession.shared.dataTask(with: url) { (data, response, error) in
        guard let data = data else { return }
        do {
                if let array = try JSONSerialization.jsonObject(with: data, options: .allowFragments) as? [[NSNumber]]{
                                            var arrayOfCoinData : [BTCData] = []
                    for currentArray in array{
                        arrayOfCoinData.append(BTCData(close: currentArray[2].doubleValue, high: currentArray[3].doubleValue, low: currentArray[4].doubleValue))
                    }
                    debugPrint(arrayOfCoinData)
                    completion(arrayOfCoinData, nil)
                }
        } catch {
            print(error)
            completion(nil, error)
        }
    }
    task.resume()
}

记录结果

  

[比特币ApiExample.BTCData(关闭:7838.8999999999996,...]

答案 1 :(得分:2)

要使用Decodable将数组数组解码为结构,必须使用unkeyedContainer。由于没有字典CodingKeys没用。

struct BTCData : Decodable {
    let timestamp : Int 
    let open, close, high, low, volume : Double

    init(from decoder: Decoder) throws {
        var container = try decoder.unkeyedContainer()
        timestamp = try container.decode(Int.self)
        open = try container.decode(Double.self)
        close = try container.decode(Double.self)
        high = try container.decode(Double.self)
        low = try container.decode(Double.self)
        volume = try container.decode(Double.self)
    }
}

您不必更改JSONDecoder()行。

...
if let bitcoin = try JSONDecoder().decode([BTCData].self, from: data).first {
   print(bitcoin)
   completion(bitcoin, nil)
}

只需添加两行,甚至可以将时间戳解码为Date

struct BTCData : Decodable {
    let timestamp : Date
    let open, close, high, low, volume : Double

    init(from decoder: Decoder) throws {
        var container = try decoder.unkeyedContainer()
        timestamp = try container.decode(Date.self)
...
let decoder = JSONDecoder()
decoder.dateDecodingStrategy = .millisecondsSince1970
if let bitcoin = try decoder.decode([BTCData].self, from: data).first {
    print(bitcoin)
    completion(bitcoin, nil)
}

解码数组并获取特定索引的值

do {
    let bitcoins = try JSONDecoder().decode([BTCData].self, from: data)
    let close52 = bitcoins[51].close
    print(close52)
...