Swift 4 JSON可解码,具有多维和多类型数组,可读取大量数据

时间:2019-07-09 04:58:19

标签: json swift4 decodable

有人可以帮助我解码来自大量数据库的SQL查询结果吗?我还没有找到任何提示...

那里有很多示例,但是对于像这样针对流入数据库的SQL查询这样的结构,什么都无法解码...

{
    "results": [
        {
            "statement_id": 0,
            "series": [
                {
                    "name": "XiaomiMiSensors",
                    "columns": [
                        "time",
                        "battery",
                        "collectorip",
                        "collectormac",
                        "conductivity",
                        "cputmp",
                        "firmwareversion",
                        "light",
                        "mac",
                        "moisture",
                        "sensorname",
                        "temperature"
                    ],
                    "values": [
                        [
                            "2019-06-23T11:16:52Z",
                            23,
                            "192.168.178.81",
                            "B8:27:EB:0A:47:12",
                            1434,
                            66.604,
                            "3.1.9",
                            7670,
                            "C4:7C:8D:65:FA:95",
                            52,
                            "Plumeria",
                            23.6
                        ],
                        [
                            "2019-06-23T12:19:56Z",
                            36,
                            "192.168.178.81",
                            "B8:27:EB:0A:47:12",
                            1401,
                            66.604,
                            "3.1.9",
                            10160,
                            "C4:7C:8D:65:FA:95",
                            53,
                            "Plumeria",
                            26.8
                        ]
                    ]
                }
            ]
        }
}

我尝试过这个

struct Response: Decodable {
    var values: [[[IntOrString]]]
}

struct Response1: Decodable {
    var columns: [IntOrString]
}

enum IntOrString: Decodable {


case int(Int)
case string(String)

init(from decoder: Decoder) throws {

    if let string = try? decoder.singleValueContainer().decode(String.self) {
        self = .string(string)
        return
    }

    if let int = try? decoder.singleValueContainer().decode(Int.self) {
        self = .int(int)
        return
    }

    throw IntOrStringError.intOrStringNotFound
}

enum IntOrStringError: Error {
    case intOrStringNotFound
}
}

class ViewController: UIViewController {
override func viewDidLoad() {
    super.viewDidLoad()
    // Do any additional setup after loading the view.


    let data = """
    {
        "series": [
            {
                "name": "XiaomiMiSensors",
                "columns": [
                    "T1", "C2", "d3"
                ],
                "values": [
                    [1, 1, 7, "Azuan Child", "Anak Azuan", "12345", "ACTIVE", "Morning", 7, 12, "2017-11-09 19:45:00"],
                    [28, 1, 0, "Azuan Child2", "Amran", "123456", "ACTIVE", "Evening", 1, 29, "2017-11-09 19:45:00"]
                ]
            }
        ]
    }
    """.data(using: .utf8)!

    if let response = try? JSONDecoder().decode(Response.self, from: data) {
        let values = response.values

        for value in values {
                for intOrString in value {
                    switch intOrString {
                    case .int(let int): print("It's an int: \(int)")
                    case .string(let string): print("It's a string: \(string)")
                    }
                }
        }
    }

    if let response1 = try? JSONDecoder().decode(Response1.self, from: data) {
        let columns = response1.columns

            for intOrString in columns {
                switch intOrString {
                case .int(let int): print("It's an int: \(int)")
                case .string(let string): print("It's a string: \(string)")
                }
        }
    }

}


}

还有这个

import Foundation

struct RawServerResponse {


enum OuterKeys: String, CodingKey {
    case results
}

enum RootKeys: String, CodingKey {
    case id, user, reviewCount = "reviews_count"
}

enum UserKeys: String, CodingKey {
    case userName = "user_name", realInfo = "real_info"
}

enum RealInfoKeys: String, CodingKey {
    case fullName = "full_name"
}

enum ReviewCountKeys: String, CodingKey {
    case count
}

let results: Int
let id: Int
let userName: String
let fullName: String
let reviewCount: Int

}

extension RawServerResponse: Decodable {


init(from decoder: Decoder) throws {
    // results
    let outerContainer = try decoder.container(keyedBy: OuterKeys.self)

    // id
    let container = try decoder.container(keyedBy: RootKeys.self)
    id = try container.decode(Int.self, forKey: .id)

    // userName
    let userContainer = try container.nestedContainer(keyedBy: UserKeys.self, forKey: .user)
    userName = try userContainer.decode(String.self, forKey: .userName)

    // fullName
    let realInfoKeysContainer = try userContainer.nestedContainer(keyedBy: RealInfoKeys.self, forKey: .realInfo)
    fullName = try realInfoKeysContainer.decode(String.self, forKey: .fullName)

    // reviewCount
    var reviewUnkeyedContainer = try container.nestedUnkeyedContainer(forKey: .reviewCount)
    var reviewCountArray = [Int]()
    while !reviewUnkeyedContainer.isAtEnd {
        let reviewCountContainer = try reviewUnkeyedContainer.nestedContainer(keyedBy: ReviewCountKeys.self)
        reviewCountArray.append(try reviewCountContainer.decode(Int.self, forKey: .count))
    }
    guard let reviewCount = reviewCountArray.first else {
        throw DecodingError.dataCorrupted(DecodingError.Context(codingPath: container.codingPath + [RootKeys.reviewCount], debugDescription: "reviews_count cannot be empty"))
    }
    self.reviewCount = reviewCount
}

}
class ViewController: UIViewController {
override func viewDidLoad() {
    super.viewDidLoad()
    // Do any additional setup after loading the view.

let jsonString = """
{
    "results": [
        {
            "id": 1,
            "user": {
                "user_name": "Tester",
                "real_info": {
                    "full_name":"Jon Doe"
                }
            },
            "reviews_count": [
            {
            "count": 4
            }
            ]
       }
    ]
}
"""

let jsonData = jsonString.data(using: .utf8)!
let decoder = JSONDecoder()
let serverResponse = try! decoder.decode(RawServerResponse.self, from: jsonData)
dump(serverResponse)

}

}

但两者显然都无法正常工作...

1 个答案:

答案 0 :(得分:0)

尝试一下:

// MARK: - Response
struct Response: Codable {
    let results: [Result]
}

// MARK: - Result
struct Result: Codable {
    let statementID: Int
    let series: [Series]

    enum CodingKeys: String, CodingKey {
        case statementID = "statement_id"
        case series
    }
}

// MARK: - Series
struct Series: Codable {
    let name: String
    let columns: [String]
    let values: [[Value]]
}

enum Value: Codable {
    case double(Double)
    case string(String)

    init(from decoder: Decoder) throws {
        let container = try decoder.singleValueContainer()
        if let x = try? container.decode(Double.self) {
            self = .double(x)
            return
        }
        if let x = try? container.decode(String.self) {
            self = .string(x)
            return
        }
        throw DecodingError.typeMismatch(Value.self, DecodingError.Context(codingPath: decoder.codingPath, debugDescription: "Wrong type for Value"))
    }

    func encode(to encoder: Encoder) throws {
        var container = encoder.singleValueContainer()
        switch self {
        case .double(let x):
            try container.encode(x)
        case .string(let x):
            try container.encode(x)
        }
    }
}

do {
    let response = try JSONDecoder().decode(Response.self, from: jsonData)
    print(response)
} catch {
    print(error)
}