RDowns RDowns - 1 month ago 9
Swift Question

What is the different between these two rows in the JSON array which means one isn't being recognised?

I have an API call that retrieves an array from my database featuring

countries
,
divisions
,
teams
.

This output shows the format of the JSON when received in Swift (
teams
not shown in example:


Optional(["countries": <__NSArrayI 0x6180001f6500>(
{
id = 1;
name = Denmark;
},
{
id = 2;
name = Belgium;
}
)
, "divisions": <__NSArrayI 0x7fc8a34455a0>(
{
Name = "ALKA SUPERLIGA";
"country_id" = 1;
id = 1;
},
{
Name = "PRO LEAGUE";
"country_id" = 2;
id = 2;
}


I am using the following function in swift to sort the
countries
and
divisions
into different string arrays to then use in an UITableView.

override func viewDidAppear(_ animated: Bool) {
let myUrl = URL(string: "http://www.quasisquest.uk/KeepScore/getTeams.php?");
var request = URLRequest(url:myUrl!);
request.httpMethod = "POST";
let postString = "";

request.httpBody = postString.data(using: String.Encoding.utf8);

let task = URLSession.shared.dataTask(with: request) { (data: Data?, response: URLResponse?, error: Error?) in

DispatchQueue.main.async
{

if error != nil {
print("error=\(error)")
return
}

do{
let json = try JSONSerialization.jsonObject(with: data!, options: .allowFragments) as? [String:AnyObject]
print (json)

if let arr = json?["countries"] as? [[String:String]] {
self.countryId = arr.flatMap { $0["id"]!}
self.countries = arr.flatMap { $0["name"]!}
self.teamsTableView.reloadData()
print ("Countries: ",self.countries)
}

if let arr = json?["divisions"] as? [[String:String]] {

self.divisions = arr.flatMap { $0["Name"]!}
self.divisionId = arr.flatMap { $0["id"]!}
self.teamsTableView.reloadData()
print ("Divisions: ",self.divisions)
}



} catch{
print(error)
}
}
}
task.resume()
//membersTableView.reloadData()

}


The
print ("Countries: ",self.countries)
outputs as expected, below:


Countries: [Optional("Denmark"), Optional("Belgium")


But the
print ("Divisions: ",self.divisions)
doesn't even run. So there must be something wrong with that IF command, yet I am using the same code as what I used from the 'countries' section.

Any ideas?

I have tried replacing
[[String : String]]
with
[[String : String?]]
but this did nothing. I have also tried
[[String : Any]]
but this brought the following error on the arr.flapMap lines:


'(_) -> Any' to expected argument type '(Dictionary) -> SegmentOfResult'

Answer

First of all in Swift 3 the common unspecified type is Any rather than AnyObject

In the given JSON

  • The root object is [String:Any]
  • The value for divisions is [[String:Any]] because it contains String and <null> types.

The value <null> will be replaced with n/a

if let json = try JSONSerialization.jsonObject(with: data!, options: .allowFragments) as? [String:Any] {
       print (json)

       if let arr = json["countries"] as? [[String:String]] {
          self.countryId = arr.flatMap { $0["id"]!}
          self.countries = arr.flatMap { $0["name"]!}
          self.teamsTableView.reloadData()
          print ("Countries: ",self.countries)
       }

       if let arr = json["divisions"] as? [[String:Any]] {
          self.divisions = arr.flatMap { $0["Name"] as? String ?? "n/a" }
          self.divisionId = arr.flatMap { $0["id"] as? String }
          self.teamsTableView.reloadData()
          print ("Divisions: ",self.divisions)
       }
} 

Notes:

Do not use multiple arrays as data source in conjunction with flatMap, this is pretty error-prone, use a custom struct instead.

A POST request is not needed, GET (a data task passing the url) is sufficient.

Comments