Reputation: 3480
I am trying to build an weather forecast application using Open Weather API and in my forecast class I have following struct type.
struct ForecastWeather {
public private(set) var date: String
public private(set) var weatherDetails: [WeatherInfo]
}
struct WeatherInfo {
public private(set) var weatherImage: String
public private(set) var time: String
public private(set) var weatherType: String
public private(set) var temperature: String
}
I need to use two dimensional array because in my table view there are sections for forecast datas. I am putting objects into var forecastWeathers = [ForecastWeather]()
array.
ForecastWeather(date: "Thursday", weatherDetails: [WeatherForecast.WeatherInfo(weatherImage: "01d", time: "12:00", weatherType: "Clear", temperature: "35.0")])
ForecastWeather(date: "Thursday", weatherDetails: [WeatherForecast.WeatherInfo(weatherImage: "02d", time: "15:00", weatherType: "Clouds", temperature: "31.0")])
ForecastWeather(date: "Thursday", weatherDetails: [WeatherForecast.WeatherInfo(weatherImage: "01n", time: "18:00", weatherType: "Clear", temperature: "21.0")])
ForecastWeather(date: "Friday", weatherDetails: [WeatherForecast.WeatherInfo(weatherImage: "03n", time: "21:00", weatherType: "Clouds", temperature: "16.0")])
ForecastWeather(date: "Friday", weatherDetails: [WeatherForecast.WeatherInfo(weatherImage: "10n", time: "00:00", weatherType: "Rain", temperature: "13.0")])
ForecastWeather(date: "Friday", weatherDetails: [WeatherForecast.WeatherInfo(weatherImage: "10d", time: "03:00", weatherType: "Rain", temperature: "14.0")])
ForecastWeather(date: "Monday", weatherDetails: [WeatherForecast.WeatherInfo(weatherImage: "10d", time: "12:00", weatherType: "Rain", temperature: "19.0")])
ForecastWeather(date: "Monday", weatherDetails: [WeatherForecast.WeatherInfo(weatherImage: "10d", time: "15:00", weatherType: "Rain", temperature: "19.0")])
ForecastWeather(date: "Monday", weatherDetails: [WeatherForecast.WeatherInfo(weatherImage: "03n", time: "18:00", weatherType: "Clouds", temperature: "16.0")])
In my table view and I need to give that sections into it like WeatherService.instance.forecastWeathers[indexPath.section].weatherDetails[indexPath.row]
. It is now giving me an error because I have 3 same Thursday object inside it. How can I map or filter forecastWeathers
array which contains date information only once because I have multiple sections I have tried to use map function but I could not be successful.
Edit here is my API call
let json = JSON(value)
for i in 0..<json["list"].count {
let icon = json["list"][i]["weather"][0]["icon"].stringValue // Image icon
let date = self.convertUnixDate(fromDoubleTo: json["list"][i]["dt"].doubleValue)
let weatherType = json["list"][i]["weather"][0]["main"].stringValue.capitalized
let temperature = "\(self.temperatureConverter(kelvinTo: json["list"][i]["main"]["temp"].doubleValue))"
let time = self.convertTime(timeArr: json["list"][i]["dt_txt"].stringValue)
let forecastObj = ForecastWeather(date: date, weatherDetails: [WeatherInfo(weatherImage: icon, time: time, weatherType: weatherType, temperature: temperature)])
print(forecastObj)
self.forecastWeathers.append(forecastObj)
}
Also there is API result 5 day forecast
Here is my table view delegate methods
func numberOfSections(in tableView: UITableView) -> Int {
return WeatherService.instance.newForecastWeathers.count
}
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return WeatherService.instance.newForecastWeathers[section].date.count
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
guard let cell = forecastTableView.dequeueReusableCell(withIdentifier: cellId) as? ForecastCell else { return ForecastCell() }
cell.configureCell(weatherDetails: WeatherService.instance.newForecastWeathers[indexPath.section].weatherDetails[indexPath.row])
return cell
}
func tableView(_ tableView: UITableView, viewForHeaderInSection section: Int) -> UIView? {
let view = UIView()
view.backgroundColor = .orange
let label = UILabel()
label.text = WeatherService.instance.newForecastWeathers[section].date
label.frame = CGRect(x: 45, y: 5, width: 100, height: 35)
view.addSubview(label)
return view
}
Upvotes: 0
Views: 169
Reputation: 27211
I've fixed some errors and allow weatherDetails
to be public to simplify appending. This is a functional-style. With sorting.
//: Playground - noun: a place where people can play
struct ForecastWeather {
public private(set) var date: String
public var weatherDetails: [WeatherInfo]
public var index: Int {
return ForecastWeather.weekdays[date] ?? 0
}
private static let weekdays: [String: Int] = ["Sunday": 0, "Monday": 1, "Thuesday": 2, "Wednesday": 3, "Thursday": 4, "Friday": 5, "Saturday": 6]
}
struct WeatherInfo {
public private(set) var weatherImage: String
public private(set) var time: String
public private(set) var weatherType: String
public private(set) var temperature: String
}
var forecastWeathers = [ForecastWeather]()
forecastWeathers.append(ForecastWeather(date: "Thursday", weatherDetails: [WeatherInfo(weatherImage: "01d", time: "12:00", weatherType: "Clear", temperature: "35.0")]))
forecastWeathers.append(ForecastWeather(date: "Thursday", weatherDetails: [WeatherInfo(weatherImage: "02d", time: "15:00", weatherType: "Clouds", temperature: "31.0")]))
forecastWeathers.append(ForecastWeather(date: "Thursday", weatherDetails: [WeatherInfo(weatherImage: "01n", time: "18:00", weatherType: "Clear", temperature: "21.0")]))
forecastWeathers.append(ForecastWeather(date: "Friday", weatherDetails: [WeatherInfo(weatherImage: "03n", time: "21:00", weatherType: "Clouds", temperature: "16.0")]))
forecastWeathers.append(ForecastWeather(date: "Friday", weatherDetails: [WeatherInfo(weatherImage: "10n", time: "00:00", weatherType: "Rain", temperature: "13.0")]))
forecastWeathers.append(ForecastWeather(date: "Friday", weatherDetails: [WeatherInfo(weatherImage: "10d", time: "03:00", weatherType: "Rain", temperature: "14.0")]))
forecastWeathers.append(ForecastWeather(date: "Monday", weatherDetails: [WeatherInfo(weatherImage: "10d", time: "12:00", weatherType: "Rain", temperature: "19.0")]))
forecastWeathers.append(ForecastWeather(date: "Monday", weatherDetails: [WeatherInfo(weatherImage: "10d", time: "15:00", weatherType: "Rain", temperature: "19.0")]))
forecastWeathers.append(ForecastWeather(date: "Monday", weatherDetails: [WeatherInfo(weatherImage: "03n", time: "18:00", weatherType: "Clouds", temperature: "16.0")]))
var storedForecastWeatherIndicies: [String: ForecastWeather] = [:]
forecastWeathers.forEach { value in
guard storedForecastWeatherIndicies[value.date] == nil else {
// if is already found
storedForecastWeatherIndicies[value.date]?
.weatherDetails
.append(contentsOf: value.weatherDetails)
return
}
// if a new value for the Dictinary
storedForecastWeatherIndicies[value.date] = value
}
let result = storedForecastWeatherIndicies.values.map { $0 }.sorted { first, second in first.index < second.index }
print(result)
[__lldb_expr_7.ForecastWeather(date: "Monday", weatherDetails: [__lldb_expr_7.WeatherInfo(weatherImage: "10d", time: "12:00", weatherType: "Rain", temperature: "19.0"), __lldb_expr_7.WeatherInfo(weatherImage: "10d", time: "15:00", weatherType: "Rain", temperature: "19.0"), __lldb_expr_7.WeatherInfo(weatherImage: "03n", time: "18:00", weatherType: "Clouds", temperature: "16.0")]), __lldb_expr_7.ForecastWeather(date: "Thursday", weatherDetails: [__lldb_expr_7.WeatherInfo(weatherImage: "01d", time: "12:00", weatherType: "Clear", temperature: "35.0"), __lldb_expr_7.WeatherInfo(weatherImage: "02d", time: "15:00", weatherType: "Clouds", temperature: "31.0"), __lldb_expr_7.WeatherInfo(weatherImage: "01n", time: "18:00", weatherType: "Clear", temperature: "21.0")]), __lldb_expr_7.ForecastWeather(date: "Friday", weatherDetails: [__lldb_expr_7.WeatherInfo(weatherImage: "03n", time: "21:00", weatherType: "Clouds", temperature: "16.0"), __lldb_expr_7.WeatherInfo(weatherImage: "10n", time: "00:00", weatherType: "Rain", temperature: "13.0"), __lldb_expr_7.WeatherInfo(weatherImage: "10d", time: "03:00", weatherType: "Rain", temperature: "14.0")])]
EDIT
This is incorrect: date.count
is lenght of your string. not the array
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return WeatherService.instance.newForecastWeathers[section].date.count
}
use weatherDetails
instead
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return WeatherService.instance.newForecastWeathers[section].weatherDetails.count
}
Upvotes: 1
Reputation: 10199
The issue is that you are not using the inner weatherDetails
as an array, since you always only add just one element.
So, you'll have to add WeatherInfo
s belonging to the same day to that array, maybe in this way:
struct ForecastWeather {
public private(set) var date: String
public private(set) var weatherDetails = [WeatherInfo]()
public init (date:String) {
self.date = date
}
public mutating func addInfo(_ info:WeatherInfo) {
weatherDetails.append(info)
}
}
struct WeatherInfo {
public private(set) var weatherImage: String
public private(set) var time: String
public private(set) var weatherType: String
public private(set) var temperature: String
}
var thursday = ForecastWeather(date: "Thursday")
thursday.addInfo(WeatherInfo(weatherImage: "01d", time: "12:00", weatherType: "Clear", temperature: "35.0"))
thursday.addInfo(WeatherInfo(weatherImage: "02d", time: "15:00", weatherType: "Clouds", temperature: "31.0"))
var friday = ForecastWeather(date: "Friday")
friday.addInfo(WeatherInfo(weatherImage: "03n", time: "21:00", weatherType: "Clouds", temperature: "16.0"))
// ...
let forecastWeathers = [thursday, friday /* ... */]
Upvotes: 1