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

标签 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 谷歌 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 的结果..

{
    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

最佳答案

如果您指的是这个 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)")
      }
    }        
  }

关于ios - 使用 encodable-decodable 从 api 中的数组解析,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/55334864/

相关文章:

json - Golang Json 解压缩到包含接口(interface){}的结构

javascript - 将输入值插入 JSON 数组

ios - 如何调用 touchesBegan 函数?

ios - 无法在 UILabel、Swift 中换行文本

ios - Alamofire 在解包 Optional 值时意外发现 nil

iphone - NavigationController 未加载 View

c++ - 在 Qt 中使用 QJsonDocument 解析嵌套的 JSON

ios - 显示从 url 到 Collection View Swift 单元格的 3 张图像

iphone - iOS:UIImageView 示例代码

订阅的 iOS 应用程序总是被拒绝