0

I'm writing an app that pulls data from the Timezonedb API to get a list of available timezones:

https://timezonedb.com/references/list-time-zone

I'm trying to parse the zoneName which is currently formatted as "Europe/Andorra". My question is how do I split the JSON string to just display city name i.e "Andorra" in a tableview?

Here's the response I'm getting back:

{
"status":"OK",
"message":"",
"zones":[
    {
        "countryCode":"AD",
        "countryName":"Andorra",
        "zoneName":"Europe\/Andorra",
        "gmtOffset":7200,
        "timestamp":1464453737
    },
    {
        "countryCode":"AE",
        "countryName":"United Arab Emirates",
        "zoneName":"Asia\/Dubai",
        "gmtOffset":14400,
        "timestamp":1464460937
    },
    {"
        countryCode":"AF",
        "countryName":"Afghanistan",
        "zoneName":"Asia\/Kabul",
        "gmtOffset":16200,
        "timestamp":1464462737
    }]}

Here's my code:

Model:

struct TimeZones: Codable {
let status, message: String?
let zones: [Zone]?
}

struct Zone: Codable {
let countryCode, countryName, zoneName: String?
let gmtOffset, timestamp: Int?
}

Here's the networking code:

var cities: [Zone] = []

   func getAvailableTimeZones() {

    let config = URLSessionConfiguration.default
    let session = URLSession(configuration: config)
    let url = Bundle.main.url(forResource: "data", withExtension: "json")!

    let task = session.dataTask(with: url) { data, response, error in

        // Check for errors
        guard error == nil else {
            print ("error: \(error!)")
            return
        }
        // Check that data has been returned
        guard let content = data else {
            print("No data")
            return
        }

        do {
            let decoder = JSONDecoder()
            decoder.keyDecodingStrategy = .convertFromSnakeCase
            let timeZones = try decoder.decode(TimeZones.self, from: content)

            if let zones = timeZones.zones {
                self.cities.append(contentsOf: zones)
            }

        } catch let err {
            print("Err", err)
        }
    }
    // Execute the HTTP request
    task.resume()
}

TableViewController:

override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
    let cell = tableView.dequeueReusableCell(withIdentifier: "searchResultsCell", for: indexPath)

    cell.textLabel?.text = cities[indexPath.row].zoneName

    return cell
}

Any help appreciated. Thank you.

Booysenberry
  • 223
  • 3
  • 16
  • 1
    If it's always the same format (i.e. continent/country name) just do this: let string = "Europe/Andorra" let str = string.split(separator: "/") let cityName = str[1] – lajosdeme Dec 10 '19 at 19:02
  • 5
    Does this answer your question? [Split a String into an array in Swift?](https://stackoverflow.com/questions/25678373/split-a-string-into-an-array-in-swift) – lajosdeme Dec 10 '19 at 19:04

2 Answers2

3

A solution is to add CodingKeys and a computed property.

And there is no reason to declare the struct members as optional

struct TimeZones: Decodable {
   let status, message: String 
   let zones: [Zone]
}

struct Zone: Decodable {
    let countryCode, countryName, zoneName: String
    let gmtOffset, timestamp: Int

    private enum CodingKeys: String, CodingKey { case countryCode, countryName, zoneName, gmtOffset, timestamp}

    lazy var zoneCountry : String = {
       return zoneName.components(separatedBy: "/").last!
    }()
}

and use it

cell.textLabel?.text = cities[indexPath.row].zoneCountry
vadian
  • 274,689
  • 30
  • 353
  • 361
0

To get the desired output with the minimal change you just have to update cellForRowAt() method like:

let zoneName = cities[indexPath.row].zoneName.components(separatedBy: "/").last ?? ""
cell.textLabel?.text = zoneName
Najeeb ur Rehman
  • 403
  • 4
  • 11