When using this:
let cities: [[String : String]] = {
guard let URL = Bundle.main.url(forResource: "cities", withExtension: "plist") else {
return []
}
return NSArray(contentsOf: URL) as! [[String : String]]
}()
from this:
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<array>
<dict>
<key>name</key>
<string>Allentown, PA</string>
<key>icao</key>
<string>ABE</string>
</dict>
....
</array>
</plist>
it is easy to later access the values using:
// inside tableView(_ cellForRowAt:)
city = cities[indexPath.row]
cell.icaoLabel?.text = city["icao"]
cell.nameLabel?.text = city["name"]
However, when declaring:
class City {
var icao: String
var name: String
// is this init() necessary?
init(icao: String, name: String) {
self.icao = icao
self.name = name
}
}
and:
let cities: [City] = {
guard let URL = Bundle.main.url(forResource: "cities", withExtension: "plist") else {
return []
}
// ** No longer works
return NSArray(contentsOf: URL) as! [City]
// ** Doesn't work either
return NSArray(contentsOf: URL)
}()
Ultimately, I want to use:
// inside tableView(_cellForRowAt:)
city = cities[indexPath.row]
cell icaoLabel?.text = city.icao
cell nameLabel?.text = city.name
How is this accomplished? Can the plist be imported this way?
Edit to the City class:
class City {
var icao: String?
var name: String?
init(icao: String, name: String) {
self.icao = icao
self.name = name
}
static func loadCities() -> [City] {
guard let URL = Bundle.main.url(forResource: "cities", withExtension: "plist") else {
return []
}
let tempCities = NSArray(contentsOf: URL) as! [[String : String]]
// now, create the desired cities array
var cities = [City]()
for city in tempCities {
guard let icaoTemp = city["icao"], let nameTemp = city["name"] else {
break
}
cities.append(City(icao: icaoTemp, name: nameTemp))
}
return cities
}
}
accessing the values:
let city: City = cities[indexPath.row]
cell.icaoLabel?.text = city.icao
cell.airportNameLabel?.text = city.name
No, there is no built in way to convert the plist data directly into an array of your City objects. You need to do that yourself.
Load the plist just as you are now. Then iterate that array getting each little dictionary. Either extract the two values and create a City instance using your current init or add a new init that takes a dictionary and let the City class set itself up.
In the end you build a new array with each of those City instances you create as you iterate the original plist array.
It probably makes sense to wrap all of that functionality up into a Cities class that knows how to read and write the plist file and work with the list of City instances. You may end up adding other appropriate logic to the class to work with the list of cities.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With