需要从 open api 获取国家名称

Posted

技术标签:

【中文标题】需要从 open api 获取国家名称【英文标题】:need to get the country name from 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)!..

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

【问题讨论】:

How to access a Particular Value from a struct的可能重复 【参考方案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
 

【讨论】:

以上是关于需要从 open api 获取国家名称的主要内容,如果未能解决你的问题,请参考以下文章

从国家代码中获取国家名称

使用 pycountry 从国家/地区获取大陆名称

从wikimapia Api获取国家和城市信息

从 Symfony2/Twig 中的 2 位国家代码获取翻译的国家名称?

如何从纬度和经度获取国家名称

如何从Drupal Commerce中的国家/地区代码获取国家/地区名称