Swift 5 从 https 请求中解析 Json 数据

Swift 5 Parse Json data from https request

我正在尝试解析 json 并获取 “价格” 值。我如何解析 json 以在 swift 5 编程语言中实现此目的。我已经尝试过 codable struct,但我总是得到一个空结果。

JSON

{
  "status" : "success",
  "data" : {
    "network" : "DOGE",
    "prices" : [
      {
        "price" : "0.37981",
        "price_base" : "USD",
        "exchange" : "binance",
        "time" : 1620014229
      }
    ]
  }
}

Swift

func api()

guard let url = URL(string: "https://sochain.com//api/v2/get_price/DOGE/USD") else { return }

        let task = URLSession.shared.dataTask(with: url) { data, response, error in

          guard let data = data, error == nil else { return }

           let dataString = String(data: data, encoding: .utf8)
  }
    
        task.resume()

}

为您的 JSONDecoder

使用 .convertFromSnakeCase
   func fetch(callback: @escaping (Result<DataPrice, Error>)->Void) {
        guard let url = URL(string: "https://sochain.com//api/v2/get_price/DOGE/USD") else { return }

        URLSession.shared.dataTask(with: url) { (data, response, error) in
            guard let data = data else {
                if let error = error {
                    callback(.failure(error))
                }
                return
            }
            do {
                let decoder = JSONDecoder()
                decoder.keyDecodingStrategy = .convertFromSnakeCase
                let result = try decoder.decode(DataPrice.self, from: data)
                
                callback(.success(result))
            } catch {
                callback(.failure(error))
            }
        }.resume()
            
    }

你的模型应该看起来像

struct DataPrice: Decodable {
  var data : Prices
}
struct Prices: Decodable {
    var prices: [Price]
}
struct Price: Decodable {
    var price : String
    var priceBase: String
    var exchange: String
    var time: Int
}

你需要做的。

  1. responsedata转换为json

  2. 阅读你得到的甲酸盐(在这里你会得到字典)

        guard let url = URL(string: "https://sochain.com//api/v2/get_price/DOGE/USD") else { return }
    
         let task = URLSession.shared.dataTask(with: url) { data, response, error in
    
             guard let data = data, error == nil else { return }
    
             do {
                 // make sure this JSON is in the format we expect
                 // convert data to json
                 if let json = try JSONSerialization.jsonObject(with: data, options: []) as? [String: Any] {
                     // try to read out a dictionary
                     print(json)
                     if let data = json["data"] as? [String:Any] {
                         print(data)
                         if let prices = data["prices"] as? [[String:Any]] {
                             print(prices)
                             let dict = prices[0]
                             print(dict)
                             if let price = dict["price"] as? String{
                                 print(price)
                             }
                         }
                     }
                 }
             } catch let error as NSError {
                 print("Failed to load: \(error.localizedDescription)")
             }
    
         }
    
         task.resume()
    

设置您的结构并展开常量以防止应用程序崩溃:

struct DataPrice: Decodable {
let data: Prices?
}

struct Prices: Decodable {
let prices: [MyPrice]?
let network: String?
}

struct MyPrice: Decodable {

let price: String?
let price_base: String?
let exchange: String?
let time: Double?
}

现在在控制器中设置 tableView 并添加 UITableViewDelegate 和 UITableViewDataSource 以显示结果:

class ViewController: UIViewController, UITableViewDelegate, UITableViewDataSource {

let tableView = UITableView()

var productList = [MyPrice]()

override func viewDidLoad() {
    super.viewDidLoad()
    
    view.backgroundColor = .black
    
    tableView.delegate = self
    tableView.dataSource = self
    tableView.tableFooterView = UIView()
    tableView.backgroundColor = .darkGray
    tableView.register(PriceCell.self, forCellReuseIdentifier: "cellId") //register your cell
    view.addSubview(tableView)
    tableView.frame = view.bounds
    //this is the call to fetch objects
    fetchObjects(urlString: "https://sochain.com//api/v2/get_price/DOGE/USD")
}

之后写给你 json 解码器函数:

fileprivate func fetchObjects(urlString: String) {
    
    guard let url = URL(string: urlString) else { return }
    
    URLSession.shared.dataTask(with: url) { data, response, err in
        guard let data = data, err == nil else { return }
        
        do {
            let jsonData = try JSONDecoder().decode(DataPrice.self, from: data)
            self.productList = jsonData.data?.prices ?? [] //append data to your productLis array
            
            DispatchQueue.main.async {
                self.tableView.reloadData()
            }
             
        } catch let jsonErr {
            print("failed to decode json:", jsonErr)
        }
        
    }.resume() // don't forget
}

设置您的表格视图:

func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
    return productList.count
}

func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
    let cell = tableView.dequeueReusableCell(withIdentifier: "cellId", for: indexPath) as! PriceCell
    let json = productList[indexPath.row]
    cell.labelPrice.text = "Price: \(json.price_base ?? "")"
    cell.labelPriceBase.text = "Price Base: \(json.price ?? "")"
    cell.labelExchange.text = "Exchang: \(json.exchange ?? "")"
    cell.labelTime.text = "Time: \(json.time ?? 0)"
    
    return cell
}

func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat {
    return 144
}

这是您的 tableView 自定义单元格:

class PriceCell: UITableViewCell {

let labelPrice: UILabel = {
    let label = UILabel()
    label.text = ""
    label.font = .systemFont(ofSize: 16, weight: .regular)
    label.numberOfLines = 0
    label.textColor = .black
    
    return label
}()

let labelPriceBase: UILabel = {
    let label = UILabel()
    label.text = ""
    label.font = .systemFont(ofSize: 16, weight: .regular)
    label.numberOfLines = 0
    label.textColor = .black
    
    return label
}()

let labelExchange: UILabel = {
    let label = UILabel()
    label.text = ""
    label.font = .systemFont(ofSize: 16, weight: .regular)
    label.numberOfLines = 0
    label.textColor = .black
    
    return label
}()

let labelTime: UILabel = {
    let label = UILabel()
    label.text = ""
    label.font = .systemFont(ofSize: 16, weight: .regular)
    label.numberOfLines = 0
    label.textColor = .black
    
    return label
}()

override init(style: UITableViewCell.CellStyle, reuseIdentifier: String?) {
    super.init(style: style, reuseIdentifier: reuseIdentifier)
    
    contentView.backgroundColor = .white
    let stackView = UIStackView(arrangedSubviews: [labelPrice, labelPriceBase, labelExchange, labelTime])
    stackView.axis = .vertical
    stackView.distribution = .fillEqually
    stackView.spacing = 8
    stackView.translatesAutoresizingMaskIntoConstraints = false
    
    contentView.addSubview(stackView)
    stackView.topAnchor.constraint(equalTo: contentView.topAnchor).isActive = true
    stackView.bottomAnchor.constraint(equalTo: contentView.bottomAnchor).isActive = true
    stackView.leadingAnchor.constraint(equalTo: contentView.leadingAnchor, constant: 20).isActive = true
    stackView.trailingAnchor.constraint(equalTo: contentView.trailingAnchor, constant: -20).isActive = true
    
}

required init?(coder: NSCoder) {
    fatalError("init(coder:) has not been implemented")
 }
}

这是结果: