json swift4如何设置结构?

json swift4如何设置结构?,json,swift,swift4,codable,decodable,Json,Swift,Swift4,Codable,Decodable,我想从http资源解析json(它是我的路由器,所以http是必需的) 在我设置了Info.plistApp Security Transport后,我通过 第一次尝试: let sphDataAddress = "http://speedport.ip/data/status.json" let url = URL(string: sphDataAddress)! let jsonData = try! Data(contentsOf: url) // ! is just for testin

我想从http资源解析json(它是我的路由器,所以http是必需的)

在我设置了
Info.plist
App Security Transport
后,我通过 第一次尝试:

let sphDataAddress = "http://speedport.ip/data/status.json"
let url = URL(string: sphDataAddress)!
let jsonData = try! Data(contentsOf: url) // ! is just for testing reason and will be in real app by guard let 
print("data \(jsonData)") // shows that the received Data are 5077bytes


struct User {

    let vartype: String
    let varid: String
    let varvalue: Company

    init?(dict: [String: Any]) {
        guard
             let vartype = dict["vartype-data"] as? String,
            let varid = dict["valid-data"] as? String,
            let varvalueDict = dict["company"] as? [String: Any],
            let varvalue = Company(dict: varvalueDict)
            else {
                return nil
        }

         self.vartype = vartype
        self.varid = varid
         self.varvalue = varvalue
    }


    struct Company {
        let vartype: String
        let varid: String
        let varvalue: String

        init?(dict: [String: Any]) {
            guard
                let vartype = dict["vartype-sub"] as? String,
                let varid = dict["varid-sub"] as? String,
                let varvalue = dict["varvalue-Sub"] as? String else {
                    return nil
            }

            self.vartype = vartype
            self.varid = varid
            self.varvalue = varvalue
        }
    }
}

if let json = try? JSONSerialization.jsonObject(with: jsonData, options: []) {
   if let jsonArray = json as? [[String: Any]] {
       let users = jsonArray.flatMap { $0.map { $0} }
       let zun = users.count

       print(users, zun)

   }
}
第二次尝试: 我也试过了,但没有成功://我把它放进查看负载只是为了测试它

 struct RouterData: Decodable {

let vartype: String?
let varid: String?
let varvalue: String?
}
override func viewDidLoad() {
    super.viewDidLoad()

    let jsonUrlString = "http://speedport.ip/data/status.json"
    guard let url = URL(string: jsonUrlString) else { return }

    URLSession.shared.dataTask(with: url) { (data, response, err) in
        //perhaps check err checked by print(response) 
        //also perhaps check response status 200 OK

        guard let data = data else { return }

        do {
            let courses = try JSONDecoder().decode([RouterData].self, from: data)
            print(courses)

        } catch let jsonErr {
            print("Error serializing json:", jsonErr)
        }  
    }.resume()
}

控制台中的错误:

类型不匹配(Swift.String、Swift.DecodingError.Context(编码路径: [Foundation.(\u JSONKey in _12768CA107A31EF2DCE034FD75B541C9)(stringValue:“索引25”,intValue:可选(25)),JsonParseSwift4.RouterData。(在 _DD16AFBB8A755D282DC27E60A66FDC03).varvalue],debugDescription:“应解码字符串,但找到了数组。”, 参考误差:零)

这是从源(路由器)提交的(完整)json结构

从路由器提交的数据包括:


JSON只是一个片段,我想展示的是,
varvalue
一次是一个字符串,一次是带有子数据的
[]
,但与
var
相同。

假设这是您要粘贴的JSON结构:

[
  {
    "varid": "dsl_downstream",
    "vartype": "value",
    "varvalue": 11111
  },
  {
    "varid": "adddect",
    "vartype": "template",
    "varvalue": [
      {
        "varid": "id",
        "vartype": "value",
        "varvalue": "some_value"
      }
    ]
  }
]
下面是一个可能的解决方案:

// let jsonData = "...".data(using: .utf8)!

enum Either<A,B> where A: Decodable, B: Decodable {
    case left(A)
    case right(B)
}

struct RouterData: Decodable {
    let type: String
    let id: String
    let value: Either<String,[RouterData]>

    enum CodingKeys: String, CodingKey {
      case type  = "vartype"
      case id    = "varid"
      case value = "varvalue"
    }

    init(from decoder: Decoder) throws {
        let container = try decoder.container(keyedBy: CodingKeys.self)

        type = try container.decode(String.self, forKey: .type)
        id = try container.decode(String.self, forKey: .id)

        if let elementValue = try? container.decode(String.self, forKey: .value) {
            value = .left(elementValue)
        } else if let elementValue = try? container.decode(Int.self, forKey: .value) {
            value = .left(String(elementValue))
        } else {
            let childData = try container.decode([RouterData].self, forKey: .value)
            value = .right(childData)
        }
    }
}

let decoded = try JSONDecoder().decode([RouterData].self, from: jsonData)
print(decoded)
//让jsonData=“…”。数据(使用:.utf8)!
枚举其中A:可解码,B:可解码{
案例左(A)
案例权利(B)
}
结构路由数据:可解码{
let类型:String
let id:String
让值:要么
枚举编码键:字符串,编码键{
case type=“vartype”
案例id=“varid”
case value=“varvalue”
}
init(来自解码器:解码器)抛出{
let container=try decoder.container(keyedBy:CodingKeys.self)
type=try container.decode(String.self,forKey:.type)
id=try container.decode(String.self,forKey:.id)
如果let elementValue=try?container.decode(String.self,forKey:.value){
value=.left(elementValue)
}如果let elementValue=try?container.decode(Int.self,forKey:.value),则为else{
value=.left(字符串(elementValue))
}否则{
let childData=try container.decode([RouterData].self,forKey:.value)
值=.right(childData)
}
}
}
let decoded=尝试JSONDecoder().decode([RouterData].self,发件人:jsonData)
打印(解码)

您的代码似乎比需要的更复杂。使用Swift 4进行JSON解码非常简单。你能将你的数据模型和完整的JSON发布到你的问题中吗?请发布原始JSON,你发布的内容是无效的。据我所知,你在varvalue中设置了一个字符串和一个数组,并用enum“other”捕获它。并再次检查if语句elementValue。2个问题。第一,你不会在swift 3中也这样做吗?第二,对我来说,swift 4在这种特殊情况下没有任何好处,对吗?swift 4中引入了Codable,你说得对。所以我的错误是没有将枚举设置为“other”,让它逐个遍历每个键。这是因为解码只能自动处理int和string,而不能处理数组。我只是想弄明白我的思想错误在哪里。如果你看了这段视频,它看起来很简单,甚至不用init就可以完成。默认情况下,Decodable可以处理几乎任何swift类型,包括序列。这个箱子很特别,因为它是多类型的variable@nathan,我们如何访问
varvalue
,它是类型数组(在第二个对象中)
decoded[1]。value
// let jsonData = "...".data(using: .utf8)!

enum Either<A,B> where A: Decodable, B: Decodable {
    case left(A)
    case right(B)
}

struct RouterData: Decodable {
    let type: String
    let id: String
    let value: Either<String,[RouterData]>

    enum CodingKeys: String, CodingKey {
      case type  = "vartype"
      case id    = "varid"
      case value = "varvalue"
    }

    init(from decoder: Decoder) throws {
        let container = try decoder.container(keyedBy: CodingKeys.self)

        type = try container.decode(String.self, forKey: .type)
        id = try container.decode(String.self, forKey: .id)

        if let elementValue = try? container.decode(String.self, forKey: .value) {
            value = .left(elementValue)
        } else if let elementValue = try? container.decode(Int.self, forKey: .value) {
            value = .left(String(elementValue))
        } else {
            let childData = try container.decode([RouterData].self, forKey: .value)
            value = .right(childData)
        }
    }
}

let decoded = try JSONDecoder().decode([RouterData].self, from: jsonData)
print(decoded)