简体   繁体   English

JSON转换成自定义对象的数组(Swift)

[英]JSON into array of custom objects (Swift)

I have a JSON and i need it to convert it into array of objects. 我有一个JSON,我需要将其转换为对象数组。 This is my JSON ( short version of it ) 这是我的JSON(它的简短版本)

[
{
    "categoryID": 5,
    "categoryDescription": "Trips",
    "groupID": 43,
    "groupDescription": "USA",
    "groupImage": "e613c87a-4dab-4929-90cf-2b584fdf0399.jpg",
    "subgroupDescription": "2 days",
    "subgroupPrice": "200"
},
{
   "categoryID": 5,
    "categoryDescription": "Trips",
    "groupID": 43,
    "groupDescription": "USA",
    "groupImage": "e613c87a-4dab-4929-90cf-2b584fdf0399.jpg",
    "subgroupDescription": "5 days",
    "subgroupPrice": "500"
},
{
    "categoryID": 5,
    "categoryDescription": "Trips",
    "groupID": 33,
    "groupDescription": "Mexico",
    "groupImage": "e613c87a-4dab-4929-90cf-2b584fdf0399.jpg",
    "subgroupDescription": "3 days",
    "subgroupPrice": "400"
},
{
    "categoryID": 5,
    "categoryDescription": "Trips",
    "groupID": 33,
    "groupDescription": "Mexico",
    "groupImage": "e613c87a-4dab-4929-90cf-2b584fdf0399.jpg",
    "subgroupDescription": "1 days",
    "subgroupPrice": "150"
},
{
    "categoryID": 3,
    "categoryDescription": "Hotels",
    "groupID": 22,
    "groupDescription": "My Hotel",
    "groupImage": "e613c87a-4dab-4929-90cf-2b584fdf0399.jpg",
    "subgroupDescription": "1 night",
    "subgroupPrice": "50"
},
{
    "categoryID": 3,
    "categoryDescription": "Hotels",
    "groupID": 10,
    "groupDescription": "Your Hotel",
    "groupImage": "e613c87a-4dab-4929-90cf-2b584fdf0399.jpg",
    "subgroupDescription": "2 nights",
    "subgroupPrice": "150"
}]

and i need to make a custom objects like this : (How can I create such this object in Swift 4?) 并且我需要制作一个这样的自定义对象:(如何在Swift 4中创建这样的对象?)

在此处输入图片说明

In JSON we have categoryID and groupID i need to filter arrays based on them, for example i need to have only one object with categoryID 5. and i need to have only one object with groupID : 43. but i need all subgroups. 在JSON中,我们有categoryIDgroupID,我需要基于它们过滤数组,例如,我只需要一个具有categoryID 5的对象,而我只需要一个具有groupID的对象:43。但是我需要所有子组。 This is the structure of my objects: ( I don't know if i'm on the right path ) 这是我的对象的结构:(我不知道我走的路是否正确)

struct Categories {
var categoryID: NSNumber
var categoryDescription: String
var groups : [Groups]}

struct Groups {
var geoupID: NSNumber
var geoupDescription: String
var groupImage: String
var subGroups : [Subgroups] }

struct Subgroups {
var subgroupPrice: NSNumber
var subgroupDescription: String }

How can I filter it in best way ? 如何以最佳方式过滤它?

As for how to make the structures, simply use Decodable and either name the fields according to what you expect in the JSON, or use CodingKeys to specify the names. 至于如何制作结构,只需使用Decodable并根据您在JSON中的期望命名字段,或使用CodingKeys指定名称。 For example: 例如:

struct MyStruct: Decodable {
    let categoryID: Int
    let categoryDescription: String
    let groupID: Int
    // …
}

Then you can decode your results as [MyStruct] using JSONDecoder . 然后,您可以使用JSONDecoder将结果解码为[MyStruct]

Now, the real problem seems to be that you want to have a different structure internally than what you receive as JSON, including constraints like "only one of each categoryID ". 现在,真正的问题似乎是您希望内部拥有与JSON接收的不同的结构,包括诸如“每个categoryID只有一个”之categoryID约束。 Probably the most straightforward way is to then iterate over the decoded results and copy the contents into different structures. 然后,最直接的方法可能是遍历解码结果并将内容复制到不同的结构中。

Instead of arrays (eg, var groups: [Groups] ) you could have a dictionary with groupID as keys to enforce there being only one of each id, for example: 代替数组(例如, var groups: [Groups] ),您可以使用具有groupID作为键的字典来强制每个ID中只有一个,例如:

guard let results = try? jsonDecoder.decode([MyStruct].self, from: json) else { return }
var categories = [Int: Category]()
for result in results {
    // fetch existing category or make a new one
    var category = categories[result.categoryID, default: Category(id: result.categoryID, description: result.categoryDescription)]

    // fetch existing group in category or make a new one
    var group = category.groups[result.groupID, default: Group(id: result.groupID, description: result.groupDescription, image: result.groupImage)]

    // append subgroup (always new since there is no id)
    let subgroup = Subgroup(description: result.subgroupDescription, price: result.subgroupPrice)
    group.subgroups.append(subgroup)

    // "save"
    category.groups[result.groupID] = group
    categories[result.categoryID] = category
}

Country Json 国家杰森

{
      ID = 2;
      Image = "";
      Name = "";
      City =     (
        {
          ID = 74;
          Name = "";
          ParentID = 2;
      },
        {
          ID = 79;
          Image = "";
          Name = Other;
          ParentID = 2;
      }
      );
    },
    {
      ID = 31;
      Image = "";
      Name = "";
      City =     (
        {
          ID = 99;
          Name = "";
          ParentID = 31;
      },
        {
          ID = 100;
          Name = "";
          ParentID = 31;
      });
    }

My Class 我的课

class Country: Codable {

    var id: String?
    var image: String?
    var name: String?
    var cityList: [City]?

    enum CodingKeys: String, CodingKey {
      case id = "ID"
      case image = "Image"
      case name = "Name"
      case city = "City"
    }

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

      id = try? values.decode(String.self, forKey: .id)
      image = try? values.decode(String.self, forKey: .image)
      name = try? values.decode(String.self, forKey: .name)
      cityList = try? values.decode([City].self, forKey: .city)
    }

    func encode(to encoder: Encoder) throws {
      var container = encoder.container(keyedBy: CodingKeys.self)
      try container.encode(id, forKey: .id)
      try container.encode(image, forKey: .image)
      try container.encode(name, forKey: .name)
      try container.encode(cityList, forKey: .city)
    }

  }

  class City: Codable {

    var id: String?
    var name: String?
    var parentId: String?

    enum CodingKeys: String, CodingKey {
      case id = "ID"
      case name = "Name"
      case parentId = "ParentID"
    }

    required init(from decoder: Decoder) throws {
      let values = try decoder.container(keyedBy: CodingKeys.self)
      id = try? values.decode(String.self, forKey: .id)
      name = try? values.decode(String.self, forKey: .name)
      parentId = try? values.decode(String.self, forKey: .parentId)
    }

    func encode(to encoder: Encoder) throws {
      var container = encoder.container(keyedBy: CodingKeys.self)
      try container.encode(id, forKey: .id)
      try container.encode(name, forKey: .name)
      try container.encode(parentId, forKey: .parentId)
    }

  }

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM