【问题标题】:need to get the country name from open api需要从 open api 获取国家名称
【发布时间】:2019-01-10 12:50:16
【问题描述】:

需要从下面的 api 调用中获取国家名称:

https://restcountries.eu/rest/v1/all

我的代码:

var arrRes = []
func getCountry() {
    let Url: String = "https://restcountries.eu/rest/v1/all"   
    Alamofire.request(Url).responseJSON { (responseData) -> Void in
        do {
            if let datas = responseData.result.value {
                let data  = (datas as AnyObject).data(using: .utf8)!
                let parseData = try JSONSerialization.jsonObject(with: data, options: [])
                for country in parseData {
                    if let name = country["name"] as? String {
                        print(name)
                    }
                }
            }
        }
        catch let error as NSError {
            print(error)
        }
    }
}

这里出现错误:'Any' is not convertible to 'AnyObject' 在下面的行 let data = (datas as AnyObject).data(using: .utf8)!..

我只需要获取名称并附加到我的数组。还有其他想法或解决方案来实现吗?

【问题讨论】:

标签: ios arrays json swift xcode


【解决方案1】:

用这个替换do catch语句块。

do {
    if let countries = responseData.result.value as? [[String: Any]] {
        for country in countries {
            if let name = country["name"] as? String {
                print(name)
            }
        }
    }
}
catch let error as NSError {
    print(error)
}

【讨论】:

  • Cannot invoke 'jsonObject' with an argument list of type '(with: Any, options: [Any])' on `let parseData = try JSONSerialization.jsonObject(with: datas, options: [])。我也试过了。。那个时候也是同样的错误
  • 您不需要let error as NSError 部分。只需} catch { print(error) }
  • 感谢@rmaddy 的提示。
【解决方案2】:

试试这个,它对我来说很好用。

let urlStr = "https://restcountries.eu/rest/v1/all"
let setFinalURl = urlStr.addingPercentEncoding (withAllowedCharacters: .urlQueryAllowed)!
var request = URLRequest(url: URL(string: setFinalURl)!)
request.httpMethod = HTTPMethod.get.rawValue

Alamofire.request(request).responseJSON
    { (responseObject) -> Void in

        if responseObject.result.isSuccess
        {
            print(responseObject.result.value!)

            if "\(String(describing: responseObject.response!.statusCode))" == "200"
            {
                let result = responseObject.result.value! as AnyObject

                let countryNamesArr = result.value(forKey: "name") as! NSArray
                print(countryNamesArr)
            }
            else
            {
                // handle error
            }
        }
        if responseObject.result.isFailure
        {
            let error : Error = responseObject.result.error!
            print(error.localizedDescription)
        }
}

【讨论】:

    【解决方案3】:

    你可以试试

    struct Root: Codable {
        let name: String  
    }
    

    func getCountry() {
    
        let urlStr = "https://restcountries.eu/rest/v1/all"
        Alamofire.request(urlStr).responseData { (data) in
    
            do {
                 guard let data = data.data else { return }
                 let res  = try JSONDecoder().decode([Root].self,from:data)
                 print(res)
            }
            catch {
                print(error)
            }
        }
    }
    

    【讨论】:

    • 再次无法将“__NSArrayI”(0x1fa903a70)类型的值转换为“NSData”(0x1fa901dd8)
    • @david 如果您需要 Codable 的数据,则无需做出 responseJson 做 reponseData
    【解决方案4】:

    删除这一行

    let data = (datas as AnyObject).data(using: .utf8)!

    并且在可选绑定中只需分配data,因为valueData? 类型,从可选绑定中你会得到Data

    if let data = responseData.result.value
    

    然后不要忘记将您的 json 转换为数组 [String:Any]

    ...jsonObject(with: data, options: []) as? [[String:Any]]
    

    ...那么不要忘记解开这个数组,否则你将无法在每个循环中遍历它


    还要注意,既然有Codable,你应该使用它而不是JSONSerialization。然后您可以使用 JSONDecoder 将您的 json 解码为您自己的符合协议 Decodable 的模型。

    【讨论】:

    • 有效答案。我建议尽量避免使用as!,为了安全起见,您可以使用as? ;)
    【解决方案5】:

    作为一种简单的方法,您可以像这样实现getCountry()

    func getCountry() {
        let url: String = "https://restcountries.eu/rest/v1/all"
        Alamofire.request(url).responseJSON { response in
            if let resultValue = response.result.value, let countryObjects = resultValue as? [[String: Any]] {
                let countryNames = countryObjects.compactMap { $0["name"] as? String }
                print(countryNames)
            }
        }
    }
    

    此时,不需要使用JSONSerialization来获取国名;根据 API 响应,responseData.result.value 是一个国家(字典)数组,每个字典都有一个“名称”值,您应该将响应 映射 到一个字符串数组。 countryNames 应该包含您要查找的内容。

    使用compactMap 的好处是避免使用任何nil 名称,因此countryNames 应该是[String] 而不是[String?]


    但是,如果您认为需要将整个响应对象转换为自定义对象(而不是字典),我强烈建议您遵循使用 Decodable 的方法。

    【讨论】:

      【解决方案6】:

      我的代码,对我来说效果很好。

      斯威夫特 5

       public func getCountry(completion: @escaping ([String]) -> ()) {
                  let url: String = "https://restcountries.eu/rest/v1/all"
                  AF.request(url).responseJSON { (responseData) -> Void in
                      do {
                          guard let data = responseData.data else { return }
                          let res  = try JSONDecoder().decode([CountryName].self,from:data)
                          completion(self.getCountryName(countryName: res))
                      }
                      catch {
                          print(error)
                      }
                  }
              }
      
       struct CountryName: Codable {
         let name: String
       }
      
       private func getCountryName(countryName:[CountryName]) -> [String]{
            var country:[String]  = []
            for index in 0...countryName.count - 1{
                 country.append(countryName[index].name)
            }
          return country
       }
      

      【讨论】:

        猜你喜欢
        • 2016-06-11
        • 1970-01-01
        • 1970-01-01
        • 2021-10-13
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2016-11-27
        • 1970-01-01
        相关资源
        最近更新 更多