david
david

Reputation: 666

need to get the country name from open api

Needs to get country name from below api call :

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

My code :

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)
        }
    }
}

getting error here : 'Any' is not convertible to 'AnyObject' on below line let data = (datas as AnyObject).data(using: .utf8)!..

I need to get only name and append to my array.Any other idea or solution to achieve that ?

Upvotes: 0

Views: 4366

Answers (6)

Omer
Omer

Reputation: 882

My code, its working well for me.

Swift 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
 }

Upvotes: 0

Saravanan
Saravanan

Reputation: 123

Try this, its working fine for me.

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)
        }
}

Upvotes: 2

Ahmad F
Ahmad F

Reputation: 31645

As a simple approach, you could implement getCountry() like this:

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)
        }
    }
}

At this point, there is no need to use JSONSerialization to get the country names; According to the API response, responseData.result.value is an array of countries (dictionaries), each dictionary has a "name" value, what you should do is to map the response to an array of string. countryNames should contains what are you looking for.

The benefit of using compactMap is to avoid any nil name, so countryNames should be [String] instead of [String?].


However, if you believe that you would need to transform the whole response objects into a custom objects (instead of dictionaries), I would highly recommend to follow the approach of using Decodable.

Upvotes: 0

Robert Dresler
Robert Dresler

Reputation: 11150

Just remove this line

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

and in optional binding just assign data, since value is of type Data?, from optional binding you get Data

if let data = responseData.result.value

then don't forget to downcast your json to array [String:Any]

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

... then don't forget to unwrap this array or you wouldn't be able to iterate through it in for each loop


Also note that since there is Codable, you should use it instead of JSONSerialization. Then you can decode your json using JSONDecoder to your own model which conforms to protocol Decodable.

Upvotes: 1

Shehata Gamal
Shehata Gamal

Reputation: 100503

You can try

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)
        }
    }
}

Upvotes: 1

Sateesh Yemireddi
Sateesh Yemireddi

Reputation: 4399

Replace do catch block of statement with this.

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)
}

Upvotes: 2

Related Questions