使用 JSONDecoder 和可编码协议的网络

Posted

技术标签:

【中文标题】使用 JSONDecoder 和可编码协议的网络【英文标题】:Networking using JSONDecoder & codable protocol 【发布时间】:2019-05-23 12:40:47 【问题描述】:

我想知道我做错了什么。我正在尝试了解如何使用 JSONDecoder 使用 urlsession 和可编码协议。当我使用 JSONDecoder 时,我收到以下错误消息:

keyNotFound(CodingKeys(stringValue: "name", intValue: nil), 我的响应包含 ''name'' 。但是当我使用 JSONSerialization 时,我可以打印响应。如果有人可以解释一下。

使用 JSONDecoder 的代码

struct Business:Codable 
    let name: String
    enum CodingKeys: String, CodingKey 
        case name = "name"
    

    init(from decoder: Decoder) throws 
        let value = try decoder.container(keyedBy: CodingKeys.self)
        self.name = try value.decode(String.self, forKey:CodingKeys.name)
    


let task = session.dataTask(with: request)  (data, response, error) in
    if let response = response as? HTTPURLResponse 
        print(response)
     else
        print("error")
    

    guard let data = data else return

    do 
        let business = try JSONDecoder().decode(Business.self, from: data)
        print(business.name)
     catch 
        print("Error parsing JSON: \(error)")
    


task.resume()

使用 JSONSerialization 的代码

struct Business: Decodable 
    let name: String
    let displayAddress: String
    let categories: String
    let imageUrl : String

    init(json: [String:Any]) 
        name = json["name"] as? String ?? ""
        displayAddress = json["location"] as? String ?? ""
        categories = json["categories"] as? String ?? ""
        imageUrl = json["image_url"] as? String ?? ""
    


let task = session.dataTask(with: request)  (data, response, error) in
    if let response = response as? HTTPURLResponse 
        print(response)
     else
        print("error")
    

    guard let data = data else return

    do 
        if let myjson = try JSONSerialization.jsonObject(with: data, options: .mutableContainers) as? Dictionary<String,Any> 
            print(myjson)
        
     catch 
        print("Error parsing ")
    


task.resume()

回应

["region": 
    center =     
        latitude = "43.67428196976998";
        longitude = "-79.39682006835938";
    ;
, "businesses": <__NSArrayM 0x60000211cff0>(

    alias = "pai-northern-thai-kitchen-toronto-5";
    categories =     (
                
            alias = thai;
            title = Thai;
        
    );
    coordinates =     
        latitude = "43.647866";
        longitude = "-79.38864150000001";
    ;
    "display_phone" = "+1 416-901-4724";
    distance = "3010.095870925626";
    id = "r_BrIgzYcwo1NAuG9dLbpg";
    "image_url" = "https://s3-media3.fl.yelpcdn.com/bphoto/t-g4d_vCAgZH_6pCqjaYWQ/o.jpg";
    "is_closed" = 0;
    location =     
        address1 = "18 Duncan Street";
        address2 = "";
        address3 = "";
        city = Toronto;
        country = CA;
        "display_address" =         (
            "18 Duncan Street",
            "Toronto, ON M5H 3G8",
            Canada
        );
        state = ON;
        "zip_code" = "M5H 3G8";
    ;
    name = "Pai Northern Thai Kitchen";
    phone = "+14169014724";
    price = "$$";
    rating = "4.5";
    "review_count" = 2405;
    transactions =     (
    );
    url = "https://www.yelp.com/biz/pai-northern-thai-kitchen-toronto-5?adjust_creative=A4ydpSOHv8wBNquTDeh0DQ&utm_campaign=yelp_api_v3&utm_medium=api_v3_business_search&utm_source=A4ydpSOHv8wBNquTDeh0DQ";
,

【问题讨论】:

您的回复是调试器格式,难以阅读。将print(String(data: data, encoding: .utf8) ?? "???") 放在guard let data = ... 之后会得到什么? 这很明显。您的name 位于路径businesses[index].name,但您正试图仅解码路径name。你实际上并没有展示你是如何使用JSONSerialization解码的。 我收到了字符串格式的回复。 【参考方案1】:

Business 不是 JSON 中的根数据对象。你需要这样的东西:

struct Business: Codable 
    let name: String


struct RootObject: Codable 
    let businesses: [Business]



let rootObject = try JSONDecoder().decode(RootObject.self, from: data)
print(rootObject.businesses.first?.name)

【讨论】:

我试过你的解决方案,我收到错误:keyNotFound

以上是关于使用 JSONDecoder 和可编码协议的网络的主要内容,如果未能解决你的问题,请参考以下文章

使用泛型/可编码 w/ API 响应 204 NO CONTENT

Swift 项目中涉及到 JSONDecoder,网络请求,泛型协议式编程的一些记录和想法

使协议可编码并将其存储在数组中

MODBUS协议整理——功能码简述

如果字典为空,则可编码问题

带有可编码数组的 swift 5 抽象网络响应