Swift 5 从 https 请求解析 Json 数据

问题描述

我正在尝试解析 json 并获取 "price" 值。我如何解析 json 以在 swift 5 编程语言中实现这一点。我尝试过 codable struct,但我一直得到空结果。

JSON

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

迅捷

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()

}

解决方法

使用 .convertFromSnakeCase 作为您的 JSONDecoder

   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,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,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
}

设置您的 tableView:

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")
 }
}

结果如下:

enter image description here

相关问答

Selenium Web驱动程序和Java。元素在(x,y)点处不可单击。其...
Python-如何使用点“。” 访问字典成员?
Java 字符串是不可变的。到底是什么意思?
Java中的“ final”关键字如何工作?(我仍然可以修改对象。...
“loop:”在Java代码中。这是什么,为什么要编译?
java.lang.ClassNotFoundException:sun.jdbc.odbc.JdbcOdbc...