GVKun编程网logo

如何使用Swift的Decodable解析一个仅知道或关心几个字段的任意JSON字符串?

10

对于如何使用Swift的Decodable解析一个仅知道或关心几个字段的任意JSON字符串?感兴趣的读者,本文将会是一篇不错的选择,并为您提供关于Codable:实现在swift中像js那样使用JSO

对于如何使用Swift的Decodable解析一个仅知道或关心几个字段的任意JSON字符串?感兴趣的读者,本文将会是一篇不错的选择,并为您提供关于Codable: 实现在 swift 中像 js 那样使用 JSON、curl get获取到一个utf-8 json字符串,用json_decode解析说格式不对。、ios – 如何使用SwiftyJSON将字符串转换为JSON、ios – 如何在Swift 4中为JSON编写一个Decodable,其中键是动态的?的有用信息。

本文目录一览:

如何使用Swift的Decodable解析一个仅知道或关心几个字段的任意JSON字符串?

如何使用Swift的Decodable解析一个仅知道或关心几个字段的任意JSON字符串?

新的Swift“ Decoder”类听起来像是解析JSON数据的好方法,但是我发现的所有示例都使用众所周知的,定义明确的’struct’来实现。

在我的情况下,我正在查询返回巨大JSON字符串的任意网站,并且我只关心几个(深度嵌套)字段,所以我不想花所有时间定义一个“结构”来获取在他们。

甚至可以通过“解码器”来做到这一点吗?如果是这样,该如何处理?

答案1

小编典典

这个问题似乎是基于对“可分解的东西”如何工作的误解。为方便起见,Decodable愿意在幕后进行一些自动代码生成,以便您 可以
定义结构或结构嵌套,并仅解码整个JSON。但是您 不需要 利用它来解码JSON。

  • 无需为不需要的“字段”定义结构属性。如果JSON字典包含100个键,而您的对应结构仅包含一个属性,则没有问题;该密钥将被获取,没有其他密钥。

  • 关于“深度嵌套”部分,您应该花很多时间来编写简单的嵌套结构,这些结构执行潜水才能到达您真正关心的字典。但是,即使您不想这样做,也可以编写一个实现的init(from:)摘要,然后取出所需的值。

换句话说,如果您认为Decodable 主要
由的实现组成init(from:),并学习编写所需的代码,则将看到可以用几行简单的代码行来解析此JSON。

举例来说,这是一个深层嵌套的信息的JSON草图,在每个层次上我们都忽略了很多额外的信息:

{  "ignore": true,  "outer1": {    "ignore": true,    "outer2": {      "ignore": true,      "outer3": {        "name": "matt",        "ignore": true      }    }  }}

我想做的是定义一个非常简单的struct Person,它仅由深层嵌套组成name

struct Person : Decodable {    let name : String}

我可以做到的!为此,我自己实现了Decodable,提供了一个“
hoover”的CodingKey采用者结构和的实现init(from:),这样(这看起来像很多工作,但不是,因为AnyCodingKey实现是样板化,复制并粘贴的)从这里开始,init(coder:)实现只是几行易于编写的代码):

    struct Person : Decodable {        let name : String        struct AnyCodingKey : CodingKey {            var stringValue: String            var intValue: Int?            init(_ codingKey: CodingKey) {                self.stringValue = codingKey.stringValue                self.intValue = codingKey.intValue            }            init(stringValue: String) {                self.stringValue = stringValue                self.intValue = nil            }            init(intValue: Int) {                self.stringValue = String(intValue)                self.intValue = intValue            }        }        init(from decoder: Decoder) throws {            var con = try! decoder.container(keyedBy: AnyCodingKey.self)            con = try! con.nestedContainer(keyedBy: AnyCodingKey.self, forKey: AnyCodingKey(stringValue:"outer1"))            con = try! con.nestedContainer(keyedBy: AnyCodingKey.self, forKey: AnyCodingKey(stringValue:"outer2"))            con = try! con.nestedContainer(keyedBy: AnyCodingKey.self, forKey: AnyCodingKey(stringValue:"outer3"))            let name = try! con.decode(String.self, forKey: AnyCodingKey(stringValue:"name"))            self.name = name        }    }

当我想深入研究JSON并获取name信息时,这很简单:

let person = try! JSONDecoder().decode(Person.self, from: json)

结果是一个带有namevalue 的Person对象"matt"。注意,我不必添加任何ignore键,也不需要嵌套结构。

Codable: 实现在 swift 中像 js 那样使用 JSON

Codable: 实现在 swift 中像 js 那样使用 JSON

Codable: 实现在 swift 中像 js 那样使用 JSON

官方文档,关于 Codable 实现:https://developer.apple.com/documentation/foundation/archives_and_serialization/encoding_and_decoding_custom_types

js 一样,iOS 11 之后,swift 也可以方便的使用 json 来传递数据了。

要想使用 json, 你操作的类需要实现 Codable 接口
Foundation 中的所有类都已经实现了 Cadable,所以如果你的实体中没有自定义的一些数据类型,都可以直接使用 JSON

js 一样,swift 中的 json 也有:

  • JSONEncoder 将数据转成 json 数据
  • JOSNDecoderjson 数据,转为可用的你需要的数据类型

看下面的 PlayGround 例子便知道如何使用了

由对象转字符串

import Foundation

struct Person: Codable {
    var name: String
    var age: Int
    var intro: String
}

let kyle = Person(name: "Kyle", age: 29, intro: "A web developer")
let tina = Person(name: "Tina", age: 26, intro: "A teacher for English")
let persons = [kyle, tina]

// Encode
let encoder = JSONEncoder()
encoder.outputFormatting = .prettyPrinted // setup formatter
let jsonData = try encoder.encode(persons)
print(String(data: jsonData, encoding: .utf8)!)


// Decode
let decoder = JSONDecoder()
// 注意 decode() 中的第一个参数
let people = try decoder.decode(Array<Person>.self, from: jsonData)
print(people[0].name)

输出如下:

[
  {
    "name" : "Kyle",
    "age" : 29,
    "intro" : "A web developer"
  },
  {
    "name" : "Tina",
    "age" : 26,
    "intro" : "A teacher for English"
  }
]
Kyle

由字符串转对象

import Foundation

struct Person: Codable {
    let name: String
    let age: Int
    let intro: String
}

let jsonString = """
[
    {
        "name": "Kyle",
        "age": 27,
        "intro": "A font-end enginer",
        "location": "Jinan"
    },
    {
        "name": "Tina",
        "age": 26,
        "intro": "A UI enginer",
        "location": "Jinan"
    }
]
"""

// 1. 先从字符串转为 Data
let jsonData = jsonString.data(using: .utf8)!

// 2. 再用 Data 转成对应的对象
let decoder = JSONDecoder()
let persons = try decoder.decode(Array<Person>.self, from: jsonData)

print(type(of: persons[0]))

cadable.png

对象名与 json 名不一致时

有些时候,对象声明中的变量名跟json中的键名不一致,如 nameEn 在 json 中需要为 json_en
只需要在对象声明中用 CodingKeys 声明要转成的字符串即可,如下:不需要转的就不需要写 = 后面的东西了

//
//  Person.swift
//  CustomisedViews
//
//  Created by Kyle on 2020/3/2.
//  Copyright © 2020 KyleBing. All rights reserved.
//

import Foundation

struct Person: Codable {
    var id: String
    var name: String
    var nameEn: String
    var nickName: String
    var perk: String
    var motto: String
    var health: String
    var sanity: String
    var hunger: String
    var version: String
    var pic: String
    
        enum CodingKeys: String, CodingKey {
        case nameEn = "name_en"
        case nickName = "nick_name"
        // 下面这些变量名不需要变,就只写 case 就可以了
        // 要把对象中的变量全部遍历出来,不然会出错
            case id
            case name
            case perk
            case motto
            case health
            case sanity
            case hunger
            case version
            case pic
        }
}

curl get获取到一个utf-8 json字符串,用json_decode解析说格式不对。

curl get获取到一个utf-8 json字符串,用json_decode解析说格式不对。

$ch = curl_init();//初始化curl curl_setopt($ch,curlopt_url,$url); curl_setopt($ch,curlopt_returntransfer,1); curl_setopt($ch, curlopt_header, 0); $data=curl_exec($ch); print_r(json_decode($data)); echo json_last_error_msg();//提示符号错误
登录后复制


用浏览器输入$url,确实反馈回来一个json数据。怎么弄?bom去头又怎么弄。好像去不掉。


回复讨论(解决方案)

.....
$data=curl_exec($ch);
echo base64_encode($data);
贴出结果

PGh0bWw+DQo8aGVhZD48dGl0bGU+MzAxIE1vdmVkIFBlcm1hbmVudGx5PC90aXRsZT48L2hlYWQ+DQo8Ym9keSBiZ2NvbG9yPSJ3aGl0ZSI+DQo8Y2VudGVyPjxoMT4zMDEgTW92ZWQgUGVybWFuZW50bHk8L2gxPjwvY2VudGVyPg0KPGhyPjxjZW50ZXI+bmdpbng8L2NlbnRlcj4NCjwvYm9keT4NCjwvaHRtbD4NCg==

加上
curl_setopt($ch, CURLOPT_FOLLOWLOCATION, true);

ios – 如何使用SwiftyJSON将字符串转换为JSON

ios – 如何使用SwiftyJSON将字符串转换为JSON

要转换的字符串:

[{“description”:“Hi”,“id”:2,“img”:“hi.png”},{“description”:“pet”,“id”:10,“img”:“pet.png “},{”description“:”Hello!:D“,”id“:12,”img“:”hello.png“}]

转换字符串的代码:

var json = JSON(stringLiteral:stringJSON)

该字符串转换为JSON,当我尝试计算这个JSON里面有多少个块(预期答案= 3)时,我得到0.

打印(json.count)

控制台输出:0

我失踪了什么帮助非常感激.

解决方法

实际上,在SwifyJSON中有一个内置函数叫做解析
/**
 Create a JSON from JSON string
- parameter string: normal json string like '{"a":"b"}'

- returns: The created JSON
*/
public static func parse(string:String) -> JSON {
    return string.dataUsingEncoding(NSUTF8StringEncoding)
        .flatMap({JSON(data: $0)}) ?? JSON(NSNull())
}

var json = JSON.parse(stringJSON)

它现在改成了

var json = JSON.init(parseString:stringJSON)

ios – 如何在Swift 4中为JSON编写一个Decodable,其中键是动态的?

ios – 如何在Swift 4中为JSON编写一个Decodable,其中键是动态的?

我有这样的 JSON.

我需要使用Swift 4在我的iOS应用程序中创建相应的Decodable结构.

{
    "cherry": {
        "filling": "cherries and love","goodWithIceCream": true,"madeBy": "my grandmother"
     },"odd": {
         "filling": "rocks,I think?","goodWithIceCream": false,"madeBy": "a child,maybe?"
     },"super-chocolate": {
         "flavor": "german chocolate with chocolate shavings","forABirthday": false,"madeBy": "the charming bakery up the street"
     }
}

需要有关制作可解码结构的帮助.如何提及樱桃,奇数和超巧克力等未知密钥.

解决方法

您需要的是在定义CodingKeys时发挥创意.让我们将响应称为FoodList和内部结构FoodDetail.您尚未定义FoodDetail的属性,因此我假设这些键都是可选的.

struct FoodDetail: Decodable {
    var name: String!
    var filling: String?
    var goodWithIceCream: Bool?
    var madeBy: String?
    var flavor: String?
    var forABirthday: Bool?

    enum CodingKeys: String,CodingKey {
        case filling,goodWithIceCream,madeBy,flavor,forABirthday
    }
}

struct FoodList: Decodable {
    var foodNames: [String]
    var foodDetails: [FoodDetail]

    // This is a dummy struct as we only use it to satisfy the container(keyedBy: ) function
    private struct CodingKeys: CodingKey {
        var intValue: Int?
        var stringValue: String

        init?(intValue: Int) { self.intValue = intValue; self.stringValue = "" }
        init?(stringValue: String) { self.stringValue = stringValue }
    }

    init(from decoder: Decoder) throws {
        self.foodNames = [String]()
        self.foodDetails = [FoodDetail]()

        let container = try decoder.container(keyedBy: CodingKeys.self)
        for key in container.allKeys {
            let foodName = key.stringValue
            var foodDetail = try container.decode(FoodDetail.self,forKey: key)
            foodDetail.name = foodName

            self.foodNames.append(foodName)
            self.foodDetails.append(foodDetail)
        }
    }
}


// Usage
let list = try! JSONDecoder().decode(FoodList.self,from: jsonData)

今天关于如何使用Swift的Decodable解析一个仅知道或关心几个字段的任意JSON字符串?的讲解已经结束,谢谢您的阅读,如果想了解更多关于Codable: 实现在 swift 中像 js 那样使用 JSON、curl get获取到一个utf-8 json字符串,用json_decode解析说格式不对。、ios – 如何使用SwiftyJSON将字符串转换为JSON、ios – 如何在Swift 4中为JSON编写一个Decodable,其中键是动态的?的相关知识,请在本站搜索。

本文标签: