Home > Net >  Thread 1 : signal SIGABRT error on API usage
Thread 1 : signal SIGABRT error on API usage

Time:07-25

I'm new to swift and currently I'm trying to learn how to use API. But I'm getting this error at my viewcontroller and appdelegate.

Here is my code:

import UIKit

class ViewController: UIViewController {
    
    @IBOutlet weak var myLabel: UILabel!
    var fetchedCountry = [Country]()

    override func viewDidLoad() {
        super.viewDidLoad()
        parseData()
    }


    func parseData(){
        let url = "https://restcountries.com/v3.1/all"
        var request = URLRequest(url: URL(string: url)!)
        request.httpMethod = "GET"
        
        let configuration = URLSessionConfiguration.default
        let session = URLSession(configuration: configuration, delegate: nil, delegateQueue: OperationQueue.main)
        
        let task = session.dataTask(with: request) { data, response, error in
            if error != nil{
                print("error!")
            }
            else{
                do{
                    
                    let fetchData = try JSONSerialization.jsonObject(with: data!, options: .mutableLeaves) as! NSArray
                    
                    
                    DispatchQueue.main.async {
                    for eachFetchedCountry in fetchData{
                        let eachCountry = eachFetchedCountry as! [String: Any]
                        let country = eachCountry["name"] as! String //Thread 1 : signal SIGABRT
                        let capital = eachCountry["capital"] as! String
                        
                        self.fetchedCountry.append(Country(country: country, capital: capital))
                    }
                    print(self.fetchedCountry)
                    print("aa")
                }
                }
                catch{
                    print("do try error")
                    
                }
            }
        }
        task.resume()
    }

class Country {
    var country : String
    var capital : String
    
    init(country: String, capital: String){
        self.capital = capital
        self.country = country
    }
}

I'm also getting this error:

Output: Could not cast value of type '__NSDictionaryI' (0x1db05bb30) to 'NSString' (0x1db05b2b0).

How can I solve this issue?

CodePudding user response:

The best solution here would be to create structs implementing the Codable protocol, that represent the answer you are getting from this API. You don´t need to decode every property but only those you are interested in.

struct CountryTransferable: Codable{
    let name: Name
    let capital: [String]?
}

struct Name: Codable {
    let common, official: String
    let nativeName: [String: Translation]?
}

struct Translation: Codable {
    let official, common: String
}

Then create another init for you Country (I´d choose a struct over a class) that can take the TransferableCountry as an argument:

struct Country {
    var country : String
    var capital : String
    
    init(country: String, capital: String){
        self.capital = capital
        self.country = country
    }
    
    init(_ transferable: CountryTransferable){
        // You can choose every other of the name or capital properties. These are just for example.
        self.country = transferable.name.official
        // As not every country seem to have a capital this can be nil
        self.capital = transferable.capital?.first ?? "unknown"
    }
}

And decoding would work this way:

if error != nil {
  print("error!")
}
else {
  do {
    // Decode to your defined transferable struct as array and map it to the Country type
    let countries = try JSONDecoder().decode([CountryTransferable].self, from: data).map{Country($0)}

    DispatchQueue.main.async {
          // assign the new values
          self.fetchedCountry = countries
      }
      print(self.fetchedCountry)
      print("aa")
    }
  } catch {
    // print something meaningfull here
    print(error)

  }
}
  • Related