Swift 4 Decodable-动态类型,键和属性

时间:2018-10-15 06:52:39

标签: json swift decodable

我有一个标准的URL get请求,该请求返回JSON响应。标准的JSON响应是这样写的

//get request for the user
{
"USER":
    {
    "NAME":"myName",
    "ID":10000
    }
}
//get request for the forums
{  
"FORUM":[  
  {  
     "SORT":1,
     "ID":35,
     "TITLE":"Feedback",
     "SECTION":"secion1"
  },
  {  
     "SORT":2,
     "ID":92,
     "TITLE":"Choosing an ISP",
     "SECTION":"secion2"
  },
  {  
     "SORT":3,
     "ID":100,
     "TITLE":"Broadband",
     "SECTION":"section2"
  },
  {  
     "SORT":4,
     "ID":142,
     "TITLE":"“NBN”",
     "SECTION":"section2"
  },
 ]
}
//get request for news
{"NEWS":
  [
    {
      "DATE":"2018-10-13T03:56:06+1000",
      "SOURCE":"smh.com.au",
      "BLURB":"Assistant Treasurer Stuart Robert says he has repaid $37,975 of \"excess usage charges\" in home internet bills footed by taxpayers.",
      "ID":102347,
      "TITLE":"Stuart Robert pays back $38,000 in excessive home internet charges"
    },
    {
      "DATE":"2018-10-12T18:00:38+1000",
      "SOURCE":"itwire.com",
      "BLURB":"The CVC costs set by the NBN Co make it very difficult for ISPs to offer gigabit connections to more than a select band of customers who are willing to sign up in numbers and pay slightly more than other speed tiers, according to one ISP who caters to this type of consumer.",
      "ID":102343,
      "TITLE":"NBN gigabit connections will remain mostly a pipe dream"},
    {
      "DATE":"2018-10-12T09:48:43+1000",
      "SOURCE":"computerworld.com.au",
      "BLURB":"The Department of Home Affairs has rejects calls to include independent judicial oversight of the decision to issue Technical Assistance Notices and Technical Capability Notices as part of proposed legislation intended to tackle police agencies’ inability to access encrypted communications services.",
      "ID":102342,
      "TITLE":"Home Affairs rejects calls for additional safeguards in ‘spyware’ law"
    },
    {
    "DATE":"2018-10-11T12:16:05+1000",
    "SOURCE":"itnews.com.au",
    "BLURB":"NBN Co is hoping to “speed up” building works on the fibre-to-the-curb (FTTC) portion of its network as it tries to make up lost ground.",
    "ID":102334,
    "TITLE":"NBN Co says fibre-to-the-curb build is more complex that it hoped"
    },
  ]
}

我们可以看到,每个请求都有一个顶级JSON对象,有些请求可能包含嵌套字典数组,而有些请求(例如User请求)则没有。

问题

我已经使用Google搜索了几个小时,遇到了dynamic keyshere,但不完全是我的追求。由于类型保持不变。我想要一种可以在运行时识别的通用类型。一种简单的方法是执行switch / if语句,但是我希望能够在无需过多维护和重复代码的情况下使其增大/缩小-每当我提出不同的请求时,我都需要重复执行URLSession块

URLSession.shared.dataTask(with: url) { (data, response, err) in
        guard let dataStr = data else {
            return
        }
        do {

            let json = try JSONSerialization.jsonObject(with: dataStr, options: [.mutableContainers, .allowFragments]) as! [String: Any]
            print("json - \(json)")

            let decoder = JSONDecoder()
            decoder.dateDecodingStrategy = .iso8601
            let root = try decoder.decode(RootUser.self, from: dataStr)// **Identify the Type.self during runtime without conditional statements** 
            print(root)


        } catch let jsonErr {
            print("error serializing json", jsonErr)
        }

        }.resume()

    URLSession.shared.dataTask(with: url) { (data, response, err) in
        //....
            let root = try decoder.decode(RootNews.self, from: dataStr)// **Identify the Type.self during runtime without conditional statements** 
       //...

        }.resume()

    URLSession.shared.dataTask(with: url) { (data, response, err) in
        //....
            let root = try decoder.decode(RootForum.self, from: dataStr)// **Identify the Type.self during runtime without conditional statements** 
       //...

        }.resume()

问题

我想知道如何在不使用条件的情况下将这些请求归为通用方法

更新

基于通用提取功能,我对可接受的答案做了一些扩展。通过将我的结构(RootUser,RootNews)组合成一个结构

struct Base: Decodable {
let news: [News]?
let user: User?

enum CodingKeys: String, CodingKey {
    case news = "NEWS"
    case user = "USER"
}
}

现在,当我调用fetch函数时,我只需要修改URL而不是类型(接受的答案中的RootUser,RootNews或Foo),它将只是Base类型。

1 个答案:

答案 0 :(得分:1)

不确定是否可以回答您的问题,但是可以使您的网络请求对任何Decodable都是通用的。

    // Sample Model to be decoded
    struct Foo: Decodable {
        var id: String
        var name: String
    }

    // Generic function to fetch decodables
    func fetch<T: Decodable>(for url: URL, complete: @escaping (T?) -> Void) {
        URLSession.shared.dataTask(with: url) { (data, response, err) in
            do {
                let model = try JSONDecoder().decode(T.self, from: data!)
                complete(model)
            }
            catch {
                print(error)
                complete(nil)
            }
        }
    }

    // Test
    let request = URL(string: "some://url.com")
    fetch(for: request!) { (model: Foo?) -> Void in
        print("found \(model)")
    }

测试调用者知道所期望的模型,因此可以在运行时推断出Type Foo并正确对其进行解码。