在Swift中解码不同类型的JSON数组

时间:2018-02-12 14:58:52

标签: json swift decodable

我正在尝试解码以下JSON对象

{
    "result":[
             {
             "rank":12,
             "user":{ 
                     "name":"bob","age":12 
                    } 
             }, 
             {
             "1":[ 
                  {
                    "name":"bob","age":12
                  },
                  {
                   "name":"tim","age":13
                  }, 
                  {
                   "name":"tony","age":12
                  }, 
                  {
                   "name":"greg","age":13
                  } 
                 ] 
            } 
           ] 
}

struct userObject {    var name:String    var age:Int }

基本上是一个具有两种不同对象类型的JSON数组

{ "rank":12, "user": {userObject} }

和a “1”:[userObjects]

的数组
struct data: Decodable {
   rank: Int
   user: user
   1:    [user]  <-- this is one area Im stuck
}

提前致谢

3 个答案:

答案 0 :(得分:2)

只是为了好玩:

首先,您需要用户的结构以及result数组中第一个和第二个字典的表示。密钥"1"已映射到one

struct User : Decodable {
    let name : String
    let age : Int
}

struct FirstDictionary : Decodable {
    let rank : Int
    let user : User
}

struct SecondDictionary : Decodable {
    let one : [User]

    private enum CodingKeys: String, CodingKey { case one = "1" }
}

现在是棘手的部分:

  • 首先获取根容器。
  • 获取result的容器为nestedUnkeyedContainer,因为该对象是一个数组。
  • 解码第一个字典并复制值。
  • 解码第二个字典并复制值。

    struct UserData: Decodable {
    
        let rank : Int
        let user : User
        let oneUsers : [User]
    
       private enum CodingKeys: String, CodingKey { case result }
    
        init(from decoder: Decoder) throws {
            let container = try decoder.container(keyedBy: CodingKeys.self)
            var arrayContainer = try container.nestedUnkeyedContainer(forKey: .result)
            let firstDictionary = try arrayContainer.decode(FirstDictionary.self)
            rank = firstDictionary.rank
            user = firstDictionary.user
            let secondDictionary = try arrayContainer.decode(SecondDictionary.self)
            oneUsers = secondDictionary.one
        }
    }
    

如果此代码优于传统的手册 JSONSerialization是另一个问题。

答案 1 :(得分:0)

如果你给出了JSON格式,那么你几乎没有运气,因为你很可能不得不将你的数组解析为[Any],这显然不是很有用。另一方面,如果你能够修改JSON的格式,你应该从另一个方向开始。定义所需的Swift对象并使用JSONEncoder.encode(...)对其进行编码,以便快速确定JSON的外观,以便以尽可能类型的方式对其进行解析。

这种方法很容易将JSON处理代码减半,因为您的Web服务协议最终会更好地构建。这可能会改善整个系统的结构,因为它将产生更稳定的通信协议。

可悲的是,当事情变得混乱时,这种方法并不总是可行的。根据您的示例,您将能够将代码解析为

let st = """
{
    "result":[
        {
            "rank":12,
            "user":{
                "name":"bob",
                "age":12
            }
        },
        {
            "1":[
                {
                    "name":"bob","age":12
                },
                {
                    "name":"tim","age":13
                },
                {
                    "name":"tony","age":12
                },
                {
                    "name":"greg","age":13
                }
            ]
        }
    ]
}
"""

let jsonData1 = st.data(using: .utf8)!
let arbitrary = try JSONSerialization.jsonObject(with: jsonData1, options: .mutableContainers)

这将允许您使用

中的一堆演员表来访问您的数据
let dict = arbitrary as! NSDictionary
print(dict["result"])

你明白了。不太有用,因为您非常希望使用{/ 1}}协议,如

Codable

不幸的是,这不起作用,因为 struct ArrayRes : Codable { let result : [[String:Any]] } let decoder1 = JSONDecoder() do { let addrRes = try decoder.decode(ArrayRes.self, from: jsonData1) print(addrRes) } catch { print("error on decode: \(error.localizedDescription)") } 不是Any,原因有点明显。

我希望你能够改变你的JSON协议,因为当前的JSON协议将成为许多凌乱代码的根本原因。

答案 2 :(得分:-1)

你必须像这样反序列化Json

INSERT

然后你需要向程序显示如何设置这样的数据。

from pymysql.cursors import *
import pymysql
from collections import OrderedDict
import datetime

class OrderedDictCursor(DictCursorMixin, Cursor):
    dict_type = OrderedDict

conn1 = pymysql.connect(host='127.0.0.1',
                       port=3306,
                       user='root',
                       passwd='pwd',
                       db='test',
                       charset='utf8',
                       use_unicode=True,
                       autocommit=True)

cursor1 = conn1.cursor(OrderedDictCursor)
odict = OrderedDict([(u'id', 374), (u'title', u'Chapter 4'), (u'intro_list', u'Objective:\r\n\r\n* Exit any mininet launch done earlier using \u201cmn \u2013c\u201d\r\n'), (u'solution', u'%%beginpanel%%\r\n\r\n## 1. net\r\n\r\n```\r\nmn -c\r\n```\r\n\r\n \u201cCTRL+C\u201d \r\n\r\n%%endpanel%%\r\n'), (u'created', datetime.datetime(2017, 3, 9, 7, 58, 7)), (u'modified', datetime.datetime(2017, 8, 28, 4, 58, 15))])
cols = odict.keys()
vals = odict.values()
cursor1.execute("INSERT INTO %s (%s) VALUES (%s)" % ("test1", ",".join(cols), (str(vals)[1:-1])))

然后根据你有多少jsonobjects你应该循环遍历它们,当你完成它时,你应该将项目发送到一个func,如果你在一个对象中将它们放在你自己的类中。 ps当你在显示程序如何设置Json对象时,你可以通过项目对象作为字典,因为我在第二个codebit中显示你。