使用encodable-decodable从api中的数组进行解析

时间:2019-03-25 09:37:41

标签: ios json swift

我有一个看起来像这样的api响应片段...

{
  "status": "OK",
  "predictions": [
    {
      "description": "Hilton Head Island, SC, USA",
      "id": "67bd386c0fb3d4f77bf3cb283a6d75565ea11732",
      "matched_substrings": [
        {
          "length": 6,
          "offset": 0
        }
      ],
      "place_id": "ChIJrRnTjtx5_IgRPSii63qm5Sw",
      "reference": "ChIJrRnTjtx5_IgRPSii63qm5Sw",
      "structured_formatting": {
        "main_text": "Hilton Head Island",
        "main_text_matched_substrings": [
          {
            "length": 6,
            "offset": 0
          }
        ],
        "secondary_text": "SC, USA"
      },
      "types": [
        "locality",
        "political",
        "geocode"
      ]
    }
}

由此,我需要main_textsecondary_text。为此,我做了一个像这样的模型课...

class FilteredLocations: Codable {

  var locationDetails: [String: Any]

  enum CodingKeys: String, CodingKey {
    case locationDetails = "structured_formatting"
  }

  required init(from decoder: Decoder) throws {
    let values = try decoder.container(keyedBy: CodingKeys.self)
    locationDetails = try? values.decode([String: Any].self, forKey: .locationDetails)//ERROR HERE
  }

  func encode(to encoder: Encoder) throws {
    var container = encoder.container(keyedBy: CodingKeys.self)
    try container.encode(locationDetails, forKey: .locationDetails)//ERROR HERE
  }
}

但是在上面的代码中,在提到的//ERROR HERE处抛出了错误Reference to member 'locationDetails' cannot be resolved without a contextual type

我做错了什么...?

编辑1 :这就是我解析数据的方式。

 if let productService = result?["predictions"] as? [[String: Any]] ,
          let jsonData = try? JSONSerialization.data(withJSONObject: productService as Any, options: []) {
          do {
            let filteredLocations = try? JSONDecoder().decode(FilteredLocations.self, from: jsonData)

            self.tableview.reloadData()
          } catch {
            print("error \(error.localizedDescription)")
          }
        }

编辑2 google api响应:

{
   "predictions" : [
      {
         "description" : "Hilton Head Island, SC, USA",
         "id" : "gfhgj3hgjhsgvh4hj4hgj424hfjhjha11732",
         "matched_substrings" : [
            {
               "length" : 6,
               "offset" : 0
            }
         ],
         "place_id" : "dfgegregergrgrergergewrer5Sw",
         "reference" : "bvEQfdgetehetheterbgcbng5Sw",
         "structured_formatting" : {
            "main_text" : "Hilton Head Island",
            "main_text_matched_substrings" : [
               {
                  "length" : 6,
                  "offset" : 0
               }
            ],
            "secondary_text" : "SC, USA"
         },
         "terms" : [
            {
               "offset" : 0,
               "value" : "Hilton Head Island"
            },
            {
               "offset" : 20,
               "value" : "SC"
            },
            {
               "offset" : 24,
               "value" : "USA"
            }
         ],
         "types" : [ "locality", "political", "geocode" ]
      }
   ],
   "status" : "OK"
}

编辑3 我如何进行api调用并获取要解析的数据。

WebServiceClient.shared.getNearbyLocationsSearchList(withParameters: parameters, inputText: searchText) { [weak self] (isSuccess, result) in
  guard let `self` = self else { return }
  if isSuccess, result != nil {
    print("Successfully fetched nearby locations!")

    if let productService = result?["predictions"] as? [[String: Any]] ,
      let jsonData = try? JSONSerialization.data(withJSONObject: productService as Any, options: []) {
      do {
        let filteredLocations = try? JSONDecoder().decode([FilteredLocations].self, from: jsonData)

      } catch {
        print("error \(error.localizedDescription)")
      }
    }        
  }

编辑4 ,这是调用网络服务后从api上获得的result

{
    description = "Houston, TX, USA";
    id = 25faf0a7ef1056b980f3a19237cfa8e295668123;
    "matched_substrings" =     (
                {
            length = 1;
            offset = 0;
        }
    );
    "place_id" = ChIJAYWNSLS4QIYROwVl894CDco;
    reference = ChIJAYWNSLS4QIYROwVl894CDco;
    "structured_formatting" =     {
        "main_text" = Houston;
        "main_text_matched_substrings" =         (
                        {
                length = 1;
                offset = 0;
            }
        );
        "secondary_text" = "TX, USA";
    };
    terms =     (
                {
            offset = 0;
            value = Houston;
        },
                {
            offset = 9;
            value = TX;
        },
                {
            offset = 13;
            value = USA;
        }
    );
    types =     (
        locality,
        political,
        geocode
    );
}

编辑5

enter image description here

1 个答案:

答案 0 :(得分:1)

如果您引用的是此JSON(有效,不同于您所附加的JSON ...)

{
    "status": "OK",
    "predictions": [{
        "description": "Hilton Head Island, SC, USA",
        "id": "67bd386c0fb3d4f77bf3cb283a6d75565ea11732",
        "matched_substrings": [{
            "length": 6,
            "offset": 0
        }],
        "place_id": "ChIJrRnTjtx5_IgRPSii63qm5Sw",
        "reference": "ChIJrRnTjtx5_IgRPSii63qm5Sw",
        "structured_formatting": {
            "main_text": "Hilton Head Island",
            "main_text_matched_substrings": [{
                "length": 6,
                "offset": 0
            }],
            "secondary_text": "SC, USA"
        },
        "types": [
            "locality",
            "political",
            "geocode"
        ]
    }]
}

然后这是如何为所有JSON数据创建结构的方法:

struct FilteredLocations: Codable {
    let status: String
    let predictions: [Prediction]
}

struct Prediction: Codable {
    let description, id: String
    let matchedSubstrings: [MatchedSubstring]
    let placeID, reference: String
    let structuredFormatting: StructuredFormatting
    let types: [String]

    enum CodingKeys: String, CodingKey {
        case description, id
        case matchedSubstrings = "matched_substrings"
        case placeID = "place_id"
        case reference
        case structuredFormatting = "structured_formatting"
        case types
    }
}

struct MatchedSubstring: Codable {
    let length, offset: Int
}

struct StructuredFormatting: Codable {
    let mainText: String
    let mainTextMatchedSubstrings: [MatchedSubstring]
    let secondaryText: String

    enum CodingKeys: String, CodingKey {
        case mainText = "main_text"
        case mainTextMatchedSubstrings = "main_text_matched_substrings"
        case secondaryText = "secondary_text"
    }
}

然后像这样解码:

let filteredLocations = try? JSONDecoder().decode(FilteredLocations.self, from: jsonData)

要编码数据:

let encoder = JSONEncoder()
encoder.outputFormatting = .prettyPrinted

do {
    let jsonData = try encoder.encode(filteredLocations)

    if let jsonString = String(data: jsonData, encoding: .utf8) {
        print(jsonString)
        // Prints out the JSON you just encoded.
    }
} catch {
    print(error.localizedDescription)
}

要获取主要文本和辅助文本,

main: filteredLocations.structuredFormatting.mainText
secondary: filteredLocations.structuredFormatting.secondaryText

我希望这个答案对您有用!

编辑1:

尝试以下代码:

WebServiceClient.shared.getNearbyLocationsSearchList(withParameters: parameters, inputText: searchText) { [weak self] (isSuccess, result) in
  guard let `self` = self else { return }
  if isSuccess, result != nil {
    print("Successfully fetched nearby locations!")

    if let jsonData = try? JSONSerialization.data(withJSONObject: result as Any, options: []) {
      do {
        let filteredLocations = try? JSONDecoder().decode([FilteredLocations].self, from: jsonData)

      } catch {
        print("error \(error.localizedDescription)")
      }
    }        
  }